Merge branch 'custom_bridgeheads' into jgrpp
# Conflicts: # docs/landscape.html # src/bridge_map.h # src/pbs.cpp # src/saveload/company_sl.cpp # src/saveload/extended_ver_sl.cpp # src/settings_type.h # src/signal.cpp # src/train_cmd.cpp # src/tunnel_map.h # src/tunnelbridge_cmd.cpp # src/tunnelbridge_map.h # src/vehicle.cpp # src/viewport.cpp
This commit is contained in:
@@ -1496,9 +1496,75 @@
|
||||
</tr>
|
||||
</table>
|
||||
</li>
|
||||
<li style="color: blue">m2 bits 2..0: rail bridge heads track reserved for pbs
|
||||
<table style="color: blue">
|
||||
<tr>
|
||||
<td><tt>0</tt> </td>
|
||||
<td>not reserved</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><tt>1</tt> </td>
|
||||
<td>X direction</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><tt>2</tt> </td>
|
||||
<td>Y direction</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><tt>3</tt> </td>
|
||||
<td>north corner (W-E)</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><tt>4</tt> </td>
|
||||
<td>south corner (W-E)</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><tt>5</tt> </td>
|
||||
<td>west corner (N-S)</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><tt>6</tt> </td>
|
||||
<td>east corner (N-S)</td>
|
||||
</tr>
|
||||
</table>
|
||||
</li>
|
||||
<li style="color: blue">m2 bit 3: rail bridge heads opposite track is reserved, too</li>
|
||||
<li>m3 bits 7..4: <a href="#OwnershipInfo">owner</a> of tram</li>
|
||||
<li style="color: purple">m3 bits 3..0: bits 3..0 of <a href="#TrackType">track type</a> for railway</li>
|
||||
<li>m5 bit 4: pbs reservation state for railway</li>
|
||||
<li style="color: blue">m4 bits 5..0: rail bridge heads track layout: bit set = track present:
|
||||
<table style="color: blue">
|
||||
<tr>
|
||||
<td nowrap valign=top>bit 0: </td>
|
||||
<td align=left>in the X direction</td>
|
||||
</tr>
|
||||
|
||||
<tr>
|
||||
<td nowrap valign=top>bit 1: </td>
|
||||
<td align=left>in the Y direction</td>
|
||||
</tr>
|
||||
|
||||
<tr>
|
||||
<td nowrap valign=top>bit 2: </td>
|
||||
<td align=left>in the north corner (direction W-E)</td>
|
||||
</tr>
|
||||
|
||||
<tr>
|
||||
<td nowrap valign=top>bit 3: </td>
|
||||
<td align=left>in the south corner (direction W-E)</td>
|
||||
</tr>
|
||||
|
||||
<tr>
|
||||
<td nowrap valign=top>bit 4: </td>
|
||||
<td align=left>in the west corner (direction N-S)</td>
|
||||
</tr>
|
||||
|
||||
<tr>
|
||||
<td nowrap valign=top>bit 5: </td>
|
||||
<td align=left>in the east corner (direction N-S)</td>
|
||||
</tr>
|
||||
</table>
|
||||
</li>
|
||||
<li>m5 bit 4: pbs reservation state for railway (tunnel only)</li>
|
||||
<li>m5 bit 7 clear: tunnel entrance/exit</li>
|
||||
<li>m5 bit 7 set: bridge ramp
|
||||
<ul>
|
||||
|
@@ -345,9 +345,9 @@ the array so you can quickly see what is used and what is not.
|
||||
<td class="bits">-inherit-</td>
|
||||
<td class="bits">-inherit-</td>
|
||||
<td class="bits">-inherit-</td>
|
||||
<td class="bits"><span class="used_p">PPPP PPPP PPPP</span> <span class="free">OOOO</span></td>
|
||||
<td class="bits">-inherit-</td>
|
||||
<td class="bits"><span class="used_p">PPPP PPPP PPPP PPPP</span></td>
|
||||
<td class="bits">-inherit-</td>
|
||||
<td class="bits"><span class="free">OO</span><span class="used_p">PP PPPP</span></td>
|
||||
<td class="bits">-inherit-</td>
|
||||
<td class="bits"><span class="free">O</span><span class="used_p">P</span>XX XX<span class="used_p">PP</span></td>
|
||||
<td class="bits">-inherit-</td>
|
||||
|
200
src/bridge_map.h
200
src/bridge_map.h
@@ -180,19 +180,24 @@ static inline void MakeRoadBridgeRamp(TileIndex t, Owner o, Owner owner_road, Ow
|
||||
*/
|
||||
static inline void MakeRailBridgeRamp(TileIndex t, Owner o, BridgeType bridgetype, DiagDirection d, RailType r, bool upgrade)
|
||||
{
|
||||
// Backup bridge signal data.
|
||||
/* Backup bridge signal and custom bridgehead data. */
|
||||
auto m2_backup = _m[t].m2;
|
||||
auto m4_backup = _m[t].m4;
|
||||
auto m5_backup = _m[t].m5;
|
||||
auto m6_backup = _me[t].m6;
|
||||
|
||||
MakeBridgeRamp(t, o, bridgetype, d, TRANSPORT_RAIL, r);
|
||||
|
||||
// Restore bridge signal data if we're upgrading an existing bridge.
|
||||
if (upgrade) {
|
||||
/* Restore bridge signal and custom bridgehead data if we're upgrading an existing bridge. */
|
||||
_m[t].m2 = m2_backup;
|
||||
SB(_m[t].m4, 0, 6, GB(m4_backup, 0, 6));
|
||||
SB(_m[t].m5, 4, 3, GB(m5_backup, 4, 3));
|
||||
SB(_me[t].m6, 0, 2, GB(m6_backup, 0, 2));
|
||||
SB(_me[t].m6, 6, 1, GB(m6_backup, 6, 1));
|
||||
} else {
|
||||
/* Set bridge head tracks to axial track only. */
|
||||
SB(_m[t].m4, 0, 6, DiagDirToDiagTrackBits(d));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -275,4 +280,195 @@ static inline void SetCustomBridgeHeadRoadBits(TileIndex t, RoadType rt, RoadBit
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if this tile is a rail bridge head
|
||||
* @param t The tile to analyze
|
||||
* @return true if it is a rail bridge head
|
||||
*/
|
||||
static inline bool IsRailBridgeHeadTile(TileIndex t)
|
||||
{
|
||||
return IsBridgeTile(t) && (TransportType)GB(_m[t].m5, 2, 2) == TRANSPORT_RAIL;
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if this tile is a flat rail bridge head
|
||||
* @param t The tile to analyze
|
||||
* @return true if it is a flat rail bridge head
|
||||
*/
|
||||
static inline bool IsFlatRailBridgeHeadTile(TileIndex t)
|
||||
{
|
||||
return IsRailBridgeHeadTile(t) && HasBridgeFlatRamp(GetTileSlope(t), DiagDirToAxis((DiagDirection)GB(_m[t].m5, 0, 2)));
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the track bits for a (possibly custom) rail bridge head
|
||||
* @param tile the tile to get the track bits from
|
||||
* @pre IsRailBridgeHeadTile(t)
|
||||
* @return road bits for the bridge head
|
||||
*/
|
||||
static inline TrackBits GetCustomBridgeHeadTrackBits(TileIndex t)
|
||||
{
|
||||
assert(IsRailBridgeHeadTile(t));
|
||||
return (TrackBits)GB(_m[t].m4, 0, 6);
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the road track for a (possibly custom) rail bridge head
|
||||
* @param t the tile to set the track bits of
|
||||
* @param b the new track bits for the tile
|
||||
* @pre IsRailBridgeHeadTile(t)
|
||||
*/
|
||||
static inline void SetCustomBridgeHeadTrackBits(TileIndex t, TrackBits b)
|
||||
{
|
||||
assert(IsRailBridgeHeadTile(t));
|
||||
SB(_m[t].m4, 0, 6, b);
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if this rail bridge head is a custom bridge head
|
||||
* @param t The tile to analyze
|
||||
* @pre IsRailBridgeHeadTile(t)
|
||||
* @return true if it is a custom bridge head
|
||||
*/
|
||||
static inline bool IsRailCustomBridgeHead(TileIndex t)
|
||||
{
|
||||
assert(IsRailBridgeHeadTile(t));
|
||||
return GetCustomBridgeHeadTrackBits(t) != DiagDirToDiagTrackBits((DiagDirection)GB(_m[t].m5, 0, 2));
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if this tile is a rail bridge head with a custom bridge head
|
||||
* @param t The tile to analyze
|
||||
* @return true if it is a rail bridge head with a custom bridge head
|
||||
*/
|
||||
static inline bool IsRailCustomBridgeHeadTile(TileIndex t)
|
||||
{
|
||||
return IsRailBridgeHeadTile(t) && IsRailCustomBridgeHead(t);
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if this tile is a bridge head with a custom bridge head
|
||||
* @param t The tile to analyze
|
||||
* @return true if it is a bridge head with a custom bridge head
|
||||
*/
|
||||
static inline bool IsCustomBridgeHeadTile(TileIndex t)
|
||||
{
|
||||
return IsRailCustomBridgeHeadTile(t) || IsRoadCustomBridgeHeadTile(t);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the reserved track bits for a rail bridge head
|
||||
* @pre IsRailBridgeHeadTile(t)
|
||||
* @param t the tile
|
||||
* @return reserved track bits
|
||||
*/
|
||||
static inline TrackBits GetBridgeReservationTrackBits(TileIndex t)
|
||||
{
|
||||
assert(IsRailBridgeHeadTile(t));
|
||||
byte track_b = GB(_m[t].m2, 0, 3);
|
||||
Track track = (Track)(track_b - 1); // map array saves Track+1
|
||||
if (track_b == 0) return TRACK_BIT_NONE;
|
||||
return (TrackBits)(TrackToTrackBits(track) | (HasBit(_m[t].m2, 3) ? TrackToTrackBits(TrackToOppositeTrack(track)) : 0));
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the reserved track bits of the rail bridge head
|
||||
* @pre IsRailBridgeHeadTile(t)
|
||||
* @param t the tile to change
|
||||
* @param b the track bits
|
||||
*/
|
||||
static inline void SetBridgeReservationTrackBits(TileIndex t, TrackBits b)
|
||||
{
|
||||
assert(IsRailBridgeHeadTile(t));
|
||||
assert(!TracksOverlap(b));
|
||||
Track track = RemoveFirstTrack(&b);
|
||||
SB(_m[t].m2, 0, 3, track == INVALID_TRACK ? 0 : track + 1);
|
||||
SB(_m[t].m2, 3, 1, (byte)(b != TRACK_BIT_NONE));
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Try to reserve a specific track on a rail bridge head tile
|
||||
* @pre IsRailBridgeHeadTile(t) && HasBit(GetCustomBridgeHeadTrackBits(tile), t)
|
||||
* @param tile the tile
|
||||
* @param t the rack to reserve
|
||||
* @return true if successful
|
||||
*/
|
||||
static inline bool TryReserveRailBridgeHead(TileIndex tile, Track t)
|
||||
{
|
||||
assert(IsRailBridgeHeadTile(tile));
|
||||
assert(HasBit(GetCustomBridgeHeadTrackBits(tile), t));
|
||||
TrackBits bits = TrackToTrackBits(t);
|
||||
TrackBits res = GetBridgeReservationTrackBits(tile);
|
||||
if ((res & bits) != TRACK_BIT_NONE) return false; // already reserved
|
||||
res |= bits;
|
||||
if (TracksOverlap(res)) return false; // crossing reservation present
|
||||
SetBridgeReservationTrackBits(tile, res);
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Lift the reservation of a specific track on a rail bridge head tile
|
||||
* @pre IsRailBridgeHeadTile(t) && HasBit(GetCustomBridgeHeadTrackBits(tile), t)
|
||||
* @param tile the tile
|
||||
* @param t the track to free
|
||||
*/
|
||||
static inline void UnreserveRailBridgeHeadTrack(TileIndex tile, Track t)
|
||||
{
|
||||
assert(IsRailBridgeHeadTile(tile));
|
||||
assert(HasBit(GetCustomBridgeHeadTrackBits(tile), t));
|
||||
TrackBits res = GetBridgeReservationTrackBits(tile);
|
||||
res &= ~TrackToTrackBits(t);
|
||||
SetBridgeReservationTrackBits(tile, res);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the possible track bits of the bridge head tile onto/across the bridge
|
||||
* @pre IsRailBridgeHeadTile(t)
|
||||
* @param t the tile
|
||||
* @return reservation state
|
||||
*/
|
||||
static inline TrackBits GetAcrossBridgePossibleTrackBits(TileIndex t)
|
||||
{
|
||||
assert(IsRailBridgeHeadTile(t));
|
||||
return DiagdirReachesTracks(ReverseDiagDir((DiagDirection)GB(_m[t].m5, 0, 2)));
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the reserved track bits of the bridge head tile onto/across the bridge
|
||||
* @pre IsBridgeTile(t) && GetTunnelBridgeTransportType(t) == TRANSPORT_RAIL
|
||||
* @param t the tile
|
||||
* @return reservation state
|
||||
*/
|
||||
static inline TrackBits GetAcrossBridgeReservationTrackBits(TileIndex t)
|
||||
{
|
||||
return GetBridgeReservationTrackBits(t) & GetAcrossBridgePossibleTrackBits(t);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the reservation state of the bridge head tile onto/across the bridge
|
||||
* @pre IsBridgeTile(t) && GetTunnelBridgeTransportType(t) == TRANSPORT_RAIL
|
||||
* @param t the tile
|
||||
* @return reservation state
|
||||
*/
|
||||
static inline bool HasAcrossBridgeReservation(TileIndex t)
|
||||
{
|
||||
return GetAcrossBridgeReservationTrackBits(t) != TRACK_BIT_NONE;
|
||||
}
|
||||
|
||||
/**
|
||||
* Lift the reservation of a specific track on a rail bridge head tile
|
||||
* @pre IsRailBridgeHeadTile(t)
|
||||
* @param tile the tile
|
||||
*/
|
||||
static inline void UnreserveAcrossRailBridgeHead(TileIndex tile)
|
||||
{
|
||||
assert(IsRailBridgeHeadTile(tile));
|
||||
TrackBits res = GetAcrossBridgeReservationTrackBits(tile);
|
||||
if (res != TRACK_BIT_NONE) {
|
||||
SetBridgeReservationTrackBits(tile, GetBridgeReservationTrackBits(tile) & ~res);
|
||||
}
|
||||
}
|
||||
|
||||
#endif /* BRIDGE_MAP_H */
|
||||
|
@@ -104,7 +104,7 @@ static TrackBits GetRailTrackBitsUniversal(TileIndex t, byte *override)
|
||||
if (override != NULL && (IsTunnel(t) || GetTunnelBridgeLength(t, GetOtherBridgeEnd(t)) > 0)) {
|
||||
*override = 1 << GetTunnelBridgeDirection(t);
|
||||
}
|
||||
return DiagDirToDiagTrackBits(GetTunnelBridgeDirection(t));
|
||||
return GetTunnelBridgeTrackBits(t);
|
||||
|
||||
case MP_ROAD:
|
||||
if (!IsLevelCrossing(t)) return TRACK_BIT_NONE;
|
||||
@@ -200,6 +200,8 @@ static void AdjustTileh(TileIndex tile, Slope *tileh)
|
||||
if (IsTileType(tile, MP_TUNNELBRIDGE)) {
|
||||
if (IsTunnel(tile)) {
|
||||
*tileh = SLOPE_STEEP; // XXX - Hack to make tunnel entrances to always have a pylon
|
||||
} else if (IsRailCustomBridgeHeadTile(tile)) {
|
||||
/* no change */
|
||||
} else if (*tileh != SLOPE_FLAT) {
|
||||
*tileh = SLOPE_FLAT;
|
||||
} else {
|
||||
|
@@ -353,7 +353,7 @@ Slope GetFoundationSlope(TileIndex tile, int *z)
|
||||
|
||||
bool HasFoundationNW(TileIndex tile, Slope slope_here, uint z_here)
|
||||
{
|
||||
if (IsRoadCustomBridgeHeadTile(tile) && GetTunnelBridgeDirection(tile) == DIAGDIR_NW) return false;
|
||||
if (IsCustomBridgeHeadTile(tile) && GetTunnelBridgeDirection(tile) == DIAGDIR_NW) return false;
|
||||
|
||||
int z;
|
||||
|
||||
@@ -372,7 +372,7 @@ bool HasFoundationNW(TileIndex tile, Slope slope_here, uint z_here)
|
||||
|
||||
bool HasFoundationNE(TileIndex tile, Slope slope_here, uint z_here)
|
||||
{
|
||||
if (IsRoadCustomBridgeHeadTile(tile) && GetTunnelBridgeDirection(tile) == DIAGDIR_NE) return false;
|
||||
if (IsCustomBridgeHeadTile(tile) && GetTunnelBridgeDirection(tile) == DIAGDIR_NE) return false;
|
||||
|
||||
int z;
|
||||
|
||||
|
@@ -1878,6 +1878,8 @@ STR_CONFIG_SETTING_REVERSE_AT_SIGNALS_HELPTEXT :Allow trains to
|
||||
|
||||
STR_CONFIG_SETTING_ENABLE_ROAD_CUSTOM_BRIDGE_HEADS :Enable road custom bridge heads: {STRING2}
|
||||
STR_CONFIG_SETTING_ENABLE_ROAD_CUSTOM_BRIDGE_HEADS_HELPTEXT :Allow road bridges to have custom, non-straight flat entry/exit tiles
|
||||
STR_CONFIG_SETTING_ENABLE_RAIL_CUSTOM_BRIDGE_HEADS :Enable rail custom bridge heads: {STRING2}
|
||||
STR_CONFIG_SETTING_ENABLE_RAIL_CUSTOM_BRIDGE_HEADS_HELPTEXT :Allow rail bridges to have custom, non-straight flat entry/exit tiles
|
||||
|
||||
STR_CONFIG_SETTING_QUERY_CAPTION :{WHITE}Change setting value
|
||||
|
||||
|
@@ -209,7 +209,7 @@ static uint32 GetRailContinuationInfo(TileIndex tile)
|
||||
|
||||
/* With tunnels and bridges the tile has tracks, but they are not necessarily connected
|
||||
* with the next tile because the ramp is not going in the right direction. */
|
||||
if (IsTileType(neighbour_tile, MP_TUNNELBRIDGE) && GetTunnelBridgeDirection(neighbour_tile) != *diagdir) {
|
||||
if (IsTileType(neighbour_tile, MP_TUNNELBRIDGE) && GetTunnelBridgeDirection(neighbour_tile) == ReverseDiagDir(*diagdir)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
|
@@ -127,7 +127,7 @@ struct CFollowTrackT
|
||||
m_old_td = old_td;
|
||||
m_err = EC_NONE;
|
||||
assert(((TrackStatusToTrackdirBits(GetTileTrackStatus(m_old_tile, TT(), IsRoadTT() ? RoadVehicle::From(m_veh)->compatible_roadtypes : 0)) & TrackdirToTrackdirBits(m_old_td)) != 0) ||
|
||||
(IsTram() && GetSingleTramBit(m_old_tile) != INVALID_DIAGDIR)); // Disable the assertion for single tram bits
|
||||
(IsTram() && GetSingleTramBit(m_old_tile) != INVALID_DIAGDIR) || (IsRailTT() && IsRailCustomBridgeHeadTile(m_old_tile))); // Disable the assertion for single tram bits
|
||||
m_exitdir = TrackdirToExitdir(m_old_td);
|
||||
if (ForcedReverse()) return true;
|
||||
if (!CanExitOldTile()) return false;
|
||||
@@ -155,7 +155,7 @@ struct CFollowTrackT
|
||||
|
||||
return false;
|
||||
}
|
||||
if (!Allow90degTurns()) {
|
||||
if (!Allow90degTurns() && m_tiles_skipped == 0) {
|
||||
m_new_td_bits &= (TrackdirBits)~(int)TrackdirCrossesTrackdirs(m_old_td);
|
||||
if (m_new_td_bits == TRACKDIR_BIT_NONE) {
|
||||
m_err = EC_90DEG;
|
||||
@@ -218,7 +218,7 @@ protected:
|
||||
m_tiles_skipped = GetTunnelBridgeLength(m_new_tile, m_old_tile);
|
||||
return;
|
||||
}
|
||||
if (!IsRoadCustomBridgeHeadTile(m_old_tile)) assert(ReverseDiagDir(enterdir) == m_exitdir);
|
||||
if (!IsRoadCustomBridgeHeadTile(m_old_tile) && !IsRailCustomBridgeHeadTile(m_old_tile)) assert(ReverseDiagDir(enterdir) == m_exitdir);
|
||||
}
|
||||
|
||||
/* normal or station tile, do one step */
|
||||
@@ -369,13 +369,22 @@ protected:
|
||||
}
|
||||
}
|
||||
} else { // IsBridge(m_new_tile)
|
||||
DiagDirection ramp_enderdir = GetTunnelBridgeDirection(m_new_tile);
|
||||
if (!m_is_bridge && ramp_enderdir == ReverseDiagDir(m_exitdir)) {
|
||||
m_err = EC_NO_WAY;
|
||||
return false;
|
||||
}
|
||||
if (!m_is_bridge && IsRoadTT() && IsRoadCustomBridgeHeadTile(m_new_tile)) {
|
||||
if (!(DiagDirToRoadBits(ReverseDiagDir(m_exitdir)) & GetCustomBridgeHeadRoadBits(m_new_tile, IsTram() ? ROADTYPE_TRAM : ROADTYPE_ROAD))) {
|
||||
m_err = EC_NO_WAY;
|
||||
return false;
|
||||
}
|
||||
} else if (!m_is_bridge && IsRailTT() && IsRailCustomBridgeHeadTile(m_new_tile)) {
|
||||
if (!(DiagdirReachesTracks(m_exitdir) & GetCustomBridgeHeadTrackBits(m_new_tile))) {
|
||||
m_err = EC_NO_WAY;
|
||||
return false;
|
||||
}
|
||||
} else if (!m_is_bridge) {
|
||||
DiagDirection ramp_enderdir = GetTunnelBridgeDirection(m_new_tile);
|
||||
if (ramp_enderdir != m_exitdir) {
|
||||
m_err = EC_NO_WAY;
|
||||
return false;
|
||||
|
@@ -378,7 +378,7 @@ public:
|
||||
}
|
||||
}
|
||||
}
|
||||
if (IsTileType(tile, MP_TUNNELBRIDGE) && IsTunnelBridgeSignalSimulationExitOnly(tile) && DiagDirToDiagTrackdir(GetTunnelBridgeDirection(tile)) == trackdir) {
|
||||
if (IsTileType(tile, MP_TUNNELBRIDGE) && IsTunnelBridgeSignalSimulationExitOnly(tile) && TrackdirEntersTunnelBridge(tile, trackdir)) {
|
||||
/* Entering a signalled bridge/tunnel from the wrong side, equivalent to encountering a one-way signal from the wrong side */
|
||||
n.m_segment->m_end_segment_reason |= ESRB_DEAD_END;
|
||||
}
|
||||
|
@@ -646,7 +646,7 @@ bool YapfTrainCheckReverse(const Train *v)
|
||||
|
||||
int reverse_penalty = 0;
|
||||
|
||||
if (v->track == TRACK_BIT_WORMHOLE) {
|
||||
if (v->track & TRACK_BIT_WORMHOLE) {
|
||||
/* front in tunnel / on bridge */
|
||||
DiagDirection dir_into_wormhole = GetTunnelBridgeDirection(tile);
|
||||
|
||||
@@ -661,7 +661,7 @@ bool YapfTrainCheckReverse(const Train *v)
|
||||
reverse_penalty -= DistanceManhattan(cur_tile, tile) * YAPF_TILE_LENGTH;
|
||||
}
|
||||
|
||||
if (last_veh->track == TRACK_BIT_WORMHOLE) {
|
||||
if (last_veh->track & TRACK_BIT_WORMHOLE) {
|
||||
/* back in tunnel / on bridge */
|
||||
DiagDirection dir_into_wormhole = GetTunnelBridgeDirection(tile_rev);
|
||||
|
||||
|
53
src/pbs.cpp
53
src/pbs.cpp
@@ -100,7 +100,8 @@ bool TryReserveRailTrackdir(TileIndex tile, Trackdir td, bool trigger_stations)
|
||||
*/
|
||||
bool TryReserveRailTrack(TileIndex tile, Track t, bool trigger_stations)
|
||||
{
|
||||
assert(HasTrack(TrackStatusToTrackBits(GetTileTrackStatus(tile, TRANSPORT_RAIL, 0)), t));
|
||||
assert_msg((TrackStatusToTrackBits(GetTileTrackStatus(tile, TRANSPORT_RAIL, 0)) & TrackToTrackBits(t)) != 0,
|
||||
"%X, %X, %X, %X", TrackStatusToTrackBits(GetTileTrackStatus(tile, TRANSPORT_RAIL, 0)), tile, t, TrackToTrackBits(t));
|
||||
|
||||
if (_settings_client.gui.show_track_reservation) {
|
||||
/* show the reserved rail if needed */
|
||||
@@ -153,11 +154,19 @@ bool TryReserveRailTrack(TileIndex tile, Track t, bool trigger_stations)
|
||||
break;
|
||||
|
||||
case MP_TUNNELBRIDGE:
|
||||
if (GetTunnelBridgeTransportType(tile) == TRANSPORT_RAIL && !GetTunnelBridgeReservationTrackBits(tile)) {
|
||||
SetTunnelBridgeReservation(tile, true);
|
||||
if (GetTunnelBridgeTransportType(tile) == TRANSPORT_RAIL) {
|
||||
if (IsTunnel(tile) && !HasTunnelReservation(tile)) {
|
||||
SetTunnelReservation(tile, true);
|
||||
MarkTileDirtyByTile(tile, ZOOM_LVL_DRAW_MAP);
|
||||
return true;
|
||||
}
|
||||
if (IsBridge(tile)) {
|
||||
if (TryReserveRailBridgeHead(tile, t)) {
|
||||
MarkBridgeOrTunnelDirtyOnReservationChange(tile, ZOOM_LVL_DRAW_MAP);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
@@ -187,7 +196,7 @@ void UnreserveRailTrackdir(TileIndex tile, Trackdir td)
|
||||
*/
|
||||
void UnreserveRailTrack(TileIndex tile, Track t)
|
||||
{
|
||||
assert(HasTrack(TrackStatusToTrackBits(GetTileTrackStatus(tile, TRANSPORT_RAIL, 0)), t));
|
||||
assert(TrackStatusToTrackBits(GetTileTrackStatus(tile, TRANSPORT_RAIL, 0)) & TrackToTrackBits(t));
|
||||
|
||||
if (_settings_client.gui.show_track_reservation) {
|
||||
if (IsBridgeTile(tile)) {
|
||||
@@ -223,9 +232,13 @@ void UnreserveRailTrack(TileIndex tile, Track t)
|
||||
|
||||
case MP_TUNNELBRIDGE:
|
||||
if (GetTunnelBridgeTransportType(tile) == TRANSPORT_RAIL) {
|
||||
SetTunnelBridgeReservation(tile, false);
|
||||
if (IsTunnelBridgeSignalSimulationExit(tile) && IsTunnelBridgePBS(tile)) SetTunnelBridgeExitSignalState(tile, SIGNAL_STATE_RED);
|
||||
MarkTileDirtyByTile(tile, ZOOM_LVL_DRAW_MAP);
|
||||
if (IsTunnel(tile)) {
|
||||
SetTunnelReservation(tile, false);
|
||||
} else {
|
||||
UnreserveRailBridgeHeadTrack(tile, t);
|
||||
}
|
||||
if (IsTunnelBridgeSignalSimulationExit(tile) && IsTunnelBridgePBS(tile) && IsTrackAcrossTunnelBridge(tile, t)) SetTunnelBridgeExitSignalState(tile, SIGNAL_STATE_RED);
|
||||
MarkBridgeOrTunnelDirtyOnReservationChange(tile, ZOOM_LVL_DRAW_MAP);
|
||||
}
|
||||
break;
|
||||
|
||||
@@ -295,7 +308,7 @@ static PBSTileInfo FollowReservation(Owner o, RailTypes rts, TileIndex tile, Tra
|
||||
if (IsRailDepotTile(tile)) break;
|
||||
/* Non-pbs signal? Reservation can't continue. */
|
||||
if (IsTileType(tile, MP_RAILWAY) && HasSignalOnTrackdir(tile, trackdir) && !IsPbsSignal(GetSignalType(tile, TrackdirToTrack(trackdir)))) break;
|
||||
if (IsTileType(tile, MP_TUNNELBRIDGE) && IsTunnelBridgeWithSignalSimulation(tile)) break;
|
||||
if (IsTileType(tile, MP_TUNNELBRIDGE) && IsTunnelBridgeWithSignalSimulation(tile) && IsTrackAcrossTunnelBridge(tile, TrackdirToTrack(trackdir))) break;
|
||||
}
|
||||
|
||||
return PBSTileInfo(tile, trackdir, false);
|
||||
@@ -320,7 +333,7 @@ static Vehicle *FindTrainOnTrackEnum(Vehicle *v, void *data)
|
||||
if (v->type != VEH_TRAIN || (v->vehstatus & VS_CRASHED)) return NULL;
|
||||
|
||||
Train *t = Train::From(v);
|
||||
if (t->track == TRACK_BIT_WORMHOLE) {
|
||||
if (t->track & TRACK_BIT_WORMHOLE) {
|
||||
/* Do not find trains inside signalled bridge/tunnels.
|
||||
* Trains on the ramp/entrance itself are found though.
|
||||
*/
|
||||
@@ -328,7 +341,7 @@ static Vehicle *FindTrainOnTrackEnum(Vehicle *v, void *data)
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
if (t->track == TRACK_BIT_WORMHOLE || HasBit((TrackBits)t->track, TrackdirToTrack(info->res.trackdir))) {
|
||||
if (t->track & TRACK_BIT_WORMHOLE || HasBit((TrackBits)t->track, TrackdirToTrack(info->res.trackdir))) {
|
||||
t = t->First();
|
||||
|
||||
/* ALWAYS return the lowest ID (anti-desync!) */
|
||||
@@ -372,7 +385,7 @@ PBSTileInfo FollowTrainReservation(const Train *v, Vehicle **train_on_res)
|
||||
if (ftoti.best != NULL) *train_on_res = ftoti.best->First();
|
||||
}
|
||||
}
|
||||
if (*train_on_res == NULL && IsTileType(ftoti.res.tile, MP_TUNNELBRIDGE) && !IsTunnelBridgeWithSignalSimulation(ftoti.res.tile)) {
|
||||
if (*train_on_res == NULL && IsTileType(ftoti.res.tile, MP_TUNNELBRIDGE) && IsTrackAcrossTunnelBridge(ftoti.res.tile, TrackdirToTrack(ftoti.res.trackdir)) && !IsTunnelBridgeWithSignalSimulation(ftoti.res.tile)) {
|
||||
/* The target tile is a bridge/tunnel, also check the other end tile. */
|
||||
FindVehicleOnPos(GetOtherTunnelBridgeEnd(ftoti.res.tile), &ftoti, FindTrainOnTrackEnum);
|
||||
if (ftoti.best != NULL) *train_on_res = ftoti.best->First();
|
||||
@@ -419,7 +432,7 @@ Train *GetTrainForReservation(TileIndex tile, Track track)
|
||||
}
|
||||
|
||||
/* Special case for bridges/tunnels: check the other end as well. */
|
||||
if (IsTileType(ftoti.res.tile, MP_TUNNELBRIDGE)) {
|
||||
if (IsTileType(ftoti.res.tile, MP_TUNNELBRIDGE) && IsTrackAcrossTunnelBridge(ftoti.res.tile, TrackdirToTrack(ftoti.res.trackdir))) {
|
||||
FindVehicleOnPos(GetOtherTunnelBridgeEnd(ftoti.res.tile), &ftoti, FindTrainOnTrackEnum);
|
||||
if (ftoti.best != NULL) return ftoti.best;
|
||||
}
|
||||
@@ -491,7 +504,7 @@ bool IsSafeWaitingPosition(const Train *v, TileIndex tile, Trackdir trackdir, bo
|
||||
if (HasSignalOnTrackdir(tile, trackdir) && !IsPbsSignal(GetSignalType(tile, TrackdirToTrack(trackdir)))) return true;
|
||||
}
|
||||
|
||||
if (IsTileType(tile, MP_TUNNELBRIDGE) && GetTunnelBridgeTransportType(tile) == TRANSPORT_RAIL) {
|
||||
if (IsTileType(tile, MP_TUNNELBRIDGE) && GetTunnelBridgeTransportType(tile) == TRANSPORT_RAIL && IsTrackAcrossTunnelBridge(tile, TrackdirToTrack(trackdir))) {
|
||||
if (IsTunnelBridgeSignalSimulationEntrance(tile)) {
|
||||
return true;
|
||||
}
|
||||
@@ -533,6 +546,7 @@ bool IsSafeWaitingPosition(const Train *v, TileIndex tile, Trackdir trackdir, bo
|
||||
return include_line_end;
|
||||
}
|
||||
if (IsTileType(ft.m_new_tile, MP_TUNNELBRIDGE) && GetTunnelBridgeTransportType(ft.m_new_tile) == TRANSPORT_RAIL &&
|
||||
IsTrackAcrossTunnelBridge(ft.m_new_tile, TrackdirToTrack(td)) &&
|
||||
IsTunnelBridgeSignalSimulationExitOnly(ft.m_new_tile) && IsTunnelBridgePBS(ft.m_new_tile)) {
|
||||
return include_line_end;
|
||||
}
|
||||
@@ -585,15 +599,20 @@ bool IsWaitingPositionFree(const Train *v, TileIndex tile, Trackdir trackdir, bo
|
||||
return pbs_res_end_wait_test(tile, trackdir);
|
||||
}
|
||||
|
||||
if (IsTileType(tile, MP_TUNNELBRIDGE) && GetTunnelBridgeTransportType(tile) == TRANSPORT_RAIL && IsTunnelBridgeSignalSimulationEntrance(tile)) {
|
||||
if (IsTileType(tile, MP_TUNNELBRIDGE) && GetTunnelBridgeTransportType(tile) == TRANSPORT_RAIL && IsTunnelBridgeSignalSimulationEntrance(tile)
|
||||
&& IsTrackAcrossTunnelBridge(tile, TrackdirToTrack(trackdir))) {
|
||||
if (IsTunnelBridgeSignalSimulationBidirectional(tile)) {
|
||||
TileIndex other_end = GetOtherTunnelBridgeEnd(tile);
|
||||
if (HasTunnelBridgeReservation(other_end) && GetTunnelBridgeExitSignalState(other_end) == SIGNAL_STATE_RED) return false;
|
||||
if (HasAcrossTunnelBridgeReservation(other_end) && GetTunnelBridgeExitSignalState(other_end) == SIGNAL_STATE_RED) return false;
|
||||
Direction dir = DiagDirToDir(GetTunnelBridgeDirection(other_end));
|
||||
if (HasVehicleOnPos(other_end, &dir, [](Vehicle *v, void *data) -> Vehicle * {
|
||||
if (v->type != VEH_TRAIN) return nullptr;
|
||||
if (v->direction != *((Direction *) data)) return nullptr;
|
||||
return v;
|
||||
DirDiff diff = DirDifference(v->direction, *((Direction *) data));
|
||||
if (diff == DIRDIFF_SAME) return v;
|
||||
if (diff == DIRDIFF_45RIGHT || diff == DIRDIFF_45LEFT) {
|
||||
if (GetAcrossTunnelBridgeTrackBits(v->tile) & Train::From(v)->track) return v;
|
||||
}
|
||||
return nullptr;
|
||||
})) return false;
|
||||
}
|
||||
return true;
|
||||
|
12
src/rail.h
12
src/rail.h
@@ -441,4 +441,16 @@ extern uint8 _sorted_railtypes_size;
|
||||
*/
|
||||
#define FOR_ALL_SORTED_RAILTYPES(var) for (uint8 index = 0; index < _sorted_railtypes_size && (var = _sorted_railtypes[index], true) ; index++)
|
||||
|
||||
/** Enum holding the signal offset in the sprite sheet according to the side it is representing. */
|
||||
enum SignalOffsets {
|
||||
SIGNAL_TO_SOUTHWEST,
|
||||
SIGNAL_TO_NORTHEAST,
|
||||
SIGNAL_TO_SOUTHEAST,
|
||||
SIGNAL_TO_NORTHWEST,
|
||||
SIGNAL_TO_EAST,
|
||||
SIGNAL_TO_WEST,
|
||||
SIGNAL_TO_SOUTH,
|
||||
SIGNAL_TO_NORTH,
|
||||
};
|
||||
|
||||
#endif /* RAIL_H */
|
||||
|
270
src/rail_cmd.cpp
270
src/rail_cmd.cpp
@@ -56,18 +56,6 @@ RailType _sorted_railtypes[RAILTYPE_END];
|
||||
uint8 _sorted_railtypes_size;
|
||||
TileIndex _rail_track_endtile; ///< The end of a rail track; as hidden return from the rail build/remove command for GUI purposes.
|
||||
|
||||
/** Enum holding the signal offset in the sprite sheet according to the side it is representing. */
|
||||
enum SignalOffsets {
|
||||
SIGNAL_TO_SOUTHWEST,
|
||||
SIGNAL_TO_NORTHEAST,
|
||||
SIGNAL_TO_SOUTHEAST,
|
||||
SIGNAL_TO_NORTHWEST,
|
||||
SIGNAL_TO_EAST,
|
||||
SIGNAL_TO_WEST,
|
||||
SIGNAL_TO_SOUTH,
|
||||
SIGNAL_TO_NORTH,
|
||||
};
|
||||
|
||||
/**
|
||||
* Reset all rail type information to its default values.
|
||||
*/
|
||||
@@ -435,6 +423,25 @@ static CommandCost CheckRailSlope(Slope tileh, TrackBits rail_bits, TrackBits ex
|
||||
return CommandCost(EXPENSES_CONSTRUCTION, f_new != f_old ? _price[PR_BUILD_FOUNDATION] : (Money)0);
|
||||
}
|
||||
|
||||
bool IsValidFlatRailBridgeHeadTrackBits(Slope normalised_slope, DiagDirection bridge_direction, TrackBits tracks)
|
||||
{
|
||||
/* bridge_direction c1 c2
|
||||
* 0 0 1
|
||||
* 1 0 3
|
||||
* 2 2 3
|
||||
* 3 2 1
|
||||
*/
|
||||
const Corner c1 = (Corner) (bridge_direction & 2);
|
||||
const Corner c2 = (Corner) (((bridge_direction + 1) & 2) + 1);
|
||||
auto test_corner = [&](Corner c) -> bool {
|
||||
if (normalised_slope & SlopeWithOneCornerRaised(c)) return true;
|
||||
Slope effective_slope = normalised_slope | SlopeWithOneCornerRaised(OppositeCorner(c));
|
||||
assert(effective_slope < lengthof(_valid_tracks_on_leveled_foundation));
|
||||
return (_valid_tracks_on_leveled_foundation[effective_slope] & tracks) == tracks;
|
||||
};
|
||||
return test_corner(c1) && test_corner(c2);
|
||||
}
|
||||
|
||||
/* Validate functions for rail building */
|
||||
static inline bool ValParamTrackOrientation(Track track)
|
||||
{
|
||||
@@ -454,6 +461,7 @@ CommandCost CmdBuildSingleRail(TileIndex tile, DoCommandFlag flags, uint32 p1, u
|
||||
{
|
||||
RailType railtype = Extract<RailType, 0, 5>(p1);
|
||||
Track track = Extract<Track, 0, 3>(p2);
|
||||
bool disable_custom_bridge_heads = HasBit(p2, 4);
|
||||
CommandCost cost(EXPENSES_CONSTRUCTION);
|
||||
|
||||
_rail_track_endtile = INVALID_TILE;
|
||||
@@ -513,6 +521,52 @@ CommandCost CmdBuildSingleRail(TileIndex tile, DoCommandFlag flags, uint32 p1, u
|
||||
break;
|
||||
}
|
||||
|
||||
case MP_TUNNELBRIDGE: {
|
||||
CommandCost ret = CheckTileOwnership(tile);
|
||||
if (ret.Failed()) return ret;
|
||||
|
||||
if (disable_custom_bridge_heads || !_settings_game.construction.rail_custom_bridge_heads || !IsFlatRailBridgeHeadTile(tile)) return DoCommand(tile, 0, 0, flags, CMD_LANDSCAPE_CLEAR); // just get appropriate error message
|
||||
|
||||
if (!IsCompatibleRail(GetRailType(tile), railtype)) return_cmd_error(STR_ERROR_IMPOSSIBLE_TRACK_COMBINATION);
|
||||
if (GetRailType(tile) != railtype && !HasPowerOnRail(railtype, GetRailType(tile))) return_cmd_error(STR_ERROR_CAN_T_CONVERT_RAIL);
|
||||
|
||||
const DiagDirection entrance_dir = GetTunnelBridgeDirection(tile);
|
||||
const TrackBits axial_track = DiagDirToDiagTrackBits(entrance_dir);
|
||||
const TrackBits existing = GetCustomBridgeHeadTrackBits(tile);
|
||||
const TrackBits future = existing | trackbit;
|
||||
|
||||
if (existing == future) return_cmd_error(STR_ERROR_ALREADY_BUILT);
|
||||
|
||||
if (flags & DC_NO_RAIL_OVERLAP || IsTunnelBridgeWithSignalSimulation(tile)) {
|
||||
if (future != TRACK_BIT_HORZ && future != TRACK_BIT_VERT) {
|
||||
return_cmd_error((flags & DC_NO_RAIL_OVERLAP) ? STR_ERROR_IMPOSSIBLE_TRACK_COMBINATION : STR_ERROR_MUST_REMOVE_SIGNALS_FIRST);
|
||||
}
|
||||
}
|
||||
|
||||
if ((trackbit & ~axial_track) && !_settings_game.construction.build_on_slopes) {
|
||||
return_cmd_error(STR_ERROR_LAND_SLOPED_IN_WRONG_DIRECTION);
|
||||
}
|
||||
|
||||
/* Steep slopes behave the same as slopes with one corner raised. */
|
||||
const Slope normalised_tileh = IsSteepSlope(tileh) ? SlopeWithOneCornerRaised(GetHighestSlopeCorner(tileh)) : tileh;
|
||||
|
||||
if (!IsValidFlatRailBridgeHeadTrackBits(normalised_tileh, GetTunnelBridgeDirection(tile), future)) {
|
||||
return_cmd_error(STR_ERROR_LAND_SLOPED_IN_WRONG_DIRECTION);
|
||||
}
|
||||
|
||||
const TileIndex other_end = GetOtherTunnelBridgeEnd(tile);
|
||||
ret = TunnelBridgeIsFree(tile, other_end);
|
||||
if (ret.Failed()) return ret;
|
||||
|
||||
if (flags & DC_EXEC) {
|
||||
SetCustomBridgeHeadTrackBits(tile, future);
|
||||
Company::Get(GetTileOwner(tile))->infrastructure.rail[GetRailType(tile)] += GetTunnelBridgeHeadOnlyRailInfrastructureCountFromTrackBits(future) - GetTunnelBridgeHeadOnlyRailInfrastructureCountFromTrackBits(existing);
|
||||
DirtyCompanyInfrastructureWindows(_current_company);
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
case MP_ROAD: {
|
||||
/* Level crossings may only be built on these slopes */
|
||||
if (!HasBit(VALID_LEVEL_CROSSING_SLOPES, tileh)) return_cmd_error(STR_ERROR_LAND_SLOPED_IN_WRONG_DIRECTION);
|
||||
@@ -731,6 +785,44 @@ CommandCost CmdRemoveSingleRail(TileIndex tile, DoCommandFlag flags, uint32 p1,
|
||||
break;
|
||||
}
|
||||
|
||||
case MP_TUNNELBRIDGE: {
|
||||
CommandCost ret = CheckTileOwnership(tile);
|
||||
if (ret.Failed()) return ret;
|
||||
|
||||
if (!IsFlatRailBridgeHeadTile(tile) || GetCustomBridgeHeadTrackBits(tile) == DiagDirToDiagTrackBits(GetTunnelBridgeDirection(tile))) {
|
||||
return DoCommand(tile, 0, 0, flags, CMD_LANDSCAPE_CLEAR); // just get appropriate error message
|
||||
}
|
||||
|
||||
const TrackBits present = GetCustomBridgeHeadTrackBits(tile);
|
||||
if ((present & trackbit) == 0) return_cmd_error(STR_ERROR_THERE_IS_NO_RAILROAD_TRACK);
|
||||
if (present == (TRACK_BIT_X | TRACK_BIT_Y)) crossing = true;
|
||||
|
||||
const TrackBits future = present ^ trackbit;
|
||||
|
||||
if ((GetAcrossBridgePossibleTrackBits(tile) & future) == 0) return DoCommand(tile, 0, 0, flags, CMD_LANDSCAPE_CLEAR); // just get appropriate error message
|
||||
|
||||
const TileIndex other_end = GetOtherTunnelBridgeEnd(tile);
|
||||
ret = TunnelBridgeIsFree(tile, other_end);
|
||||
if (ret.Failed()) return ret;
|
||||
|
||||
cost.AddCost(RailClearCost(GetRailType(tile)));
|
||||
|
||||
if (flags & DC_EXEC) {
|
||||
owner = GetTileOwner(tile);
|
||||
|
||||
if (HasReservedTracks(tile, trackbit)) {
|
||||
v = GetTrainForReservation(tile, track);
|
||||
if (v != NULL) FreeTrainTrackReservation(v);
|
||||
}
|
||||
|
||||
SetCustomBridgeHeadTrackBits(tile, future);
|
||||
Company::Get(GetTileOwner(tile))->infrastructure.rail[GetRailType(tile)] -= GetTunnelBridgeHeadOnlyRailInfrastructureCountFromTrackBits(present) - GetTunnelBridgeHeadOnlyRailInfrastructureCountFromTrackBits(future);
|
||||
DirtyCompanyInfrastructureWindows(_current_company);
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
default: return_cmd_error(STR_ERROR_THERE_IS_NO_RAILROAD_TRACK);
|
||||
}
|
||||
|
||||
@@ -1084,6 +1176,9 @@ CommandCost CmdBuildSingleSignal(TileIndex tile, DoCommandFlag flags, uint32 p1,
|
||||
/* You can only build signals on plain rail tiles or tunnel/bridges, and the selected track must exist */
|
||||
if (IsTileType(tile, MP_TUNNELBRIDGE)) {
|
||||
if (GetTunnelBridgeTransportType(tile) != TRANSPORT_RAIL) return CMD_ERROR;
|
||||
if (!ValParamTrackOrientation(track) || !IsTrackAcrossTunnelBridge(tile, track)) {
|
||||
return_cmd_error(STR_ERROR_THERE_IS_NO_RAILROAD_TRACK);
|
||||
}
|
||||
CommandCost ret = EnsureNoTrainOnTrack(GetOtherTunnelBridgeEnd(tile), track);
|
||||
if (ret.Failed()) return ret;
|
||||
ret = EnsureNoTrainOnTrack(tile, track);
|
||||
@@ -1100,19 +1195,24 @@ CommandCost CmdBuildSingleSignal(TileIndex tile, DoCommandFlag flags, uint32 p1,
|
||||
CommandCost cost;
|
||||
/* handle signals simulation on tunnel/bridge. */
|
||||
if (IsTileType(tile, MP_TUNNELBRIDGE)) {
|
||||
if (TracksOverlap(GetTunnelBridgeTrackBits(tile))) return_cmd_error(STR_ERROR_NO_SUITABLE_RAILROAD_TRACK);
|
||||
bool bidirectional = HasBit(p1, 18) && (sigtype == SIGTYPE_PBS);
|
||||
TileIndex tile_exit = GetOtherTunnelBridgeEnd(tile);
|
||||
cost = CommandCost();
|
||||
bool flip_variant = false;
|
||||
bool is_pbs = (sigtype == SIGTYPE_PBS) || (sigtype == SIGTYPE_PBS_ONEWAY);
|
||||
Trackdir entrance_td = TrackExitdirToTrackdir(track, GetTunnelBridgeDirection(tile));
|
||||
bool p2_signal_in = p2 & SignalAlongTrackdir(entrance_td);
|
||||
bool p2_signal_out = p2 & SignalAgainstTrackdir(entrance_td);
|
||||
bool p2_active = p2_signal_in || p2_signal_out;
|
||||
if (!IsTunnelBridgeWithSignalSimulation(tile)) { // toggle signal zero costs.
|
||||
if (convert_signal) return_cmd_error(STR_ERROR_THERE_ARE_NO_SIGNALS);
|
||||
if (p2 != 12) cost = CommandCost(EXPENSES_CONSTRUCTION, _price[PR_BUILD_SIGNALS] * ((GetTunnelBridgeLength(tile, tile_exit) + 4) >> 2) * (bidirectional ? 2 : 1)); // minimal 1
|
||||
if (!(p2_signal_in && p2_signal_out)) cost = CommandCost(EXPENSES_CONSTRUCTION, _price[PR_BUILD_SIGNALS] * ((GetTunnelBridgeLength(tile, tile_exit) + 4) >> 2) * (bidirectional ? 2 : 1)); // minimal 1
|
||||
} else {
|
||||
if (HasBit(p1, 17)) return CommandCost();
|
||||
bool is_bidi = IsTunnelBridgeSignalSimulationBidirectional(tile);
|
||||
bool will_be_bidi = is_bidi;
|
||||
if (p2 == 0) {
|
||||
if (!p2_active) {
|
||||
if (convert_signal) {
|
||||
will_be_bidi = bidirectional && !ctrl_pressed;
|
||||
} else if (ctrl_pressed) {
|
||||
@@ -1121,7 +1221,7 @@ CommandCost CmdBuildSingleSignal(TileIndex tile, DoCommandFlag flags, uint32 p1,
|
||||
} else if (!is_pbs) {
|
||||
will_be_bidi = false;
|
||||
}
|
||||
if ((p2 != 0 && (sigvar == SIG_SEMAPHORE) != IsTunnelBridgeSemaphore(tile)) ||
|
||||
if ((!p2_active && (sigvar == SIG_SEMAPHORE) != IsTunnelBridgeSemaphore(tile)) ||
|
||||
(convert_signal && (ctrl_pressed || (sigvar == SIG_SEMAPHORE) != IsTunnelBridgeSemaphore(tile)))) {
|
||||
flip_variant = true;
|
||||
cost = CommandCost(EXPENSES_CONSTRUCTION, ((_price[PR_BUILD_SIGNALS] * (will_be_bidi ? 2 : 1)) + (_price[PR_CLEAR_SIGNALS] * (is_bidi ? 2 : 1))) *
|
||||
@@ -1144,7 +1244,7 @@ CommandCost CmdBuildSingleSignal(TileIndex tile, DoCommandFlag flags, uint32 p1,
|
||||
if (flags & DC_EXEC) {
|
||||
Company * const c = Company::Get(GetTileOwner(tile));
|
||||
if (IsTunnelBridgeWithSignalSimulation(tile)) c->infrastructure.signal -= GetTunnelBridgeSignalSimulationSignalCount(tile, tile_exit);
|
||||
if (p2 == 0 && IsTunnelBridgeWithSignalSimulation(tile)) { // Toggle signal if already signals present.
|
||||
if (!p2_active && IsTunnelBridgeWithSignalSimulation(tile)) { // Toggle signal if already signals present.
|
||||
if (convert_signal) {
|
||||
if (flip_variant) {
|
||||
SetTunnelBridgeSemaphore(tile, !IsTunnelBridgeSemaphore(tile));
|
||||
@@ -1175,18 +1275,16 @@ CommandCost CmdBuildSingleSignal(TileIndex tile, DoCommandFlag flags, uint32 p1,
|
||||
}
|
||||
} else {
|
||||
/* Create one direction tunnel/bridge if required. */
|
||||
if (p2 == 0) {
|
||||
if (!p2_active) {
|
||||
if (bidirectional) {
|
||||
set_bidi(tile);
|
||||
set_bidi(tile_exit);
|
||||
} else {
|
||||
SetupBridgeTunnelSignalSimulation(tile, tile_exit);
|
||||
}
|
||||
} else if (p2 == 4 || p2 == 8) {
|
||||
DiagDirection tbdir = GetTunnelBridgeDirection(tile);
|
||||
} else if (p2_signal_in != p2_signal_out) {
|
||||
/* If signal only on one side build accoringly one-way tunnel/bridge. */
|
||||
if ((p2 == 8 && (tbdir == DIAGDIR_NE || tbdir == DIAGDIR_SE)) ||
|
||||
(p2 == 4 && (tbdir == DIAGDIR_SW || tbdir == DIAGDIR_NW))) {
|
||||
if (p2_signal_in) {
|
||||
ClearBridgeTunnelSignalSimulation(tile_exit, tile);
|
||||
SetupBridgeTunnelSignalSimulation(tile, tile_exit);
|
||||
} else {
|
||||
@@ -1194,7 +1292,7 @@ CommandCost CmdBuildSingleSignal(TileIndex tile, DoCommandFlag flags, uint32 p1,
|
||||
SetupBridgeTunnelSignalSimulation(tile_exit, tile);
|
||||
}
|
||||
}
|
||||
if (p2 == 0 || p2 == 4 || p2 == 8) {
|
||||
if (!(p2_signal_in && p2_signal_out)) {
|
||||
SetTunnelBridgeSemaphore(tile, sigvar == SIG_SEMAPHORE);
|
||||
SetTunnelBridgeSemaphore(tile_exit, sigvar == SIG_SEMAPHORE);
|
||||
SetTunnelBridgePBS(tile, is_pbs);
|
||||
@@ -1202,8 +1300,8 @@ CommandCost CmdBuildSingleSignal(TileIndex tile, DoCommandFlag flags, uint32 p1,
|
||||
if (!IsTunnelBridgePBS(tile)) remove_pbs_bidi();
|
||||
}
|
||||
}
|
||||
if (IsTunnelBridgeSignalSimulationExit(tile) && IsTunnelBridgePBS(tile) && !HasTunnelBridgeReservation(tile)) SetTunnelBridgeExitSignalState(tile, SIGNAL_STATE_RED);
|
||||
if (IsTunnelBridgeSignalSimulationExit(tile_exit) && IsTunnelBridgePBS(tile_exit) && !HasTunnelBridgeReservation(tile_exit)) SetTunnelBridgeExitSignalState(tile_exit, SIGNAL_STATE_RED);
|
||||
if (IsTunnelBridgeSignalSimulationExit(tile) && IsTunnelBridgePBS(tile) && !HasAcrossTunnelBridgeReservation(tile)) SetTunnelBridgeExitSignalState(tile, SIGNAL_STATE_RED);
|
||||
if (IsTunnelBridgeSignalSimulationExit(tile_exit) && IsTunnelBridgePBS(tile_exit) && !HasAcrossTunnelBridgeReservation(tile_exit)) SetTunnelBridgeExitSignalState(tile_exit, SIGNAL_STATE_RED);
|
||||
MarkBridgeOrTunnelDirty(tile);
|
||||
AddSideToSignalBuffer(tile, INVALID_DIAGDIR, GetTileOwner(tile));
|
||||
AddSideToSignalBuffer(tile_exit, INVALID_DIAGDIR, GetTileOwner(tile));
|
||||
@@ -1393,13 +1491,27 @@ static bool CheckSignalAutoFill(TileIndex &tile, Trackdir &trackdir, int &signal
|
||||
TileIndex orig_tile = tile; // backup old value
|
||||
|
||||
if (GetTunnelBridgeTransportType(tile) != TRANSPORT_RAIL) return false;
|
||||
if (GetTunnelBridgeDirection(tile) != TrackdirToExitdir(trackdir)) return false;
|
||||
|
||||
signal_ctr += IsDiagonalTrackdir(trackdir) ? 2 : 1;
|
||||
if (GetTunnelBridgeDirection(tile) == TrackdirToExitdir(trackdir)) {
|
||||
/* Skip to end of tunnel or bridge
|
||||
* note that tile is a parameter by reference, so it must be updated */
|
||||
tile = GetOtherTunnelBridgeEnd(tile);
|
||||
signal_ctr += GetTunnelBridgeLength(orig_tile, tile) * 2;
|
||||
|
||||
signal_ctr += (GetTunnelBridgeLength(orig_tile, tile) + 2) * 2;
|
||||
/* Check for track bits on the new tile */
|
||||
trackdirbits = TrackStatusToTrackdirBits(GetTileTrackStatus(tile, TRANSPORT_RAIL, 0));
|
||||
|
||||
if (TracksOverlap(TrackdirBitsToTrackBits(trackdirbits))) return false;
|
||||
trackdirbits &= TrackdirReachesTrackdirs(trackdir);
|
||||
|
||||
/* Get the first track dir */
|
||||
trackdir = RemoveFirstTrackdir(&trackdirbits);
|
||||
|
||||
/* Any left? It's a junction so we stop */
|
||||
if (trackdirbits != TRACKDIR_BIT_NONE) return false;
|
||||
|
||||
signal_ctr += IsDiagonalTrackdir(trackdir) ? 2 : 1;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -1823,6 +1935,24 @@ CommandCost CmdConvertRail(TileIndex tile, DoCommandFlag flags, uint32 p1, uint3
|
||||
|
||||
SmallVector<Train *, 2> vehicles_affected;
|
||||
|
||||
auto find_train_reservations = [&vehicles_affected, &totype](TileIndex tile, TrackBits reserved) {
|
||||
Track track;
|
||||
while ((track = RemoveFirstTrack(&reserved)) != INVALID_TRACK) {
|
||||
Train *v = GetTrainForReservation(tile, track);
|
||||
if (v != NULL && !HasPowerOnRail(v->railtype, totype)) {
|
||||
/* No power on new rail type, reroute. */
|
||||
FreeTrainTrackReservation(v);
|
||||
*vehicles_affected.Append() = v;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
auto yapf_notify_track_change = [](TileIndex tile, TrackBits tracks) {
|
||||
while (tracks != TRACK_BIT_NONE) {
|
||||
YapfNotifyTrackLayoutChange(tile, RemoveFirstTrack(&tracks));
|
||||
}
|
||||
};
|
||||
|
||||
/* Vehicle on the tile when not converting Rail <-> ElRail
|
||||
* Tunnels and bridges have special check later */
|
||||
if (tt != MP_TUNNELBRIDGE) {
|
||||
@@ -1834,16 +1964,7 @@ CommandCost CmdConvertRail(TileIndex tile, DoCommandFlag flags, uint32 p1, uint3
|
||||
}
|
||||
}
|
||||
if (flags & DC_EXEC) { // we can safely convert, too
|
||||
TrackBits reserved = GetReservedTrackbits(tile);
|
||||
Track track;
|
||||
while ((track = RemoveFirstTrack(&reserved)) != INVALID_TRACK) {
|
||||
Train *v = GetTrainForReservation(tile, track);
|
||||
if (v != NULL && !HasPowerOnRail(v->railtype, totype)) {
|
||||
/* No power on new rail type, reroute. */
|
||||
FreeTrainTrackReservation(v);
|
||||
*vehicles_affected.Append() = v;
|
||||
}
|
||||
}
|
||||
find_train_reservations(tile, GetReservedTrackbits(tile));
|
||||
|
||||
/* Update the company infrastructure counters. */
|
||||
if (!IsRailStationTile(tile) || !IsStationTileBlocked(tile)) {
|
||||
@@ -1884,10 +2005,7 @@ CommandCost CmdConvertRail(TileIndex tile, DoCommandFlag flags, uint32 p1, uint3
|
||||
default: // RAIL_TILE_NORMAL, RAIL_TILE_SIGNALS
|
||||
if (flags & DC_EXEC) {
|
||||
/* notify YAPF about the track layout change */
|
||||
TrackBits tracks = GetTrackBits(tile);
|
||||
while (tracks != TRACK_BIT_NONE) {
|
||||
YapfNotifyTrackLayoutChange(tile, RemoveFirstTrack(&tracks));
|
||||
}
|
||||
yapf_notify_track_change(tile, GetTrackBits(tile));
|
||||
}
|
||||
cost.AddCost(RailConvertCost(type, totype) * CountBits(GetTrackBits(tile)));
|
||||
break;
|
||||
@@ -1916,22 +2034,18 @@ CommandCost CmdConvertRail(TileIndex tile, DoCommandFlag flags, uint32 p1, uint3
|
||||
}
|
||||
}
|
||||
|
||||
uint middle_len = GetTunnelBridgeLength(tile, endtile);
|
||||
uint num_raw_pieces = middle_len + CountBits(GetTunnelBridgeTrackBits(tile)) + CountBits(GetTunnelBridgeTrackBits(endtile));
|
||||
|
||||
if (flags & DC_EXEC) {
|
||||
Track track = DiagDirToDiagTrack(GetTunnelBridgeDirection(tile));
|
||||
if (HasTunnelBridgeReservation(tile)) {
|
||||
Train *v = GetTrainForReservation(tile, track);
|
||||
if (v != NULL && !HasPowerOnRail(v->railtype, totype)) {
|
||||
/* No power on new rail type, reroute. */
|
||||
FreeTrainTrackReservation(v);
|
||||
*vehicles_affected.Append() = v;
|
||||
}
|
||||
}
|
||||
find_train_reservations(tile, GetTunnelBridgeReservationTrackBits(tile));
|
||||
find_train_reservations(endtile, GetTunnelBridgeReservationTrackBits(endtile));
|
||||
|
||||
/* Update the company infrastructure counters. */
|
||||
uint num_pieces = (GetTunnelBridgeLength(tile, endtile) + 2) * TUNNELBRIDGE_TRACKBIT_FACTOR;
|
||||
uint num_infra_pieces = (middle_len* TUNNELBRIDGE_TRACKBIT_FACTOR) + GetTunnelBridgeHeadOnlyRailInfrastructureCount(tile) + GetTunnelBridgeHeadOnlyRailInfrastructureCount(endtile);
|
||||
Company *c = Company::Get(GetTileOwner(tile));
|
||||
c->infrastructure.rail[GetRailType(tile)] -= num_pieces;
|
||||
c->infrastructure.rail[totype] += num_pieces;
|
||||
c->infrastructure.rail[GetRailType(tile)] -= num_infra_pieces;
|
||||
c->infrastructure.rail[totype] += num_infra_pieces;
|
||||
DirtyCompanyInfrastructureWindows(c->index);
|
||||
|
||||
SetRailType(tile, totype);
|
||||
@@ -1940,8 +2054,9 @@ CommandCost CmdConvertRail(TileIndex tile, DoCommandFlag flags, uint32 p1, uint3
|
||||
FindVehicleOnPos(tile, &affected_trains, &UpdateTrainPowerProc);
|
||||
FindVehicleOnPos(endtile, &affected_trains, &UpdateTrainPowerProc);
|
||||
|
||||
YapfNotifyTrackLayoutChange(tile, track);
|
||||
YapfNotifyTrackLayoutChange(endtile, track);
|
||||
/* notify YAPF about the track layout change */
|
||||
yapf_notify_track_change(tile, GetTunnelBridgeTrackBits(tile));
|
||||
yapf_notify_track_change(endtile, GetTunnelBridgeTrackBits(endtile));
|
||||
|
||||
if (IsBridge(tile)) {
|
||||
MarkBridgeDirty(tile, ZOOM_LVL_DRAW_MAP);
|
||||
@@ -1951,7 +2066,7 @@ CommandCost CmdConvertRail(TileIndex tile, DoCommandFlag flags, uint32 p1, uint3
|
||||
}
|
||||
}
|
||||
|
||||
cost.AddCost((GetTunnelBridgeLength(tile, endtile) + 2) * RailConvertCost(type, totype));
|
||||
cost.AddCost(num_raw_pieces * RailConvertCost(type, totype));
|
||||
break;
|
||||
}
|
||||
|
||||
@@ -2089,7 +2204,7 @@ static uint GetSaveSlopeZ(uint x, uint y, Track track)
|
||||
return GetSlopePixelZ(x, y);
|
||||
}
|
||||
|
||||
static void DrawSingleSignal(TileIndex tile, const RailtypeInfo *rti, Track track, SignalState condition, SignalOffsets image, uint pos)
|
||||
void DrawSingleSignal(TileIndex tile, const RailtypeInfo *rti, Track track, SignalState condition, SignalOffsets image, uint pos, SignalType type, SignalVariant variant, bool show_restricted)
|
||||
{
|
||||
bool side;
|
||||
switch (_settings_game.construction.train_signal_side) {
|
||||
@@ -2114,11 +2229,6 @@ static void DrawSingleSignal(TileIndex tile, const RailtypeInfo *rti, Track trac
|
||||
uint x = TileX(tile) * TILE_SIZE + SignalPositions[side][pos].x;
|
||||
uint y = TileY(tile) * TILE_SIZE + SignalPositions[side][pos].y;
|
||||
|
||||
SignalType type = GetSignalType(tile, track);
|
||||
SignalVariant variant = GetSignalVariant(tile, track);
|
||||
|
||||
bool show_restricted = (variant == SIG_ELECTRIC) && IsRestrictedSignal(tile) && (GetExistingTraceRestrictProgram(tile, track) != NULL);
|
||||
|
||||
SpriteID sprite = GetCustomSignalSprite(rti, tile, type, variant, condition);
|
||||
bool is_custom_sprite = (sprite != 0);
|
||||
if (sprite != 0) {
|
||||
@@ -2164,6 +2274,15 @@ static void DrawSingleSignal(TileIndex tile, const RailtypeInfo *rti, Track trac
|
||||
}
|
||||
}
|
||||
|
||||
static void DrawSingleSignal(TileIndex tile, const RailtypeInfo *rti, Track track, SignalState condition, SignalOffsets image, uint pos)
|
||||
{
|
||||
SignalType type = GetSignalType(tile, track);
|
||||
SignalVariant variant = GetSignalVariant(tile, track);
|
||||
|
||||
bool show_restricted = (variant == SIG_ELECTRIC) && IsRestrictedSignal(tile) && (GetExistingTraceRestrictProgram(tile, track) != NULL);
|
||||
DrawSingleSignal(tile, rti, track, condition, image, pos, type, variant, show_restricted);
|
||||
}
|
||||
|
||||
static uint32 _drawtile_track_palette;
|
||||
|
||||
|
||||
@@ -2325,10 +2444,19 @@ static inline void DrawTrackSprite(SpriteID sprite, PaletteID pal, const TileInf
|
||||
DrawGroundSprite(sprite, pal, NULL, 0, (ti->tileh & s) ? -8 : 0);
|
||||
}
|
||||
|
||||
static RailGroundType GetRailOrBridgeGroundType(TileInfo *ti) {
|
||||
if (IsTileType(ti->tile, MP_TUNNELBRIDGE)) {
|
||||
return HasTunnelBridgeSnowOrDesert(ti->tile) ? RAIL_GROUND_ICE_DESERT : RAIL_GROUND_GRASS;
|
||||
} else {
|
||||
return GetRailGroundType(ti->tile);
|
||||
}
|
||||
}
|
||||
|
||||
static void DrawTrackBitsOverlay(TileInfo *ti, TrackBits track, const RailtypeInfo *rti)
|
||||
{
|
||||
RailGroundType rgt = GetRailGroundType(ti->tile);
|
||||
Foundation f = GetRailFoundation(ti->tileh, track);
|
||||
const bool is_bridge = IsTileType(ti->tile, MP_TUNNELBRIDGE);
|
||||
RailGroundType rgt = GetRailOrBridgeGroundType(ti);
|
||||
Foundation f = is_bridge ? FOUNDATION_LEVELED : GetRailFoundation(ti->tileh, track);
|
||||
Corner halftile_corner = CORNER_INVALID;
|
||||
|
||||
if (IsNonContinuousFoundation(f)) {
|
||||
@@ -2367,7 +2495,10 @@ static void DrawTrackBitsOverlay(TileInfo *ti, TrackBits track, const RailtypeIn
|
||||
|
||||
SpriteID overlay = GetCustomRailSprite(rti, ti->tile, RTSG_OVERLAY);
|
||||
SpriteID ground = GetCustomRailSprite(rti, ti->tile, RTSG_GROUND);
|
||||
TrackBits pbs = _settings_client.gui.show_track_reservation ? GetRailReservationTrackBits(ti->tile) : TRACK_BIT_NONE;
|
||||
TrackBits pbs = TRACK_BIT_NONE;
|
||||
if (_settings_client.gui.show_track_reservation) {
|
||||
pbs = is_bridge ? GetTunnelBridgeReservationTrackBits(ti->tile) : GetRailReservationTrackBits(ti->tile);
|
||||
}
|
||||
|
||||
if (track == TRACK_BIT_NONE) {
|
||||
/* Half-tile foundation, no track here? */
|
||||
@@ -2477,7 +2608,7 @@ static void DrawTrackBitsOverlay(TileInfo *ti, TrackBits track, const RailtypeIn
|
||||
* @param ti TileInfo
|
||||
* @param track TrackBits to draw
|
||||
*/
|
||||
static void DrawTrackBits(TileInfo *ti, TrackBits track)
|
||||
void DrawTrackBits(TileInfo *ti, TrackBits track)
|
||||
{
|
||||
const RailtypeInfo *rti = GetRailTypeInfo(GetRailType(ti->tile));
|
||||
|
||||
@@ -2486,8 +2617,9 @@ static void DrawTrackBits(TileInfo *ti, TrackBits track)
|
||||
return;
|
||||
}
|
||||
|
||||
RailGroundType rgt = GetRailGroundType(ti->tile);
|
||||
Foundation f = GetRailFoundation(ti->tileh, track);
|
||||
const bool is_bridge = IsTileType(ti->tile, MP_TUNNELBRIDGE);
|
||||
RailGroundType rgt = GetRailOrBridgeGroundType(ti);
|
||||
Foundation f = is_bridge ? FOUNDATION_LEVELED : GetRailFoundation(ti->tileh, track);
|
||||
Corner halftile_corner = CORNER_INVALID;
|
||||
|
||||
if (IsNonContinuousFoundation(f)) {
|
||||
@@ -2578,7 +2710,7 @@ static void DrawTrackBits(TileInfo *ti, TrackBits track)
|
||||
/* PBS debugging, draw reserved tracks darker */
|
||||
if (_game_mode != GM_MENU && _settings_client.gui.show_track_reservation) {
|
||||
/* Get reservation, but mask track on halftile slope */
|
||||
TrackBits pbs = GetRailReservationTrackBits(ti->tile) & track;
|
||||
TrackBits pbs = (is_bridge ? GetTunnelBridgeReservationTrackBits(ti->tile) : GetRailReservationTrackBits(ti->tile)) & track;
|
||||
if (pbs & TRACK_BIT_X) {
|
||||
if (ti->tileh == SLOPE_FLAT || ti->tileh == SLOPE_ELEVATED) {
|
||||
DrawGroundSprite(rti->base_sprites.single_x, PALETTE_CRASH);
|
||||
|
@@ -486,7 +486,7 @@ static inline bool HasOnewaySignalBlockingTrackdir(TileIndex tile, Trackdir td)
|
||||
return true;
|
||||
}
|
||||
if (IsTileType(tile, MP_TUNNELBRIDGE) && IsTunnelBridgeSignalSimulationExitOnly(tile) &&
|
||||
DiagDirToDiagTrackdir(GetTunnelBridgeDirection(tile)) == td) {
|
||||
TrackdirEntersTunnelBridge(tile, td)) {
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
|
@@ -1372,6 +1372,29 @@ bool AfterLoadGame()
|
||||
}
|
||||
}
|
||||
|
||||
if (SlXvIsFeaturePresent(XSLFI_SIG_TUNNEL_BRIDGE, 1, 6)) {
|
||||
/* m2 signal state bit allocation has shrunk */
|
||||
for (TileIndex t = 0; t < map_size; t++) {
|
||||
if (IsTileType(t, MP_TUNNELBRIDGE) && GetTunnelBridgeTransportType(t) == TRANSPORT_RAIL && IsBridge(t) && IsTunnelBridgeSignalSimulationEntrance(t)) {
|
||||
extern void ShiftBridgeEntranceSimulatedSignalsExtended(TileIndex t, int shift, uint64 in);
|
||||
const uint shift = 15 - BRIDGE_M2_SIGNAL_STATE_COUNT;
|
||||
ShiftBridgeEntranceSimulatedSignalsExtended(t, shift, GB(_m[t].m2, BRIDGE_M2_SIGNAL_STATE_COUNT, shift));
|
||||
SB(_m[t].m2, 0, 15, GB(_m[t].m2, 0, 15) << shift);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!SlXvIsFeaturePresent(XSLFI_CUSTOM_BRIDGE_HEADS, 2)) {
|
||||
/* change map bits for rail bridge heads */
|
||||
for (TileIndex t = 0; t < map_size; t++) {
|
||||
if (IsBridgeTile(t) && GetTunnelBridgeTransportType(t) == TRANSPORT_RAIL) {
|
||||
SetCustomBridgeHeadTrackBits(t, DiagDirToDiagTrackBits(GetTunnelBridgeDirection(t)));
|
||||
SetBridgeReservationTrackBits(t, HasBit(_m[t].m5, 4) ? DiagDirToDiagTrackBits(GetTunnelBridgeDirection(t)) : TRACK_BIT_NONE);
|
||||
ClrBit(_m[t].m5, 4);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* Elrails got added in rev 24 */
|
||||
if (IsSavegameVersionBefore(24)) {
|
||||
RailType min_rail = RAILTYPE_ELECTRIC;
|
||||
@@ -2109,7 +2132,7 @@ bool AfterLoadGame()
|
||||
break;
|
||||
|
||||
case MP_TUNNELBRIDGE: // Clear PBS reservation on tunnels/bridges
|
||||
if (GetTunnelBridgeTransportType(t) == TRANSPORT_RAIL) SetTunnelBridgeReservation(t, false);
|
||||
if (GetTunnelBridgeTransportType(t) == TRANSPORT_RAIL) UnreserveAcrossRailTunnelBridge(t);
|
||||
break;
|
||||
|
||||
default: break;
|
||||
@@ -3376,17 +3399,6 @@ bool AfterLoadGame()
|
||||
}
|
||||
}
|
||||
}
|
||||
if (SlXvIsFeaturePresent(XSLFI_SIG_TUNNEL_BRIDGE, 1, 6)) {
|
||||
/* m2 signal state bit allocation has shrunk */
|
||||
for (TileIndex t = 0; t < map_size; t++) {
|
||||
if (IsTileType(t, MP_TUNNELBRIDGE) && GetTunnelBridgeTransportType(t) == TRANSPORT_RAIL && IsBridge(t) && IsTunnelBridgeSignalSimulationEntrance(t)) {
|
||||
extern void ShiftBridgeEntranceSimulatedSignalsExtended(TileIndex t, int shift, uint64 in);
|
||||
const uint shift = 15 - BRIDGE_M2_SIGNAL_STATE_COUNT;
|
||||
ShiftBridgeEntranceSimulatedSignalsExtended(t, shift, GB(_m[t].m2, BRIDGE_M2_SIGNAL_STATE_COUNT, shift));
|
||||
SB(_m[t].m2, 0, 15, GB(_m[t].m2, 0, 15) << shift);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (SlXvIsFeatureMissing(XSLFI_CUSTOM_BRIDGE_HEADS)) {
|
||||
/* ensure that previously unused custom bridge-head bits are cleared */
|
||||
|
@@ -202,13 +202,12 @@ void AfterLoadCompanyStats()
|
||||
/* Count each tunnel/bridge TUNNELBRIDGE_TRACKBIT_FACTOR times to simulate
|
||||
* the higher structural maintenance needs, and don't forget the end tiles. */
|
||||
const uint middle_len = GetTunnelBridgeLength(tile, other_end) * TUNNELBRIDGE_TRACKBIT_FACTOR;
|
||||
const uint len = middle_len + (2 * TUNNELBRIDGE_TRACKBIT_FACTOR);
|
||||
|
||||
switch (GetTunnelBridgeTransportType(tile)) {
|
||||
case TRANSPORT_RAIL:
|
||||
c = Company::GetIfValid(GetTileOwner(tile));
|
||||
if (c != NULL) {
|
||||
c->infrastructure.rail[GetRailType(tile)] += len;
|
||||
c->infrastructure.rail[GetRailType(tile)] += middle_len + GetTunnelBridgeHeadOnlyRailInfrastructureCount(tile) + GetTunnelBridgeHeadOnlyRailInfrastructureCount(other_end);
|
||||
if (IsTunnelBridgeWithSignalSimulation(tile)) {
|
||||
c->infrastructure.signal += GetTunnelBridgeSignalSimulationSignalCount(tile, other_end);
|
||||
}
|
||||
@@ -222,7 +221,7 @@ void AfterLoadCompanyStats()
|
||||
|
||||
case TRANSPORT_WATER:
|
||||
c = Company::GetIfValid(GetTileOwner(tile));
|
||||
if (c != NULL) c->infrastructure.water += len;
|
||||
if (c != NULL) c->infrastructure.water += middle_len + (2 * TUNNELBRIDGE_TRACKBIT_FACTOR);
|
||||
break;
|
||||
|
||||
default:
|
||||
|
@@ -75,7 +75,7 @@ const SlxiSubChunkInfo _sl_xv_sub_chunk_infos[] = {
|
||||
{ XSLFI_CARGO_TYPE_ORDERS, XSCF_NULL, 3, 3, "cargo_type_orders", NULL, NULL, "ORDX,VEOX" },
|
||||
{ XSLFI_EXTENDED_GAMELOG, XSCF_NULL, 1, 1, "extended_gamelog", NULL, NULL, NULL },
|
||||
{ XSLFI_STATION_CATCHMENT_INC, XSCF_NULL, 1, 1, "station_catchment_inc", NULL, NULL, NULL },
|
||||
{ XSLFI_CUSTOM_BRIDGE_HEADS, XSCF_NULL, 1, 1, "custom_bridge_heads", NULL, NULL, NULL },
|
||||
{ XSLFI_CUSTOM_BRIDGE_HEADS, XSCF_NULL, 2, 2, "custom_bridge_heads", NULL, NULL, NULL },
|
||||
{ XSLFI_CHUNNEL, XSCF_NULL, 1, 1, "chunnel", NULL, NULL, "TUNN" },
|
||||
{ XSLFI_SCHEDULED_DISPATCH, XSCF_NULL, 1, 1, "scheduled_dispatch", NULL, NULL, NULL },
|
||||
{ XSLFI_MORE_TOWN_GROWTH_RATES, XSCF_NULL, 1, 1, "more_town_growth_rates", NULL, NULL, NULL },
|
||||
|
@@ -375,6 +375,7 @@ struct ConstructionSettings {
|
||||
bool enable_remove_water; ///< enable removing sea and rivers in-game
|
||||
uint8 road_custom_bridge_heads; ///< allow construction of road custom bridge heads
|
||||
bool chunnel; ///< allow construction of tunnels under water
|
||||
uint8 rail_custom_bridge_heads; ///< allow construction of rail custom bridge heads
|
||||
|
||||
uint32 terraform_per_64k_frames; ///< how many tile heights may, over a long period, be terraformed per 65536 frames?
|
||||
uint16 terraform_frame_burst; ///< how many tile heights may, over a short period, be terraformed?
|
||||
|
@@ -217,7 +217,9 @@ static Vehicle *TrainInWormholeTileEnum(Vehicle *v, void *data)
|
||||
{
|
||||
/* Only look for front engine or last wagon. */
|
||||
if (v->type != VEH_TRAIN || (v->Previous() != NULL && v->Next() != NULL)) return NULL;
|
||||
if (*(TileIndex *)data != TileVirtXY(v->x_pos, v->y_pos)) return NULL;
|
||||
TileIndex tile = *(TileIndex *)data;
|
||||
if (tile != TileVirtXY(v->x_pos, v->y_pos)) return NULL;
|
||||
if (!(Train::From(v)->track & TRACK_BIT_WORMHOLE) && !(Train::From(v)->track & GetAcrossTunnelBridgeTrackBits(tile))) return NULL;
|
||||
return v;
|
||||
}
|
||||
|
||||
@@ -407,11 +409,29 @@ static SigInfo ExploreSegment(Owner owner)
|
||||
case MP_TUNNELBRIDGE: {
|
||||
if (!IsOneSignalBlock(owner, GetTileOwner(tile))) continue;
|
||||
if (GetTunnelBridgeTransportType(tile) != TRANSPORT_RAIL) continue;
|
||||
DiagDirection dir = GetTunnelBridgeDirection(tile);
|
||||
DiagDirection tunnel_bridge_dir = GetTunnelBridgeDirection(tile);
|
||||
TrackBits tracks = GetTunnelBridgeTrackBits(tile);
|
||||
TrackBits across_tracks = GetAcrossTunnelBridgeTrackBits(tile);
|
||||
|
||||
auto check_train_present = [tile, tracks, across_tracks](DiagDirection enterdir) -> bool {
|
||||
if (tracks == TRACK_BIT_HORZ || tracks == TRACK_BIT_VERT) {
|
||||
if (_enterdir_to_trackbits[enterdir] & across_tracks) {
|
||||
return EnsureNoTrainOnTrackBits(tile, TRACK_BIT_WORMHOLE | across_tracks).Failed();
|
||||
} else {
|
||||
return EnsureNoTrainOnTrackBits(tile, tracks & (~across_tracks)).Failed();
|
||||
}
|
||||
} else {
|
||||
return HasVehicleOnPos(tile, NULL, &TrainOnTileEnum);
|
||||
}
|
||||
};
|
||||
|
||||
TrackBits tracks_masked = (TrackBits)(tracks & _enterdir_to_trackbits[enterdir == INVALID_DIAGDIR ? tunnel_bridge_dir : enterdir]); // only incidating trackbits
|
||||
if (tracks == TRACK_BIT_HORZ || tracks == TRACK_BIT_VERT) tracks = tracks_masked;
|
||||
|
||||
if (IsTunnelBridgeWithSignalSimulation(tile)) {
|
||||
if (enterdir == INVALID_DIAGDIR) { // incoming from the wormhole
|
||||
if (!(info.flags & SF_TRAIN) && IsTunnelBridgeSignalSimulationExit(tile)) { // tunnel entrence is ignored
|
||||
if (enterdir == INVALID_DIAGDIR) {
|
||||
// incoming from the wormhole, onto signal
|
||||
if (!(info.flags & SF_TRAIN) && IsTunnelBridgeSignalSimulationExit(tile)) { // tunnel entrance is ignored
|
||||
if (HasVehicleOnPos(GetOtherTunnelBridgeEnd(tile), &tile, &TrainInWormholeTileEnum)) info.flags |= SF_TRAIN;
|
||||
if (!(info.flags & SF_TRAIN) && HasVehicleOnPos(tile, &tile, &TrainInWormholeTileEnum)) info.flags |= SF_TRAIN;
|
||||
}
|
||||
@@ -419,11 +439,13 @@ static SigInfo ExploreSegment(Owner owner)
|
||||
info.flags |= SF_FULL;
|
||||
return info;
|
||||
}
|
||||
enterdir = dir;
|
||||
exitdir = ReverseDiagDir(dir);
|
||||
Trackdir exit_track = TrackEnterdirToTrackdir(FindFirstTrack(GetAcrossTunnelBridgeTrackBits(tile)), ReverseDiagDir(tunnel_bridge_dir));
|
||||
exitdir = TrackdirToExitdir(exit_track);
|
||||
enterdir = ReverseDiagDir(exitdir);
|
||||
tile += TileOffsByDiagDir(exitdir); // just skip to next tile
|
||||
} else { // NOT incoming from the wormhole!
|
||||
if (ReverseDiagDir(enterdir) != dir) continue;
|
||||
break;
|
||||
} else if (_enterdir_to_trackbits[enterdir] & GetAcrossTunnelBridgeTrackBits(tile)) {
|
||||
// NOT incoming from the wormhole!
|
||||
if (IsTunnelBridgeSignalSimulationExit(tile)) {
|
||||
if (IsTunnelBridgePBS(tile)) {
|
||||
info.flags |= SF_PBS;
|
||||
@@ -440,21 +462,32 @@ static SigInfo ExploreSegment(Owner owner)
|
||||
}
|
||||
continue;
|
||||
}
|
||||
} else {
|
||||
}
|
||||
if (enterdir == INVALID_DIAGDIR) { // incoming from the wormhole
|
||||
if (!(info.flags & SF_TRAIN) && HasVehicleOnPos(tile, NULL, &TrainOnTileEnum)) info.flags |= SF_TRAIN;
|
||||
enterdir = dir;
|
||||
exitdir = ReverseDiagDir(dir);
|
||||
tile += TileOffsByDiagDir(exitdir); // just skip to next tile
|
||||
} else { // NOT incoming from the wormhole!
|
||||
if (ReverseDiagDir(enterdir) != dir) continue;
|
||||
if (!(info.flags & SF_TRAIN) && HasVehicleOnPos(tile, NULL, &TrainOnTileEnum)) info.flags |= SF_TRAIN;
|
||||
tile = GetOtherTunnelBridgeEnd(tile); // just skip to exit tile
|
||||
enterdir = INVALID_DIAGDIR;
|
||||
exitdir = INVALID_DIAGDIR;
|
||||
if (!(info.flags & SF_TRAIN) && check_train_present(tunnel_bridge_dir)) info.flags |= SF_TRAIN;
|
||||
enterdir = tunnel_bridge_dir;
|
||||
} else if (enterdir != tunnel_bridge_dir) { // NOT incoming from the wormhole!
|
||||
if (tracks_masked == TRACK_BIT_NONE) continue; // no incidating track
|
||||
if (!(info.flags & SF_TRAIN) && check_train_present(enterdir)) info.flags |= SF_TRAIN;
|
||||
}
|
||||
for (DiagDirection dir = DIAGDIR_BEGIN; dir < DIAGDIR_END; dir++) { // test all possible exit directions
|
||||
if (dir != enterdir && (tracks & _enterdir_to_trackbits[dir])) { // any track incidating?
|
||||
if (dir == tunnel_bridge_dir) {
|
||||
if (!MaybeAddToTodoSet(GetOtherTunnelBridgeEnd(tile), INVALID_DIAGDIR, tile, INVALID_DIAGDIR)) {
|
||||
info.flags |= SF_FULL;
|
||||
return info;
|
||||
}
|
||||
} else {
|
||||
TileIndex newtile = tile + TileOffsByDiagDir(dir); // new tile to check
|
||||
DiagDirection newdir = ReverseDiagDir(dir); // direction we are entering from
|
||||
if (!MaybeAddToTodoSet(newtile, newdir, tile, dir)) {
|
||||
info.flags |= SF_FULL;
|
||||
return info;
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
continue; // continue the while() loop
|
||||
}
|
||||
|
||||
default:
|
||||
@@ -593,18 +626,23 @@ static SigSegState UpdateSignalsInBuffer(Owner owner)
|
||||
* train entering/leaving block, train leaving depot...
|
||||
*/
|
||||
switch (GetTileType(tile)) {
|
||||
case MP_TUNNELBRIDGE:
|
||||
case MP_TUNNELBRIDGE: {
|
||||
/* 'optimization assert' - do not try to update signals when it is not needed */
|
||||
assert(GetTunnelBridgeTransportType(tile) == TRANSPORT_RAIL);
|
||||
assert(dir == INVALID_DIAGDIR || dir == ReverseDiagDir(GetTunnelBridgeDirection(tile)));
|
||||
if (IsTunnel(tile)) assert(dir == INVALID_DIAGDIR || dir == ReverseDiagDir(GetTunnelBridgeDirection(tile)));
|
||||
TrackBits across = GetAcrossTunnelBridgeTrackBits(tile);
|
||||
if (dir == INVALID_DIAGDIR || _enterdir_to_trackbits[dir] & across) {
|
||||
_tbdset.Add(tile, INVALID_DIAGDIR); // we can safely start from wormhole centre
|
||||
if (!IsTunnelBridgeWithSignalSimulation(tile)) { // Don't worry with other side of tunnel.
|
||||
_tbdset.Add(GetOtherTunnelBridgeEnd(tile), INVALID_DIAGDIR);
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
FALLTHROUGH;
|
||||
|
||||
case MP_RAILWAY:
|
||||
if (IsRailDepot(tile)) {
|
||||
if (IsRailDepotTile(tile)) {
|
||||
/* 'optimization assert' do not try to update signals in other cases */
|
||||
assert(dir == INVALID_DIAGDIR || dir == GetRailDepotDirection(tile));
|
||||
_tbdset.Add(tile, INVALID_DIAGDIR); // start from depot inside
|
||||
@@ -704,8 +742,13 @@ void AddTrackToSignalBuffer(TileIndex tile, Track track, Owner owner)
|
||||
|
||||
_last_owner = owner;
|
||||
|
||||
_globset.Add(tile, _search_dir_1[track]);
|
||||
_globset.Add(tile, _search_dir_2[track]);
|
||||
DiagDirection wormhole_dir = IsTileType(tile, MP_TUNNELBRIDGE) ? GetTunnelBridgeDirection(tile) : INVALID_DIAGDIR;
|
||||
|
||||
auto add_dir = [&](DiagDirection dir) {
|
||||
_globset.Add(tile, dir == wormhole_dir ? INVALID_DIAGDIR : dir);
|
||||
};
|
||||
add_dir(_search_dir_1[track]);
|
||||
add_dir(_search_dir_2[track]);
|
||||
|
||||
if (_globset.Items() >= SIG_GLOB_UPDATE) {
|
||||
/* too many items, force update */
|
||||
|
@@ -1464,6 +1464,15 @@ str = STR_CONFIG_SETTING_ENABLE_ROAD_CUSTOM_BRIDGE_HEADS
|
||||
strhelp = STR_CONFIG_SETTING_ENABLE_ROAD_CUSTOM_BRIDGE_HEADS_HELPTEXT
|
||||
patxname = ""custom_bridge_heads.construction.road_custom_bridge_heads""
|
||||
|
||||
[SDT_BOOL]
|
||||
base = GameSettings
|
||||
var = construction.rail_custom_bridge_heads
|
||||
def = true
|
||||
cat = SC_BASIC
|
||||
str = STR_CONFIG_SETTING_ENABLE_RAIL_CUSTOM_BRIDGE_HEADS
|
||||
strhelp = STR_CONFIG_SETTING_ENABLE_RAIL_CUSTOM_BRIDGE_HEADS_HELPTEXT
|
||||
patxname = ""custom_bridge_heads.construction.rail_custom_bridge_heads""
|
||||
|
||||
[SDT_BOOL]
|
||||
base = GameSettings
|
||||
var = station.adjacent_stations
|
||||
|
@@ -308,7 +308,7 @@ protected: // These functions should not be called outside acceleration code.
|
||||
inline byte GetAirDragArea() const
|
||||
{
|
||||
/* Air drag is higher in tunnels due to the limited cross-section. */
|
||||
return (this->track == TRACK_BIT_WORMHOLE && this->vehstatus & VS_HIDDEN) ? 28 : 14;
|
||||
return (this->track & TRACK_BIT_WORMHOLE && this->vehstatus & VS_HIDDEN) ? 28 : 14;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@@ -591,7 +591,7 @@ int Train::GetCurrentMaxSpeed() const
|
||||
}
|
||||
|
||||
/* Vehicle is on the middle part of a bridge. */
|
||||
if (u->track == TRACK_BIT_WORMHOLE && !(u->vehstatus & VS_HIDDEN)) {
|
||||
if (u->track & TRACK_BIT_WORMHOLE && !(u->vehstatus & VS_HIDDEN)) {
|
||||
max_speed = min(max_speed, GetBridgeSpec(GetBridgeType(u->tile))->speed);
|
||||
}
|
||||
}
|
||||
@@ -1792,17 +1792,17 @@ static void UpdateStatusAfterSwap(Train *v)
|
||||
if (v->track != TRACK_BIT_DEPOT) v->direction = ReverseDir(v->direction);
|
||||
|
||||
/* Call the proper EnterTile function unless we are in a wormhole. */
|
||||
if (v->track != TRACK_BIT_WORMHOLE) {
|
||||
if (!(v->track & TRACK_BIT_WORMHOLE)) {
|
||||
VehicleEnterTile(v, v->tile, v->x_pos, v->y_pos);
|
||||
} else {
|
||||
/* VehicleEnter_TunnelBridge() sets TRACK_BIT_WORMHOLE when the vehicle
|
||||
/* VehicleEnter_TunnelBridge() may set TRACK_BIT_WORMHOLE when the vehicle
|
||||
* is on the last bit of the bridge head (frame == TILE_SIZE - 1).
|
||||
* If we were swapped with such a vehicle, we have set TRACK_BIT_WORMHOLE,
|
||||
* when we shouldn't have. Check if this is the case. */
|
||||
TileIndex vt = TileVirtXY(v->x_pos, v->y_pos);
|
||||
if (IsTileType(vt, MP_TUNNELBRIDGE)) {
|
||||
VehicleEnterTile(v, vt, v->x_pos, v->y_pos);
|
||||
if (v->track != TRACK_BIT_WORMHOLE && IsBridgeTile(v->tile)) {
|
||||
if (!(v->track & TRACK_BIT_WORMHOLE) && IsBridgeTile(v->tile)) {
|
||||
/* We have just left the wormhole, possibly set the
|
||||
* "goingdown" bit. UpdateInclination() can be used
|
||||
* because we are at the border of the tile. */
|
||||
@@ -1814,7 +1814,7 @@ static void UpdateStatusAfterSwap(Train *v)
|
||||
}
|
||||
|
||||
v->UpdatePosition();
|
||||
if (v->track == TRACK_BIT_WORMHOLE) v->UpdateInclination(false, false, true);
|
||||
if (v->track & TRACK_BIT_WORMHOLE) v->UpdateInclination(false, false, true);
|
||||
v->UpdateViewport(true, true);
|
||||
}
|
||||
|
||||
@@ -2182,7 +2182,7 @@ void ReverseTrainDirection(Train *v)
|
||||
}
|
||||
|
||||
/* We are inside tunnel/bridge with signals, reversing will close the entrance. */
|
||||
if (IsTunnelBridgeWithSignalSimulation(v->tile)) {
|
||||
if (IsTunnelBridgeWithSignalSimulation(v->tile) && IsTunnelBridgeSignalSimulationEntrance(v->tile)) {
|
||||
/* Flip signal on tunnel entrance tile red. */
|
||||
SetTunnelBridgeEntranceSignalState(v->tile, SIGNAL_STATE_RED);
|
||||
MarkTileDirtyByTile(v->tile);
|
||||
@@ -2195,7 +2195,7 @@ void ReverseTrainDirection(Train *v)
|
||||
/* VehicleExitDir does not always produce the desired dir for depots and
|
||||
* tunnels/bridges that is needed for UpdateSignalsOnSegment. */
|
||||
DiagDirection dir = VehicleExitDir(v->direction, v->track);
|
||||
if (IsRailDepotTile(v->tile) || IsTileType(v->tile, MP_TUNNELBRIDGE)) dir = INVALID_DIAGDIR;
|
||||
if (IsRailDepotTile(v->tile) || (IsTileType(v->tile, MP_TUNNELBRIDGE) && (v->track & TRACK_BIT_WORMHOLE || dir == GetTunnelBridgeDirection(v->tile)))) dir = INVALID_DIAGDIR;
|
||||
|
||||
if (UpdateSignalsOnSegment(v->tile, dir, v->owner) == SIGSEG_PBS || _settings_game.pf.reserve_paths) {
|
||||
/* If we are currently on a tile with conventional signals, we can't treat the
|
||||
@@ -2597,7 +2597,7 @@ static void HandleLastTunnelBridgeSignals(TileIndex tile, TileIndex end, DiagDir
|
||||
|
||||
static void UnreserveBridgeTunnelTile(TileIndex tile)
|
||||
{
|
||||
SetTunnelBridgeReservation(tile, false);
|
||||
UnreserveAcrossRailTunnelBridge(tile);
|
||||
if (IsTunnelBridgeSignalSimulationExit(tile) && IsTunnelBridgePBS(tile)) SetTunnelBridgeExitSignalState(tile, SIGNAL_STATE_RED);
|
||||
}
|
||||
|
||||
@@ -2610,27 +2610,36 @@ static void UnreserveBridgeTunnelTile(TileIndex tile)
|
||||
*/
|
||||
static void ClearPathReservation(const Train *v, TileIndex tile, Trackdir track_dir, bool tunbridge_clear_unsignaled_other_end = false)
|
||||
{
|
||||
DiagDirection dir = TrackdirToExitdir(track_dir);
|
||||
|
||||
if (IsTileType(tile, MP_TUNNELBRIDGE)) {
|
||||
TileIndex end = GetOtherTunnelBridgeEnd(tile);
|
||||
if (IsTrackAcrossTunnelBridge(tile, TrackdirToTrack(track_dir))) {
|
||||
UnreserveBridgeTunnelTile(tile);
|
||||
|
||||
if (IsTunnelBridgeWithSignalSimulation(tile)) {
|
||||
/* Are we just leaving a tunnel/bridge? */
|
||||
if (GetTunnelBridgeDirection(tile) == ReverseDiagDir(dir)) {
|
||||
bool free = TunnelBridgeIsFree(tile, end, v).Succeeded();
|
||||
HandleLastTunnelBridgeSignals(tile, end, dir, free);
|
||||
if (TrackdirExitsTunnelBridge(tile, track_dir)) {
|
||||
TileIndex end = GetOtherTunnelBridgeEnd(tile);
|
||||
bool free = TunnelBridgeIsFree(tile, end, v, true).Succeeded();
|
||||
HandleLastTunnelBridgeSignals(tile, end, ReverseDiagDir(GetTunnelBridgeDirection(tile)), free);
|
||||
}
|
||||
} else if (tunbridge_clear_unsignaled_other_end) {
|
||||
UnreserveBridgeTunnelTile(end);
|
||||
TileIndex end = GetOtherTunnelBridgeEnd(tile);
|
||||
UnreserveAcrossRailTunnelBridge(end);
|
||||
if (_settings_client.gui.show_track_reservation) {
|
||||
MarkTileDirtyByTile(end, ZOOM_LVL_DRAW_MAP);
|
||||
}
|
||||
}
|
||||
|
||||
if (_settings_client.gui.show_track_reservation) {
|
||||
MarkBridgeOrTunnelDirtyOnReservationChange(tile, ZOOM_LVL_DRAW_MAP);
|
||||
}
|
||||
} else {
|
||||
UnreserveRailTrack(tile, TrackdirToTrack(track_dir));
|
||||
if (_settings_client.gui.show_track_reservation) {
|
||||
MarkTileDirtyByTile(tile, ZOOM_LVL_DRAW_MAP);
|
||||
MarkTileDirtyByTile(end, ZOOM_LVL_DRAW_MAP);
|
||||
}
|
||||
}
|
||||
} else if (IsRailStationTile(tile)) {
|
||||
DiagDirection dir = TrackdirToExitdir(track_dir);
|
||||
TileIndex new_tile = TileAddByDiagDir(tile, dir);
|
||||
/* If the new tile is not a further tile of the same station, we
|
||||
* clear the reservation for the whole platform. */
|
||||
@@ -2696,11 +2705,10 @@ void FreeTrainTrackReservation(const Train *v, TileIndex origin, Trackdir orig_t
|
||||
} else if (HasSignalOnTrackdir(tile, ReverseTrackdir(td)) && IsOnewaySignal(tile, TrackdirToTrack(td))) {
|
||||
break;
|
||||
}
|
||||
} else if (IsTunnelBridgeWithSignalSimulation(tile)) {
|
||||
} else if (IsTunnelBridgeWithSignalSimulation(tile) && TrackdirExitsTunnelBridge(tile, td)) {
|
||||
TileIndex end = GetOtherTunnelBridgeEnd(tile);
|
||||
bool free = TunnelBridgeIsFree(tile, end, v).Succeeded();
|
||||
|
||||
if (!free && GetTunnelBridgeDirection(tile) == ReverseDiagDir(TrackdirToExitdir(td))) break;
|
||||
bool free = TunnelBridgeIsFree(tile, end, v, true).Succeeded();
|
||||
if (!free) break;
|
||||
}
|
||||
|
||||
/* Don't free first station/bridge/tunnel if we are on it. */
|
||||
@@ -3189,7 +3197,7 @@ bool TryPathReserve(Train *v, bool mark_as_stuck, bool first_tile_okay)
|
||||
}
|
||||
|
||||
if (IsTileType(v->tile, MP_TUNNELBRIDGE) && IsTunnelBridgeSignalSimulationExitOnly(v->tile) &&
|
||||
DiagDirToDiagTrackBits(GetTunnelBridgeDirection(v->tile)) == v->track) {
|
||||
(GetAcrossTunnelBridgeTrackBits(v->tile) & v->track)) {
|
||||
// prevent any attempt to reserve the wrong way onto a tunnel/bridge exit
|
||||
return false;
|
||||
}
|
||||
@@ -3246,7 +3254,7 @@ bool TryPathReserve(Train *v, bool mark_as_stuck, bool first_tile_okay)
|
||||
static bool CheckReverseTrain(const Train *v)
|
||||
{
|
||||
if (_settings_game.difficulty.line_reverse_mode != 0 ||
|
||||
v->track == TRACK_BIT_DEPOT || v->track == TRACK_BIT_WORMHOLE ||
|
||||
v->track == TRACK_BIT_DEPOT || v->track & TRACK_BIT_WORMHOLE ||
|
||||
!(v->direction & 1)) {
|
||||
return false;
|
||||
}
|
||||
@@ -3441,15 +3449,18 @@ static TrainMovedChangeSignalEnum TrainMovedChangeSignal(Train* v, TileIndex til
|
||||
void Train::ReserveTrackUnderConsist() const
|
||||
{
|
||||
for (const Train *u = this; u != NULL; u = u->Next()) {
|
||||
switch (u->track) {
|
||||
case TRACK_BIT_WORMHOLE:
|
||||
if (u->track & TRACK_BIT_WORMHOLE) {
|
||||
if (IsRailCustomBridgeHeadTile(u->tile)) {
|
||||
/* reserve the first available track */
|
||||
TrackBits bits = GetAcrossTunnelBridgeTrackBits(u->tile);
|
||||
Track first_track = RemoveFirstTrack(&bits);
|
||||
assert(IsValidTrack(first_track));
|
||||
TryReserveRailTrack(u->tile, first_track);
|
||||
} else {
|
||||
TryReserveRailTrack(u->tile, DiagDirToDiagTrack(GetTunnelBridgeDirection(u->tile)));
|
||||
break;
|
||||
case TRACK_BIT_DEPOT:
|
||||
break;
|
||||
default:
|
||||
}
|
||||
} else if (u->track != TRACK_BIT_DEPOT) {
|
||||
TryReserveRailTrack(u->tile, TrackBitsToTrack(u->track));
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -3578,14 +3589,14 @@ static bool CheckTrainCollision(Train *v)
|
||||
/* can't collide in depot */
|
||||
if (v->track == TRACK_BIT_DEPOT) return false;
|
||||
|
||||
assert(v->track == TRACK_BIT_WORMHOLE || TileVirtXY(v->x_pos, v->y_pos) == v->tile);
|
||||
assert(v->track & TRACK_BIT_WORMHOLE || TileVirtXY(v->x_pos, v->y_pos) == v->tile);
|
||||
|
||||
TrainCollideChecker tcc;
|
||||
tcc.v = v;
|
||||
tcc.num = 0;
|
||||
|
||||
/* find colliding vehicles */
|
||||
if (v->track == TRACK_BIT_WORMHOLE) {
|
||||
if (v->track & TRACK_BIT_WORMHOLE) {
|
||||
FindVehicleOnPos(v->tile, &tcc, FindTrainCollideEnum);
|
||||
FindVehicleOnPos(GetOtherTunnelBridgeEnd(v->tile), &tcc, FindTrainCollideEnum);
|
||||
} else {
|
||||
@@ -3621,7 +3632,7 @@ static Vehicle *CheckTrainAtSignal(Vehicle *v, void *data)
|
||||
struct FindSpaceBetweenTrainsChecker {
|
||||
int32 pos;
|
||||
uint16 distance;
|
||||
DirectionByte direction;
|
||||
DiagDirectionByte direction;
|
||||
};
|
||||
|
||||
/** Find train in front and keep distance between trains in tunnel/bridge. */
|
||||
@@ -3630,15 +3641,20 @@ static Vehicle *FindSpaceBetweenTrainsEnum(Vehicle *v, void *data)
|
||||
/* Don't look at wagons between front and back of train. */
|
||||
if (v->type != VEH_TRAIN || (v->Previous() != NULL && v->Next() != NULL)) return NULL;
|
||||
|
||||
if (!IsDiagonalDirection(v->direction)) {
|
||||
/* Check for vehicles on non-across track pieces of custom bridge head */
|
||||
if ((GetAcrossTunnelBridgeTrackBits(v->tile) & Train::From(v)->track & TRACK_BIT_ALL) == TRACK_BIT_NONE) return NULL;
|
||||
}
|
||||
|
||||
const FindSpaceBetweenTrainsChecker *checker = (FindSpaceBetweenTrainsChecker*) data;
|
||||
int32 a, b = 0;
|
||||
|
||||
switch (checker->direction) {
|
||||
default: NOT_REACHED();
|
||||
case DIR_NE: a = checker->pos; b = v->x_pos; break;
|
||||
case DIR_SE: a = v->y_pos; b = checker->pos; break;
|
||||
case DIR_SW: a = v->x_pos; b = checker->pos; break;
|
||||
case DIR_NW: a = checker->pos; b = v->y_pos; break;
|
||||
case DIAGDIR_NE: a = checker->pos; b = v->x_pos; break;
|
||||
case DIAGDIR_SE: a = v->y_pos; b = checker->pos; break;
|
||||
case DIAGDIR_SW: a = v->x_pos; b = checker->pos; break;
|
||||
case DIAGDIR_NW: a = checker->pos; b = v->y_pos; break;
|
||||
}
|
||||
|
||||
if (a > b && a <= (b + (int)(checker->distance)) + (int)(TILE_SIZE) - 1) return v;
|
||||
@@ -3653,18 +3669,18 @@ static bool IsTooCloseBehindTrain(Vehicle *v, TileIndex tile, uint16 distance, b
|
||||
|
||||
FindSpaceBetweenTrainsChecker checker;
|
||||
checker.distance = distance;
|
||||
checker.direction = t->direction;
|
||||
checker.direction = DirToDiagDirAlongAxis(t->direction, DiagDirToAxis(GetTunnelBridgeDirection(t->tile)));
|
||||
switch (checker.direction) {
|
||||
default: NOT_REACHED();
|
||||
case DIR_NE: checker.pos = (TileX(tile) * TILE_SIZE) + TILE_UNIT_MASK; break;
|
||||
case DIR_SE: checker.pos = (TileY(tile) * TILE_SIZE); break;
|
||||
case DIR_SW: checker.pos = (TileX(tile) * TILE_SIZE); break;
|
||||
case DIR_NW: checker.pos = (TileY(tile) * TILE_SIZE) + TILE_UNIT_MASK; break;
|
||||
case DIAGDIR_NE: checker.pos = (TileX(tile) * TILE_SIZE) + TILE_UNIT_MASK; break;
|
||||
case DIAGDIR_SE: checker.pos = (TileY(tile) * TILE_SIZE); break;
|
||||
case DIAGDIR_SW: checker.pos = (TileX(tile) * TILE_SIZE); break;
|
||||
case DIAGDIR_NW: checker.pos = (TileY(tile) * TILE_SIZE) + TILE_UNIT_MASK; break;
|
||||
}
|
||||
|
||||
if (HasVehicleOnPos(t->tile, &checker, &FindSpaceBetweenTrainsEnum)) {
|
||||
/* Revert train if not going with tunnel direction. */
|
||||
if (DirToDiagDir(t->direction) != GetTunnelBridgeDirection(t->tile)) {
|
||||
if (checker.direction != GetTunnelBridgeDirection(t->tile)) {
|
||||
SetBit(t->flags, VRF_REVERSING);
|
||||
}
|
||||
return true;
|
||||
@@ -3673,7 +3689,7 @@ static bool IsTooCloseBehindTrain(Vehicle *v, TileIndex tile, uint16 distance, b
|
||||
if (check_endtile){
|
||||
if (HasVehicleOnPos(GetOtherTunnelBridgeEnd(t->tile), &checker, &FindSpaceBetweenTrainsEnum)) {
|
||||
/* Revert train if not going with tunnel direction. */
|
||||
if (DirToDiagDir(t->direction) != GetTunnelBridgeDirection(t->tile)) {
|
||||
if (checker.direction != GetTunnelBridgeDirection(t->tile)) {
|
||||
SetBit(t->flags, VRF_REVERSING);
|
||||
}
|
||||
return true;
|
||||
@@ -3685,19 +3701,30 @@ static bool IsTooCloseBehindTrain(Vehicle *v, TileIndex tile, uint16 distance, b
|
||||
|
||||
static bool CheckTrainStayInWormHolePathReserve(Train *t, TileIndex tile)
|
||||
{
|
||||
TileIndex veh_orig = t->tile;
|
||||
Trackdir td = TrackEnterdirToTrackdir(FindFirstTrack(GetAcrossTunnelBridgeTrackBits(tile)), ReverseDiagDir(GetTunnelBridgeDirection(tile)));
|
||||
TileIndex veh_orig_tile = t->tile;
|
||||
TrackBits veh_orig_track = t->track;
|
||||
Direction veh_orig_direction = t->direction;
|
||||
t->tile = tile;
|
||||
t->track = TRACK_BIT_WORMHOLE;
|
||||
t->direction = TrackdirToDirection(td);
|
||||
CFollowTrackRail ft(GetTileOwner(tile), GetRailTypeInfo(t->railtype)->compatible_railtypes);
|
||||
if (ft.Follow(tile, DiagDirToDiagTrackdir(ReverseDiagDir(GetTunnelBridgeDirection(tile))))) {
|
||||
if (ft.Follow(tile, td)) {
|
||||
TrackdirBits reserved = ft.m_new_td_bits & TrackBitsToTrackdirBits(GetReservedTrackbits(ft.m_new_tile));
|
||||
if (reserved == TRACKDIR_BIT_NONE) {
|
||||
/* next tile is not reserved, so reserve the exit tile */
|
||||
SetTunnelBridgeReservation(tile, true);
|
||||
if (IsBridge(tile)) {
|
||||
TryReserveRailBridgeHead(tile, FindFirstTrack(GetAcrossTunnelBridgeTrackBits(tile)));
|
||||
} else {
|
||||
SetTunnelReservation(tile, true);
|
||||
}
|
||||
MarkTileDirtyByTile(tile, ZOOM_LVL_DRAW_MAP);
|
||||
}
|
||||
}
|
||||
bool ok = TryPathReserve(t);
|
||||
t->tile = veh_orig;
|
||||
t->tile = veh_orig_tile;
|
||||
t->track = veh_orig_track;
|
||||
t->direction = veh_orig_direction;
|
||||
if (ok && IsTunnelBridgePBS(tile)) SetTunnelBridgeExitSignalState(tile, SIGNAL_STATE_GREEN);
|
||||
return ok;
|
||||
}
|
||||
@@ -3715,7 +3742,7 @@ static bool CheckTrainStayInWormHole(Train *t, TileIndex tile)
|
||||
SigSegState seg_state = (_settings_game.pf.reserve_paths || IsTunnelBridgePBS(tile)) ? SIGSEG_PBS : UpdateSignalsOnSegment(tile, INVALID_DIAGDIR, t->owner);
|
||||
if (seg_state != SIGSEG_PBS) {
|
||||
CFollowTrackRail ft(GetTileOwner(tile), GetRailTypeInfo(t->railtype)->compatible_railtypes);
|
||||
if (ft.Follow(tile, DiagDirToDiagTrackdir(ReverseDiagDir(GetTunnelBridgeDirection(tile))))) {
|
||||
if (ft.Follow(tile, TrackEnterdirToTrackdir(FindFirstTrack(GetAcrossTunnelBridgeTrackBits(tile)), ReverseDiagDir(GetTunnelBridgeDirection(tile))))) {
|
||||
if (ft.m_new_td_bits != TRACKDIR_BIT_NONE && KillFirstBit(ft.m_new_td_bits) == TRACKDIR_BIT_NONE) {
|
||||
Trackdir td = FindFirstTrackdir(ft.m_new_td_bits);
|
||||
if (HasPbsSignalOnTrackdir(ft.m_new_tile, td)) {
|
||||
@@ -3779,6 +3806,18 @@ bool TrainController(Train *v, Vehicle *nomove, bool reverse)
|
||||
Train *first = v->First();
|
||||
Train *prev;
|
||||
bool direction_changed = false; // has direction of any part changed?
|
||||
bool update_signal_tunbridge_exit = false;
|
||||
Direction old_direction = INVALID_DIR;
|
||||
TrackBits old_trackbits = INVALID_TRACK_BIT;
|
||||
|
||||
auto notify_direction_changed = [&](Direction old_direction, Direction new_direction) {
|
||||
if (prev == NULL && _settings_game.vehicle.train_acceleration_model == AM_ORIGINAL) {
|
||||
const AccelerationSlowdownParams *asp = &_accel_slowdown[GetRailTypeInfo(v->railtype)->acceleration_type];
|
||||
DirDiff diff = DirDifference(old_direction, new_direction);
|
||||
v->cur_speed -= (diff == DIRDIFF_45RIGHT || diff == DIRDIFF_45LEFT ? asp->small_turn : asp->large_turn) * v->cur_speed >> 8;
|
||||
}
|
||||
direction_changed = true;
|
||||
};
|
||||
|
||||
if (reverse && v->reverse_distance == 1) {
|
||||
goto reverse_train_direction;
|
||||
@@ -3791,11 +3830,24 @@ bool TrainController(Train *v, Vehicle *nomove, bool reverse)
|
||||
|
||||
/* For every vehicle after and including the given vehicle */
|
||||
for (prev = v->Previous(); v != nomove; prev = v, v = v->Next()) {
|
||||
old_direction = v->direction;
|
||||
old_trackbits = v->track;
|
||||
DiagDirection enterdir = DIAGDIR_BEGIN;
|
||||
bool update_signals_crossing = false; // will we update signals or crossing state?
|
||||
|
||||
|
||||
GetNewVehiclePosResult gp = GetNewVehiclePos(v);
|
||||
if (v->track != TRACK_BIT_WORMHOLE) {
|
||||
if (!(v->track & TRACK_BIT_WORMHOLE) && gp.old_tile != gp.new_tile &&
|
||||
IsRailBridgeHeadTile(gp.old_tile) && DiagdirBetweenTiles(gp.old_tile, gp.new_tile) == GetTunnelBridgeDirection(gp.old_tile)) {
|
||||
/* left a bridge headtile into a wormhole */
|
||||
Direction old_direction = v->direction;
|
||||
uint32 r = VehicleEnterTile(v, gp.old_tile, gp.x, gp.y); // NB: old tile, the bridge head which the train just left
|
||||
if (HasBit(r, VETS_CANNOT_ENTER)) {
|
||||
goto invalid_rail;
|
||||
}
|
||||
if (old_direction != v->direction) notify_direction_changed(old_direction, v->direction);
|
||||
}
|
||||
if (!(v->track & TRACK_BIT_WORMHOLE)) {
|
||||
/* Not inside tunnel */
|
||||
if (gp.old_tile == gp.new_tile) {
|
||||
/* Staying in the old tile */
|
||||
@@ -3818,6 +3870,7 @@ bool TrainController(Train *v, Vehicle *nomove, bool reverse)
|
||||
/* The new position is the end of the platform */
|
||||
TrainEnterStation(v->First(), r >> VETS_STATION_ID_OFFSET);
|
||||
}
|
||||
if (old_direction != v->direction) notify_direction_changed(old_direction, v->direction);
|
||||
}
|
||||
} else {
|
||||
/* A new tile is about to be entered. */
|
||||
@@ -3826,9 +3879,11 @@ bool TrainController(Train *v, Vehicle *nomove, bool reverse)
|
||||
enterdir = DiagdirBetweenTiles(gp.old_tile, gp.new_tile);
|
||||
assert(IsValidDiagDirection(enterdir));
|
||||
|
||||
enter_new_tile:
|
||||
|
||||
/* Get the status of the tracks in the new tile and mask
|
||||
* away the bits that aren't reachable. */
|
||||
TrackStatus ts = GetTileTrackStatus(gp.new_tile, TRANSPORT_RAIL, 0, ReverseDiagDir(enterdir));
|
||||
TrackStatus ts = GetTileTrackStatus(gp.new_tile, TRANSPORT_RAIL, 0, (v->track & TRACK_BIT_WORMHOLE) ? INVALID_DIAGDIR : ReverseDiagDir(enterdir));
|
||||
TrackdirBits reachable_trackdirs = DiagdirReachesTrackdirs(enterdir);
|
||||
|
||||
TrackdirBits trackdirbits = TrackStatusToTrackdirBits(ts) & reachable_trackdirs;
|
||||
@@ -3838,7 +3893,11 @@ bool TrainController(Train *v, Vehicle *nomove, bool reverse)
|
||||
if (_settings_game.pf.forbid_90_deg && prev == NULL) {
|
||||
/* We allow wagons to make 90 deg turns, because forbid_90_deg
|
||||
* can be switched on halfway a turn */
|
||||
if (!(v->track & TRACK_BIT_WORMHOLE)) {
|
||||
bits &= ~TrackCrossesTracks(FindFirstTrack(v->track));
|
||||
} else if (v->track & TRACK_BIT_MASK) {
|
||||
bits &= ~TrackCrossesTracks(FindFirstTrack(v->track & TRACK_BIT_MASK));
|
||||
}
|
||||
}
|
||||
|
||||
if (bits == TRACK_BIT_NONE) goto invalid_rail;
|
||||
@@ -3926,9 +3985,9 @@ bool TrainController(Train *v, Vehicle *nomove, bool reverse)
|
||||
}
|
||||
} else {
|
||||
/* The wagon is active, simply follow the prev vehicle. */
|
||||
if (prev->tile == gp.new_tile) {
|
||||
if (TileVirtXY(prev->x_pos, prev->y_pos) == gp.new_tile) {
|
||||
/* Choose the same track as prev */
|
||||
if (prev->track == TRACK_BIT_WORMHOLE) {
|
||||
if (prev->track & TRACK_BIT_WORMHOLE) {
|
||||
/* Vehicles entering tunnels enter the wormhole earlier than for bridges.
|
||||
* However, just choose the track into the wormhole. */
|
||||
assert(IsTunnel(prev->tile));
|
||||
@@ -3950,7 +4009,7 @@ bool TrainController(Train *v, Vehicle *nomove, bool reverse)
|
||||
{TRACK_BIT_NONE, TRACK_BIT_RIGHT, TRACK_BIT_X, TRACK_BIT_UPPER},
|
||||
{TRACK_BIT_RIGHT, TRACK_BIT_NONE, TRACK_BIT_LOWER, TRACK_BIT_Y }
|
||||
};
|
||||
DiagDirection exitdir = DiagdirBetweenTiles(gp.new_tile, prev->tile);
|
||||
DiagDirection exitdir = DiagdirBetweenTiles(gp.new_tile, TileVirtXY(prev->x_pos, prev->y_pos));
|
||||
assert(IsValidDiagDirection(exitdir));
|
||||
chosen_track = _connecting_track[enterdir][exitdir];
|
||||
}
|
||||
@@ -3970,12 +4029,12 @@ bool TrainController(Train *v, Vehicle *nomove, bool reverse)
|
||||
Direction chosen_dir = (Direction)b[2];
|
||||
|
||||
/* Call the landscape function and tell it that the vehicle entered the tile */
|
||||
uint32 r = VehicleEnterTile(v, gp.new_tile, gp.x, gp.y);
|
||||
uint32 r = (v->track & TRACK_BIT_WORMHOLE) ? 0 : VehicleEnterTile(v, gp.new_tile, gp.x, gp.y);
|
||||
if (HasBit(r, VETS_CANNOT_ENTER)) {
|
||||
goto invalid_rail;
|
||||
}
|
||||
|
||||
if (IsTunnelBridgeWithSignalSimulation(gp.new_tile)) {
|
||||
if (!(v->track & TRACK_BIT_WORMHOLE) && IsTunnelBridgeWithSignalSimulation(gp.new_tile) && (GetAcrossTunnelBridgeTrackBits(gp.new_tile) & chosen_track)) {
|
||||
/* If red signal stop. */
|
||||
if (v->IsFrontEngine() && v->force_proceed == 0) {
|
||||
if (IsTunnelBridgeSignalSimulationEntrance(gp.new_tile) && GetTunnelBridgeEntranceSignalState(gp.new_tile) == SIGNAL_STATE_RED) {
|
||||
@@ -4008,7 +4067,7 @@ bool TrainController(Train *v, Vehicle *nomove, bool reverse)
|
||||
}
|
||||
|
||||
/* Clear any track reservation when the last vehicle leaves the tile */
|
||||
if (v->Next() == NULL) ClearPathReservation(v, v->tile, v->GetVehicleTrackdir(), true);
|
||||
if (v->Next() == NULL && !(v->track & TRACK_BIT_WORMHOLE)) ClearPathReservation(v, v->tile, v->GetVehicleTrackdir(), true);
|
||||
|
||||
v->tile = gp.new_tile;
|
||||
|
||||
@@ -4025,12 +4084,7 @@ bool TrainController(Train *v, Vehicle *nomove, bool reverse)
|
||||
update_signals_crossing = true;
|
||||
|
||||
if (chosen_dir != v->direction) {
|
||||
if (prev == NULL && _settings_game.vehicle.train_acceleration_model == AM_ORIGINAL) {
|
||||
const AccelerationSlowdownParams *asp = &_accel_slowdown[GetRailTypeInfo(v->railtype)->acceleration_type];
|
||||
DirDiff diff = DirDifference(v->direction, chosen_dir);
|
||||
v->cur_speed -= (diff == DIRDIFF_45RIGHT || diff == DIRDIFF_45LEFT ? asp->small_turn : asp->large_turn) * v->cur_speed >> 8;
|
||||
}
|
||||
direction_changed = true;
|
||||
notify_direction_changed(v->direction, chosen_dir);
|
||||
v->direction = chosen_dir;
|
||||
}
|
||||
|
||||
@@ -4106,19 +4160,16 @@ bool TrainController(Train *v, Vehicle *nomove, bool reverse)
|
||||
v->force_proceed = 0;
|
||||
v->wait_counter = 0;
|
||||
v->tunnel_bridge_signal_num = 0;
|
||||
v->x_pos = gp.x;
|
||||
v->y_pos = gp.y;
|
||||
v->UpdatePosition();
|
||||
v->UpdateViewport(false, false);
|
||||
UpdateSignalsOnSegment(gp.new_tile, INVALID_DIAGDIR, v->owner);
|
||||
continue;
|
||||
update_signal_tunbridge_exit = true;
|
||||
}
|
||||
}
|
||||
if (old_tile == gp.new_tile && IsTunnelBridgeWithSignalSimulation(v->tile) && v->IsFrontEngine()) {
|
||||
TileIndex next_tile = old_tile + TileOffsByDir(v->direction);
|
||||
Axis axis = DiagDirToAxis(GetTunnelBridgeDirection(v->tile));
|
||||
DiagDirection axial_dir = DirToDiagDirAlongAxis(v->direction, axis);
|
||||
TileIndex next_tile = old_tile + TileOffsByDiagDir(axial_dir);
|
||||
bool is_exit = false;
|
||||
if (IsTileType(next_tile, MP_TUNNELBRIDGE) && IsTunnelBridgeWithSignalSimulation(next_tile) &&
|
||||
ReverseDiagDir(GetTunnelBridgeDirection(next_tile)) == DirToDiagDir(v->direction)) {
|
||||
ReverseDiagDir(GetTunnelBridgeDirection(next_tile)) == axial_dir) {
|
||||
if (IsBridge(next_tile) && IsBridge(v->tile)) {
|
||||
// bridge ramp facing towards us
|
||||
is_exit = true;
|
||||
@@ -4140,6 +4191,10 @@ bool TrainController(Train *v, Vehicle *nomove, bool reverse)
|
||||
|
||||
if (IsTileType(gp.new_tile, MP_TUNNELBRIDGE) && HasBit(VehicleEnterTile(v, gp.new_tile, gp.x, gp.y), VETS_ENTERED_WORMHOLE)) {
|
||||
/* Perform look-ahead on tunnel exit. */
|
||||
if (IsRailCustomBridgeHeadTile(gp.new_tile)) {
|
||||
enterdir = ReverseDiagDir(GetTunnelBridgeDirection(gp.new_tile));
|
||||
goto enter_new_tile;
|
||||
}
|
||||
if (v->IsFrontEngine()) {
|
||||
TryReserveRailTrack(gp.new_tile, DiagDirToDiagTrack(GetTunnelBridgeDirection(gp.new_tile)));
|
||||
CheckNextTrainTile(v);
|
||||
@@ -4163,6 +4218,10 @@ bool TrainController(Train *v, Vehicle *nomove, bool reverse)
|
||||
}
|
||||
}
|
||||
if (v->IsDrawn()) v->Vehicle::UpdateViewport(true);
|
||||
if (update_signal_tunbridge_exit) {
|
||||
UpdateSignalsOnSegment(gp.new_tile, INVALID_DIAGDIR, v->owner);
|
||||
update_signal_tunbridge_exit = false;
|
||||
}
|
||||
continue;
|
||||
}
|
||||
}
|
||||
@@ -4185,6 +4244,11 @@ bool TrainController(Train *v, Vehicle *nomove, bool reverse)
|
||||
AffectSpeedByZChange(v, old_z);
|
||||
}
|
||||
|
||||
if (update_signal_tunbridge_exit) {
|
||||
UpdateSignalsOnSegment(gp.new_tile, INVALID_DIAGDIR, v->owner);
|
||||
update_signal_tunbridge_exit = false;
|
||||
}
|
||||
|
||||
if (update_signals_crossing) {
|
||||
if (v->IsFrontEngine()) {
|
||||
switch (TrainMovedChangeSignal(v, gp.new_tile, enterdir)) {
|
||||
@@ -4264,6 +4328,11 @@ invalid_rail:
|
||||
if (prev != NULL) error("Disconnecting train");
|
||||
|
||||
reverse_train_direction:
|
||||
if (old_trackbits != INVALID_TRACK_BIT && (v->track ^ old_trackbits) & TRACK_BIT_WORMHOLE) {
|
||||
/* Entering/exiting wormhole failed/aborted, back out changes to vehicle direction and track */
|
||||
v->track = old_trackbits;
|
||||
v->direction = old_direction;
|
||||
}
|
||||
if (reverse) {
|
||||
v->wait_counter = 0;
|
||||
v->cur_speed = 0;
|
||||
@@ -4274,6 +4343,21 @@ reverse_train_direction:
|
||||
return false;
|
||||
}
|
||||
|
||||
static TrackBits GetTrackbitsFromCrashedVehicle(Train *t)
|
||||
{
|
||||
TrackBits train_tbits = t->track;
|
||||
if (train_tbits & TRACK_BIT_WORMHOLE) {
|
||||
/* Vehicle is inside a wormhole, v->track contains no useful value then. */
|
||||
train_tbits = GetAcrossTunnelBridgeReservationTrackBits(t->tile);
|
||||
if (train_tbits != TRACK_BIT_NONE) return train_tbits;
|
||||
/* Pick the first available tunnel/bridge head track which could be reserved */
|
||||
train_tbits = GetAcrossTunnelBridgeTrackBits(t->tile);
|
||||
return train_tbits ^ KillFirstBit(train_tbits);
|
||||
} else {
|
||||
return train_tbits;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Collect trackbits of all crashed train vehicles on a tile
|
||||
* @param v Vehicle passed from Find/HasVehicleOnPos()
|
||||
@@ -4285,18 +4369,34 @@ static Vehicle *CollectTrackbitsFromCrashedVehiclesEnum(Vehicle *v, void *data)
|
||||
TrackBits *trackbits = (TrackBits *)data;
|
||||
|
||||
if (v->type == VEH_TRAIN && (v->vehstatus & VS_CRASHED) != 0) {
|
||||
TrackBits train_tbits = Train::From(v)->track;
|
||||
if (train_tbits == TRACK_BIT_WORMHOLE) {
|
||||
/* Vehicle is inside a wormhole, v->track contains no useful value then. */
|
||||
*trackbits |= DiagDirToDiagTrackBits(GetTunnelBridgeDirection(v->tile));
|
||||
} else if (train_tbits != TRACK_BIT_DEPOT) {
|
||||
*trackbits |= train_tbits;
|
||||
if (Train::From(v)->track != TRACK_BIT_DEPOT) {
|
||||
*trackbits |= GetTrackbitsFromCrashedVehicle(Train::From(v));
|
||||
}
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static void SetSignalledBridgeTunnelGreenIfClear(TileIndex tile, TileIndex end)
|
||||
{
|
||||
if (TunnelBridgeIsFree(tile, end, nullptr, true).Succeeded()) {
|
||||
auto process_tile = [](TileIndex t) {
|
||||
if (IsTunnelBridgeSignalSimulationEntrance(t)) {
|
||||
if (IsBridge(t)) {
|
||||
SetAllBridgeEntranceSimulatedSignalsGreen(t);
|
||||
MarkBridgeDirty(t, ZOOM_LVL_DRAW_MAP);
|
||||
}
|
||||
if (IsTunnelBridgeSignalSimulationEntrance(t) && GetTunnelBridgeEntranceSignalState(t) == SIGNAL_STATE_RED) {
|
||||
SetTunnelBridgeEntranceSignalState(t, SIGNAL_STATE_GREEN);
|
||||
MarkTileDirtyByTile(t, ZOOM_LVL_DRAW_MAP);
|
||||
}
|
||||
}
|
||||
};
|
||||
process_tile(tile);
|
||||
process_tile(end);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Deletes/Clears the last wagon of a crashed train. It takes the engine of the
|
||||
* train, then goes to the last wagon and deletes that. Each call to this function
|
||||
@@ -4327,18 +4427,14 @@ static void DeleteLastWagon(Train *v)
|
||||
}
|
||||
|
||||
/* 'v' shouldn't be accessed after it has been deleted */
|
||||
TrackBits trackbits = v->track;
|
||||
TileIndex tile = v->tile;
|
||||
Owner owner = v->owner;
|
||||
const TrackBits orig_trackbits = v->track;
|
||||
TrackBits trackbits = GetTrackbitsFromCrashedVehicle(v);
|
||||
const TileIndex tile = v->tile;
|
||||
const Owner owner = v->owner;
|
||||
|
||||
delete v;
|
||||
v = NULL; // make sure nobody will try to read 'v' anymore
|
||||
|
||||
if (trackbits == TRACK_BIT_WORMHOLE) {
|
||||
/* Vehicle is inside a wormhole, v->track contains no useful value then. */
|
||||
trackbits = DiagDirToDiagTrackBits(GetTunnelBridgeDirection(tile));
|
||||
}
|
||||
|
||||
Track track = TrackBitsToTrack(trackbits);
|
||||
if (HasReservedTracks(tile, trackbits)) {
|
||||
UnreserveRailTrack(tile, track);
|
||||
@@ -4357,29 +4453,12 @@ static void DeleteLastWagon(Train *v)
|
||||
if (IsLevelCrossingTile(tile)) UpdateLevelCrossing(tile);
|
||||
|
||||
/* Update signals */
|
||||
if (IsTileType(tile, MP_TUNNELBRIDGE)) {
|
||||
UpdateSignalsOnSegment(tile, INVALID_DIAGDIR, owner);
|
||||
if (IsTunnelBridgeWithSignalSimulation(tile)) {
|
||||
TileIndex end = GetOtherTunnelBridgeEnd(tile);
|
||||
UpdateSignalsOnSegment(end, INVALID_DIAGDIR, owner);
|
||||
if (TunnelBridgeIsFree(tile, end, nullptr).Succeeded()) {
|
||||
auto process_tile = [](TileIndex t) {
|
||||
if (IsTunnelBridgeSignalSimulationEntrance(t)) {
|
||||
if (IsBridge(t)) {
|
||||
SetAllBridgeEntranceSimulatedSignalsGreen(t);
|
||||
MarkBridgeDirty(t, ZOOM_LVL_DRAW_MAP);
|
||||
SetSignalledBridgeTunnelGreenIfClear(tile, end);
|
||||
}
|
||||
if (IsTunnelBridgeSignalSimulationEntrance(t) && GetTunnelBridgeEntranceSignalState(t) == SIGNAL_STATE_RED) {
|
||||
SetTunnelBridgeEntranceSignalState(t, SIGNAL_STATE_GREEN);
|
||||
MarkTileDirtyByTile(t, ZOOM_LVL_DRAW_MAP);
|
||||
}
|
||||
}
|
||||
};
|
||||
process_tile(tile);
|
||||
process_tile(end);
|
||||
}
|
||||
}
|
||||
} else if (IsRailDepotTile(tile)) {
|
||||
if ((orig_trackbits & TRACK_BIT_WORMHOLE) || IsRailDepotTile(tile)) {
|
||||
UpdateSignalsOnSegment(tile, INVALID_DIAGDIR, owner);
|
||||
} else {
|
||||
SetSignalsOnBothDir(tile, track, owner);
|
||||
@@ -4403,7 +4482,7 @@ static void ChangeTrainDirRandomly(Train *v)
|
||||
/* Refrain from updating the z position of the vehicle when on
|
||||
* a bridge, because UpdateInclination() will put the vehicle under
|
||||
* the bridge in that case */
|
||||
if (v->track != TRACK_BIT_WORMHOLE) {
|
||||
if (!(v->track & TRACK_BIT_WORMHOLE)) {
|
||||
v->UpdatePosition();
|
||||
v->UpdateInclination(false, true);
|
||||
} else {
|
||||
@@ -4518,7 +4597,7 @@ static bool TrainApproachingLineEnd(Train *v, bool signal, bool reverse)
|
||||
static bool TrainCanLeaveTile(const Train *v)
|
||||
{
|
||||
/* Exit if inside a tunnel/bridge or a depot */
|
||||
if (v->track == TRACK_BIT_WORMHOLE || v->track == TRACK_BIT_DEPOT) return false;
|
||||
if (v->track & TRACK_BIT_WORMHOLE || v->track == TRACK_BIT_DEPOT) return false;
|
||||
|
||||
TileIndex tile = v->tile;
|
||||
|
||||
@@ -4526,6 +4605,13 @@ static bool TrainCanLeaveTile(const Train *v)
|
||||
if (IsTileType(tile, MP_TUNNELBRIDGE)) {
|
||||
DiagDirection dir = GetTunnelBridgeDirection(tile);
|
||||
if (DiagDirToDir(dir) == v->direction) return false;
|
||||
if (IsRailCustomBridgeHeadTile(tile) && VehicleExitDir(v->direction, v->track) == dir) {
|
||||
if (_settings_game.pf.forbid_90_deg && v->Previous() == NULL && GetTunnelBridgeLength(tile, GetOtherTunnelBridgeEnd(tile)) == 0) {
|
||||
/* Check for 90 degree turn on zero-length bridge span */
|
||||
if (!(GetCustomBridgeHeadTrackBits(tile) & ~TrackCrossesTracks(FindFirstTrack(v->track)))) return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/* entering a depot? */
|
||||
@@ -4926,7 +5012,13 @@ Trackdir Train::GetVehicleTrackdir() const
|
||||
|
||||
if (this->track == TRACK_BIT_WORMHOLE) {
|
||||
/* train in tunnel or on bridge, so just use his direction and assume a diagonal track */
|
||||
return DiagDirToDiagTrackdir(DirToDiagDir(this->direction));
|
||||
TrackBits tracks = GetAcrossTunnelBridgeReservationTrackBits(this->tile);
|
||||
if (!tracks) tracks = GetAcrossTunnelBridgeTrackBits(this->tile);
|
||||
Trackdir td = TrackExitdirToTrackdir(FindFirstTrack(tracks), GetTunnelBridgeDirection(this->tile));
|
||||
if (GetTunnelBridgeDirection(this->tile) != DirToDiagDir(this->direction)) td = ReverseTrackdir(td);
|
||||
return td;
|
||||
} else if (this->track & TRACK_BIT_WORMHOLE) {
|
||||
return TrackDirectionToTrackdir(FindFirstTrack(this->track & TRACK_BIT_MASK), this->direction);
|
||||
}
|
||||
|
||||
return TrackDirectionToTrackdir(FindFirstTrack(this->track), this->direction);
|
||||
@@ -4957,23 +5049,28 @@ void DeleteVisibleTrain(Train *v)
|
||||
/* 'u' shouldn't be accessed after it has been deleted */
|
||||
TileIndex tile = u->tile;
|
||||
TrackBits trackbits = u->track;
|
||||
bool in_wormhole = trackbits & TRACK_BIT_WORMHOLE;
|
||||
|
||||
delete u;
|
||||
|
||||
if (trackbits == TRACK_BIT_WORMHOLE) {
|
||||
if (in_wormhole) {
|
||||
/* Vehicle is inside a wormhole, u->track contains no useful value then. */
|
||||
trackbits = DiagDirToDiagTrackBits(GetTunnelBridgeDirection(tile));
|
||||
if (IsTunnelBridgeWithSignalSimulation(tile)) {
|
||||
TileIndex end = GetOtherTunnelBridgeEnd(tile);
|
||||
UpdateSignalsOnSegment(end, INVALID_DIAGDIR, GetTileOwner(tile));
|
||||
SetSignalledBridgeTunnelGreenIfClear(tile, end);
|
||||
}
|
||||
|
||||
} else {
|
||||
Track track = TrackBitsToTrack(trackbits);
|
||||
if (HasReservedTracks(tile, trackbits)) UnreserveRailTrack(tile, track);
|
||||
if (IsLevelCrossingTile(tile)) UpdateLevelCrossing(tile);
|
||||
}
|
||||
|
||||
/* Update signals */
|
||||
if (IsTileType(tile, MP_TUNNELBRIDGE) || IsRailDepotTile(tile)) {
|
||||
if (in_wormhole || IsRailDepotTile(tile)) {
|
||||
AddSideToSignalBuffer(tile, INVALID_DIAGDIR, GetTileOwner(tile));
|
||||
} else {
|
||||
AddTrackToSignalBuffer(tile, track, GetTileOwner(tile));
|
||||
AddTrackToSignalBuffer(tile, TrackBitsToTrack(trackbits), GetTileOwner(tile));
|
||||
}
|
||||
} while (prev != NULL);
|
||||
|
||||
|
@@ -55,6 +55,40 @@ static inline TunnelID GetTunnelIndex(TileIndex t)
|
||||
return map_id == TUNNEL_ID_MAP_LOOKUP ? GetTunnelIndexByLookup(t) : map_id;
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if this tile is a rail tunnel
|
||||
* @param t the tile that might be a rail tunnel
|
||||
* @return true if it is a rail tunnel
|
||||
*/
|
||||
static inline bool IsRailTunnelTile(TileIndex t)
|
||||
{
|
||||
return IsTunnelTile(t) && (TransportType)GB(_m[t].m5, 2, 2) == TRANSPORT_RAIL;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the reservation state of the rail tunnel
|
||||
* @pre IsRailTunnelTile(t)
|
||||
* @param t the tile
|
||||
* @return reservation state
|
||||
*/
|
||||
static inline bool HasTunnelReservation(TileIndex t)
|
||||
{
|
||||
assert(IsRailTunnelTile(t));
|
||||
return HasBit(_m[t].m5, 4);
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the reservation state of the rail tunnel
|
||||
* @pre IsRailTunnelTile(t)
|
||||
* @param t the tile
|
||||
* @param b the reservation state
|
||||
*/
|
||||
static inline void SetTunnelReservation(TileIndex t, bool b)
|
||||
{
|
||||
assert(IsRailTunnelTile(t));
|
||||
SB(_m[t].m5, 4, 1, b ? 1 : 0);
|
||||
}
|
||||
|
||||
TileIndex GetOtherTunnelEnd(TileIndex);
|
||||
|
||||
/** Flags for miscellaneous industry tile specialities */
|
||||
|
@@ -17,6 +17,7 @@
|
||||
void MarkBridgeDirty(TileIndex begin, TileIndex end, DiagDirection direction, uint bridge_height, const ZoomLevel mark_dirty_if_zoomlevel_is_below = ZOOM_LVL_END);
|
||||
void MarkBridgeDirty(TileIndex tile, const ZoomLevel mark_dirty_if_zoomlevel_is_below = ZOOM_LVL_END);
|
||||
void MarkBridgeOrTunnelDirty(TileIndex tile, const ZoomLevel mark_dirty_if_zoomlevel_is_below = ZOOM_LVL_END);
|
||||
void MarkBridgeOrTunnelDirtyOnReservationChange(TileIndex tile, const ZoomLevel mark_dirty_if_zoomlevel_is_below = ZOOM_LVL_END);
|
||||
uint GetTunnelBridgeSignalSimulationSignalCount(TileIndex begin, TileIndex end);
|
||||
|
||||
/**
|
||||
|
@@ -59,6 +59,7 @@ TileIndex _build_tunnel_endtile; ///< The end of a tunnel; as hidden return from
|
||||
/** Z position of the bridge sprites relative to bridge height (downwards) */
|
||||
static const int BRIDGE_Z_START = 3;
|
||||
|
||||
extern void DrawTrackBits(TileInfo *ti, TrackBits track);
|
||||
extern void DrawRoadBits(TileInfo *ti);
|
||||
extern const RoadBits _invalid_tileh_slopes_road[2][15];
|
||||
|
||||
@@ -102,6 +103,21 @@ void MarkBridgeOrTunnelDirty(TileIndex tile, const ZoomLevel mark_dirty_if_zooml
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Mark bridge or tunnel tiles dirty on tunnel/bridge head reservation change
|
||||
* @param tile Bridge head or tunnel entrance.
|
||||
*/
|
||||
void MarkBridgeOrTunnelDirtyOnReservationChange(TileIndex tile, const ZoomLevel mark_dirty_if_zoomlevel_is_below)
|
||||
{
|
||||
if (IsTunnelBridgeWithSignalSimulation(tile)) {
|
||||
MarkTileDirtyByTile(tile, mark_dirty_if_zoomlevel_is_below);
|
||||
} else if (IsBridge(tile)) {
|
||||
MarkBridgeDirty(tile, mark_dirty_if_zoomlevel_is_below);
|
||||
} else {
|
||||
MarkTileDirtyByTile(tile, mark_dirty_if_zoomlevel_is_below);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get number of signals on bridge or tunnel with signal simulation.
|
||||
* @param begin The begin of the tunnel or bridge.
|
||||
@@ -515,9 +531,9 @@ CommandCost CmdBuildBridge(TileIndex end_tile, DoCommandFlag flags, uint32 p1, u
|
||||
switch (transport_type) {
|
||||
case TRANSPORT_RAIL:
|
||||
/* Add to company infrastructure count if required. */
|
||||
if (is_new_owner && c != NULL) c->infrastructure.rail[railtype] += (bridge_len + 2) * TUNNELBRIDGE_TRACKBIT_FACTOR;
|
||||
MakeRailBridgeRamp(tile_start, owner, bridge_type, dir, railtype, is_upgrade);
|
||||
MakeRailBridgeRamp(tile_end, owner, bridge_type, ReverseDiagDir(dir), railtype, is_upgrade);
|
||||
if (is_new_owner && c != NULL) c->infrastructure.rail[railtype] += (bridge_len * TUNNELBRIDGE_TRACKBIT_FACTOR) + GetTunnelBridgeHeadOnlyRailInfrastructureCount(tile_start) + GetTunnelBridgeHeadOnlyRailInfrastructureCount(tile_end);
|
||||
break;
|
||||
|
||||
case TRANSPORT_ROAD: {
|
||||
@@ -982,7 +998,7 @@ static CommandCost DoClearTunnel(TileIndex tile, DoCommandFlag flags)
|
||||
Owner owner = GetTileOwner(tile);
|
||||
|
||||
Train *v = NULL;
|
||||
if (HasTunnelBridgeReservation(tile)) {
|
||||
if (HasTunnelReservation(tile)) {
|
||||
v = GetTrainForReservation(tile, track);
|
||||
if (v != NULL) FreeTrainTrackReservation(v);
|
||||
}
|
||||
@@ -1066,25 +1082,49 @@ static CommandCost DoClearBridge(TileIndex tile, DoCommandFlag flags)
|
||||
ChangeTownRating(t, RATING_TUNNEL_BRIDGE_DOWN_STEP, RATING_TUNNEL_BRIDGE_MINIMUM, flags);
|
||||
}
|
||||
|
||||
CommandCost cost(EXPENSES_CONSTRUCTION);
|
||||
|
||||
const bool rail = GetTunnelBridgeTransportType(tile) == TRANSPORT_RAIL;
|
||||
TrackBits tile_tracks = TRACK_BIT_NONE;
|
||||
TrackBits endtile_tracks = TRACK_BIT_NONE;
|
||||
if (rail) {
|
||||
tile_tracks = GetCustomBridgeHeadTrackBits(tile);
|
||||
endtile_tracks = GetCustomBridgeHeadTrackBits(endtile);
|
||||
cost.AddCost(RailClearCost(GetRailType(tile)) * (CountBits(tile_tracks) + CountBits(endtile_tracks) - 2));
|
||||
}
|
||||
|
||||
Money base_cost = (GetTunnelBridgeTransportType(tile) != TRANSPORT_WATER) ? _price[PR_CLEAR_BRIDGE] : _price[PR_CLEAR_AQUEDUCT];
|
||||
uint len = GetTunnelBridgeLength(tile, endtile) + 2; // Don't forget the end tiles.
|
||||
uint middle_len = GetTunnelBridgeLength(tile, endtile);
|
||||
uint len = middle_len + 2; // Don't forget the end tiles.
|
||||
|
||||
cost.AddCost(len * base_cost);
|
||||
|
||||
if (flags & DC_EXEC) {
|
||||
/* read this value before actual removal of bridge */
|
||||
bool rail = GetTunnelBridgeTransportType(tile) == TRANSPORT_RAIL;
|
||||
Owner owner = GetTileOwner(tile);
|
||||
int height = GetBridgeHeight(tile);
|
||||
Train *v = NULL;
|
||||
SmallVector<Train *, 2> vehicles_affected;
|
||||
|
||||
if (rail && HasTunnelBridgeReservation(tile)) {
|
||||
v = GetTrainForReservation(tile, DiagDirToDiagTrack(direction));
|
||||
if (v != NULL) FreeTrainTrackReservation(v);
|
||||
if (rail) {
|
||||
auto find_train_reservations = [&vehicles_affected](TileIndex tile) {
|
||||
TrackBits reserved = GetBridgeReservationTrackBits(tile);
|
||||
Track track;
|
||||
while ((track = RemoveFirstTrack(&reserved)) != INVALID_TRACK) {
|
||||
Train *v = GetTrainForReservation(tile, track);
|
||||
if (v != NULL) {
|
||||
FreeTrainTrackReservation(v);
|
||||
*vehicles_affected.Append() = v;
|
||||
}
|
||||
}
|
||||
};
|
||||
find_train_reservations(tile);
|
||||
find_train_reservations(endtile);
|
||||
}
|
||||
|
||||
/* Update company infrastructure counts. */
|
||||
if (rail) {
|
||||
if (Company::IsValidID(owner)) {
|
||||
Company::Get(owner)->infrastructure.rail[GetRailType(tile)] -= len * TUNNELBRIDGE_TRACKBIT_FACTOR;
|
||||
Company::Get(owner)->infrastructure.rail[GetRailType(tile)] -= (middle_len * TUNNELBRIDGE_TRACKBIT_FACTOR) + GetTunnelBridgeHeadOnlyRailInfrastructureCount(tile) + GetTunnelBridgeHeadOnlyRailInfrastructureCount(endtile);
|
||||
if (IsTunnelBridgeWithSignalSimulation(tile)) { // handle tunnel/bridge signals.
|
||||
Company::Get(GetTileOwner(tile))->infrastructure.signal -= GetTunnelBridgeSignalSimulationSignalCount(tile, endtile);
|
||||
}
|
||||
@@ -1113,18 +1153,28 @@ static CommandCost DoClearBridge(TileIndex tile, DoCommandFlag flags)
|
||||
|
||||
if (rail) {
|
||||
/* cannot use INVALID_DIAGDIR for signal update because the bridge doesn't exist anymore */
|
||||
AddSideToSignalBuffer(tile, ReverseDiagDir(direction), owner);
|
||||
AddSideToSignalBuffer(endtile, direction, owner);
|
||||
|
||||
Track track = DiagDirToDiagTrack(direction);
|
||||
YapfNotifyTrackLayoutChange(tile, track);
|
||||
YapfNotifyTrackLayoutChange(endtile, track);
|
||||
auto notify_track_change = [owner](TileIndex tile, DiagDirection direction, TrackBits tracks) {
|
||||
auto check_dir = [&](DiagDirection d) {
|
||||
if (DiagdirReachesTracks(d) & tracks) AddSideToSignalBuffer(tile, d, owner);
|
||||
};
|
||||
check_dir(ChangeDiagDir(direction, DIAGDIRDIFF_90RIGHT));
|
||||
check_dir(ChangeDiagDir(direction, DIAGDIRDIFF_REVERSE));
|
||||
check_dir(ChangeDiagDir(direction, DIAGDIRDIFF_90LEFT));
|
||||
while (tracks != TRACK_BIT_NONE) {
|
||||
YapfNotifyTrackLayoutChange(tile, RemoveFirstTrack(&tracks));
|
||||
}
|
||||
};
|
||||
notify_track_change(tile, direction, tile_tracks);
|
||||
notify_track_change(endtile, ReverseDiagDir(direction), endtile_tracks);
|
||||
|
||||
if (v != NULL) TryPathReserve(v, true);
|
||||
for (uint i = 0; i < vehicles_affected.Length(); ++i) {
|
||||
TryPathReserve(vehicles_affected[i], true);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return CommandCost(EXPENSES_CONSTRUCTION, len * base_cost);
|
||||
return cost;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -1489,7 +1539,7 @@ static void DrawTile_TunnelBridge(TileInfo *ti)
|
||||
}
|
||||
|
||||
/* PBS debugging, draw reserved tracks darker */
|
||||
if (_game_mode != GM_MENU && _settings_client.gui.show_track_reservation && HasTunnelBridgeReservation(ti->tile)) {
|
||||
if (_game_mode != GM_MENU && _settings_client.gui.show_track_reservation && HasTunnelReservation(ti->tile)) {
|
||||
if (rti->UsesOverlay()) {
|
||||
SpriteID overlay = GetCustomRailSprite(rti, ti->tile, RTSG_OVERLAY);
|
||||
DrawGroundSprite(overlay + RTO_X + DiagDirToAxis(tunnelbridge_direction), PALETTE_CRASH);
|
||||
@@ -1531,6 +1581,52 @@ static void DrawTile_TunnelBridge(TileInfo *ti)
|
||||
DrawBridgeMiddle(ti);
|
||||
return;
|
||||
}
|
||||
if (transport_type == TRANSPORT_RAIL && IsRailCustomBridgeHead(ti->tile)) {
|
||||
DrawTrackBits(ti, GetCustomBridgeHeadTrackBits(ti->tile));
|
||||
if (HasRailCatenaryDrawn(GetRailType(ti->tile))) {
|
||||
DrawRailCatenary(ti);
|
||||
}
|
||||
|
||||
if (IsTunnelBridgeWithSignalSimulation(ti->tile)) {
|
||||
extern void DrawSingleSignal(TileIndex tile, const RailtypeInfo *rti, Track track, SignalState condition,
|
||||
SignalOffsets image, uint pos, SignalType type, SignalVariant variant, bool show_restricted);
|
||||
|
||||
DiagDirection dir = GetTunnelBridgeDirection(ti->tile);
|
||||
SignalVariant variant = IsTunnelBridgeSemaphore(ti->tile) ? SIG_SEMAPHORE : SIG_ELECTRIC;
|
||||
const RailtypeInfo *rti = GetRailTypeInfo(GetRailType(ti->tile));
|
||||
|
||||
Track t = FindFirstTrack(GetAcrossTunnelBridgeTrackBits(ti->tile));
|
||||
auto draw_signals = [&](uint position, SignalOffsets image, DiagDirection towards) {
|
||||
if (dir == towards) {
|
||||
/* flip signal directions */
|
||||
position ^= 1;
|
||||
image = (SignalOffsets)(image ^ 1);
|
||||
}
|
||||
if (IsTunnelBridgeSignalSimulationEntrance(ti->tile)) {
|
||||
DrawSingleSignal(ti->tile, rti, t, GetTunnelBridgeEntranceSignalState(ti->tile), image, position, SIGTYPE_NORMAL, variant, false);
|
||||
}
|
||||
if (IsTunnelBridgeSignalSimulationExit(ti->tile)) {
|
||||
SignalType type = SIGTYPE_NORMAL;
|
||||
if (IsTunnelBridgePBS(ti->tile)) {
|
||||
type = IsTunnelBridgeSignalSimulationEntrance(ti->tile) ? SIGTYPE_PBS : SIGTYPE_PBS_ONEWAY;
|
||||
}
|
||||
DrawSingleSignal(ti->tile, rti, t, GetTunnelBridgeExitSignalState(ti->tile), (SignalOffsets)(image ^ 1), position ^ 1, type, variant, false);
|
||||
}
|
||||
};
|
||||
switch (t) {
|
||||
default: NOT_REACHED();
|
||||
case TRACK_X: draw_signals( 8, SIGNAL_TO_SOUTHWEST, DIAGDIR_SW); break;
|
||||
case TRACK_Y: draw_signals(10, SIGNAL_TO_SOUTHEAST, DIAGDIR_NW); break;
|
||||
case TRACK_UPPER: draw_signals( 4, SIGNAL_TO_WEST, DIAGDIR_NW); break;
|
||||
case TRACK_LOWER: draw_signals( 6, SIGNAL_TO_WEST, DIAGDIR_SW); break;
|
||||
case TRACK_LEFT: draw_signals( 0, SIGNAL_TO_NORTH, DIAGDIR_NW); break;
|
||||
case TRACK_RIGHT: draw_signals( 2, SIGNAL_TO_NORTH, DIAGDIR_NE); break;
|
||||
}
|
||||
}
|
||||
|
||||
DrawBridgeMiddle(ti);
|
||||
return;
|
||||
}
|
||||
|
||||
const PalSpriteID *psid;
|
||||
int base_offset;
|
||||
@@ -1614,7 +1710,7 @@ static void DrawTile_TunnelBridge(TileInfo *ti)
|
||||
}
|
||||
|
||||
/* PBS debugging, draw reserved tracks darker */
|
||||
if (_game_mode != GM_MENU && _settings_client.gui.show_track_reservation && HasTunnelBridgeReservation(ti->tile)) {
|
||||
if (_game_mode != GM_MENU && _settings_client.gui.show_track_reservation && GetBridgeReservationTrackBits(ti->tile) != TRACK_BIT_NONE) {
|
||||
if (rti->UsesOverlay()) {
|
||||
SpriteID overlay = GetCustomRailSprite(rti, ti->tile, RTSG_OVERLAY);
|
||||
if (HasBridgeFlatRamp(ti->tileh, DiagDirToAxis(tunnelbridge_direction))) {
|
||||
@@ -1782,8 +1878,8 @@ void DrawBridgeMiddle(const TileInfo *ti)
|
||||
}
|
||||
}
|
||||
|
||||
if (_game_mode != GM_MENU && _settings_client.gui.show_track_reservation && !IsInvisibilitySet(TO_BRIDGES) && HasTunnelBridgeReservation(rampnorth)
|
||||
&& !IsTunnelBridgeWithSignalSimulation(rampnorth)) {
|
||||
if (_game_mode != GM_MENU && _settings_client.gui.show_track_reservation && !IsInvisibilitySet(TO_BRIDGES)
|
||||
&& !IsTunnelBridgeWithSignalSimulation(rampnorth) && (HasAcrossBridgeReservation(rampnorth) || HasAcrossBridgeReservation(rampsouth))) {
|
||||
if (rti->UsesOverlay()) {
|
||||
SpriteID overlay = GetCustomRailSprite(rti, ti->tile, RTSG_OVERLAY);
|
||||
AddSortableSpriteToDraw(overlay + RTO_X + axis, PALETTE_CRASH, ti->x, ti->y, 16, 16, 0, bridge_z, IsTransparencySet(TO_BRIDGES));
|
||||
@@ -1852,7 +1948,7 @@ static int GetSlopePixelZ_TunnelBridge(TileIndex tile, uint x, uint y)
|
||||
/* In the tunnel entrance? */
|
||||
if (5 <= pos && pos <= 10) return z;
|
||||
} else { // IsBridge(tile)
|
||||
if (IsRoadCustomBridgeHeadTile(tile)) {
|
||||
if (IsCustomBridgeHeadTile(tile)) {
|
||||
return z + TILE_HEIGHT + (IsSteepSlope(tileh) ? TILE_HEIGHT : 0);
|
||||
}
|
||||
|
||||
@@ -1883,7 +1979,7 @@ static int GetSlopePixelZ_TunnelBridge(TileIndex tile, uint x, uint y)
|
||||
|
||||
static Foundation GetFoundation_TunnelBridge(TileIndex tile, Slope tileh)
|
||||
{
|
||||
if (IsRoadCustomBridgeHeadTile(tile)) return FOUNDATION_LEVELED;
|
||||
if (IsCustomBridgeHeadTile(tile)) return FOUNDATION_LEVELED;
|
||||
return IsTunnel(tile) ? FOUNDATION_NONE : GetBridgeFoundation(tileh, DiagDirToAxis(GetTunnelBridgeDirection(tile)));
|
||||
}
|
||||
|
||||
@@ -1997,15 +2093,14 @@ static TrackStatus GetTileTrackStatus_TunnelBridge(TileIndex tile, TransportType
|
||||
|
||||
DiagDirection dir = GetTunnelBridgeDirection(tile);
|
||||
|
||||
if (mode == TRANSPORT_ROAD && IsRoadCustomBridgeHeadTile(tile)) {
|
||||
if (side != INVALID_DIAGDIR && side == dir) return 0;
|
||||
if (mode == TRANSPORT_ROAD && IsRoadCustomBridgeHeadTile(tile)) {
|
||||
TrackBits bits = TRACK_BIT_NONE;
|
||||
if (sub_mode & ROADTYPES_TRAM) bits |= _road_trackbits[GetCustomBridgeHeadRoadBits(tile, ROADTYPE_TRAM)];
|
||||
if (sub_mode & ROADTYPES_ROAD) bits |= _road_trackbits[GetCustomBridgeHeadRoadBits(tile, ROADTYPE_ROAD)];
|
||||
return CombineTrackStatus(TrackBitsToTrackdirBits(bits), TRACKDIR_BIT_NONE);
|
||||
}
|
||||
if (side != INVALID_DIAGDIR && side != ReverseDiagDir(dir)) return 0;
|
||||
return CombineTrackStatus(TrackBitsToTrackdirBits(DiagDirToDiagTrackBits(dir)), TRACKDIR_BIT_NONE);
|
||||
return CombineTrackStatus(TrackBitsToTrackdirBits(mode == TRANSPORT_RAIL ? GetTunnelBridgeTrackBits(tile) : DiagDirToDiagTrackBits(dir)), TRACKDIR_BIT_NONE);
|
||||
}
|
||||
|
||||
static void UpdateRoadTunnelBridgeInfrastructure(TileIndex begin, TileIndex end, bool add) {
|
||||
@@ -2063,9 +2158,6 @@ void SubtractRoadTunnelBridgeInfrastructure(TileIndex begin, TileIndex end) {
|
||||
static void ChangeTileOwner_TunnelBridge(TileIndex tile, Owner old_owner, Owner new_owner)
|
||||
{
|
||||
const TileIndex other_end = GetOtherTunnelBridgeEnd(tile);
|
||||
/* Set number of pieces to zero if it's the southern tile as we
|
||||
* don't want to update the infrastructure counts twice. */
|
||||
const uint num_pieces = tile < other_end ? (GetTunnelBridgeLength(tile, other_end) + 2) * TUNNELBRIDGE_TRACKBIT_FACTOR : 0;
|
||||
const TransportType tt = GetTunnelBridgeTransportType(tile);
|
||||
|
||||
if (tt == TRANSPORT_ROAD && tile < other_end) {
|
||||
@@ -2092,9 +2184,15 @@ static void ChangeTileOwner_TunnelBridge(TileIndex tile, Owner old_owner, Owner
|
||||
|
||||
Company *old = Company::Get(old_owner);
|
||||
if (tt == TRANSPORT_RAIL) {
|
||||
/* Set number of middle pieces to zero if it's the southern tile as we
|
||||
* don't want to update the infrastructure counts twice. */
|
||||
const uint num_pieces = GetTunnelBridgeHeadOnlyRailInfrastructureCount(tile) + (tile < other_end ? GetTunnelBridgeLength(tile, other_end) * TUNNELBRIDGE_TRACKBIT_FACTOR : 0);
|
||||
old->infrastructure.rail[GetRailType(tile)] -= num_pieces;
|
||||
if (new_owner != INVALID_OWNER) Company::Get(new_owner)->infrastructure.rail[GetRailType(tile)] += num_pieces;
|
||||
} else if (tt == TRANSPORT_WATER) {
|
||||
/* Set number of pieces to zero if it's the southern tile as we
|
||||
* don't want to update the infrastructure counts twice. */
|
||||
const uint num_pieces = tile < other_end ? (GetTunnelBridgeLength(tile, other_end) + 2) * TUNNELBRIDGE_TRACKBIT_FACTOR : 0;
|
||||
old->infrastructure.water -= num_pieces;
|
||||
if (new_owner != INVALID_OWNER) Company::Get(new_owner)->infrastructure.water += num_pieces;
|
||||
}
|
||||
@@ -2141,23 +2239,31 @@ extern const byte _tunnel_turnaround_pre_visibility_frame[DIAGDIR_END] = {31, 27
|
||||
|
||||
static VehicleEnterTileStatus VehicleEnter_TunnelBridge(Vehicle *v, TileIndex tile, int x, int y)
|
||||
{
|
||||
/* Direction into the wormhole */
|
||||
const DiagDirection dir = GetTunnelBridgeDirection(tile);
|
||||
/* New position of the vehicle on the tile */
|
||||
int pos = (DiagDirToAxis(dir) == AXIS_X ? x - (TileX(tile) * TILE_SIZE) : y - (TileY(tile) * TILE_SIZE));
|
||||
/* Number of units moved by the vehicle since entering the tile */
|
||||
int frame = (dir == DIAGDIR_NE || dir == DIAGDIR_NW) ? TILE_SIZE - 1 - pos : pos;
|
||||
|
||||
if (frame > (int) TILE_SIZE || frame < 0) return VETSB_CANNOT_ENTER;
|
||||
if (frame == TILE_SIZE) {
|
||||
TileIndexDiffC offset = TileIndexDiffCByDiagDir(ReverseDiagDir(dir));
|
||||
x += offset.x;
|
||||
y += offset.y;
|
||||
}
|
||||
|
||||
int z = GetSlopePixelZ(x, y) - v->z_pos;
|
||||
|
||||
if (abs(z) > 2) return VETSB_CANNOT_ENTER;
|
||||
/* Direction into the wormhole */
|
||||
const DiagDirection dir = GetTunnelBridgeDirection(tile);
|
||||
/* Direction of the vehicle */
|
||||
const DiagDirection vdir = DirToDiagDir(v->direction);
|
||||
/* New position of the vehicle on the tile */
|
||||
byte pos = (DiagDirToAxis(vdir) == AXIS_X ? x : y) & TILE_UNIT_MASK;
|
||||
/* Number of units moved by the vehicle since entering the tile */
|
||||
byte frame = (vdir == DIAGDIR_NE || vdir == DIAGDIR_NW) ? TILE_SIZE - 1 - pos : pos;
|
||||
|
||||
if (IsTunnel(tile)) {
|
||||
/* Direction of the vehicle */
|
||||
const DiagDirection vdir = DirToDiagDir(v->direction);
|
||||
if (v->type == VEH_TRAIN) {
|
||||
Train *t = Train::From(v);
|
||||
|
||||
if (t->track != TRACK_BIT_WORMHOLE && dir == vdir) {
|
||||
if (!(t->track & TRACK_BIT_WORMHOLE) && dir == vdir) {
|
||||
if (t->IsFrontEngine() && frame == TUNNEL_SOUND_FRAME) {
|
||||
if (!PlayVehicleSound(t, VSE_TUNNEL) && RailVehInfo(t->engine_type)->engclass == 0) {
|
||||
SndPlayVehicleFx(SND_05_TRAIN_THROUGH_TUNNEL, v);
|
||||
@@ -2173,7 +2279,7 @@ static VehicleEnterTileStatus VehicleEnter_TunnelBridge(Vehicle *v, TileIndex ti
|
||||
}
|
||||
}
|
||||
|
||||
if (dir == ReverseDiagDir(vdir) && frame == TILE_SIZE - _tunnel_visibility_frame[dir] && z == 0) {
|
||||
if (dir == ReverseDiagDir(vdir) && frame == (int) (_tunnel_visibility_frame[dir] - 1) && z == 0) {
|
||||
/* We're at the tunnel exit ?? */
|
||||
if (t->tile != tile && GetOtherTunnelEnd(t->tile) != tile) return VETSB_CONTINUE; // In chunnel
|
||||
t->tile = tile;
|
||||
@@ -2203,7 +2309,7 @@ static VehicleEnterTileStatus VehicleEnter_TunnelBridge(Vehicle *v, TileIndex ti
|
||||
}
|
||||
|
||||
/* We're at the tunnel exit ?? */
|
||||
if (dir == ReverseDiagDir(vdir) && frame == TILE_SIZE - _tunnel_visibility_frame[dir] && z == 0) {
|
||||
if (dir == ReverseDiagDir(vdir) && frame == (int) (_tunnel_visibility_frame[dir] - 1) && z == 0) {
|
||||
if (rv->tile != tile && GetOtherTunnelEnd(rv->tile) != tile) return VETSB_CONTINUE; // In chunnel
|
||||
rv->tile = tile;
|
||||
rv->cur_image_valid_dir = INVALID_DIR;
|
||||
@@ -2224,11 +2330,12 @@ static VehicleEnterTileStatus VehicleEnter_TunnelBridge(Vehicle *v, TileIndex ti
|
||||
first->cur_speed = min(first->cur_speed, spd);
|
||||
}
|
||||
|
||||
if (vdir == dir) {
|
||||
/* Vehicle enters bridge at the last frame inside this tile. */
|
||||
if (frame != TILE_SIZE - 1) return VETSB_CONTINUE;
|
||||
const Direction bridge_dir = DiagDirToDir(dir);
|
||||
if (v->direction == bridge_dir) {
|
||||
switch (v->type) {
|
||||
case VEH_TRAIN: {
|
||||
/* Trains enter bridge at the first frame beyond this tile. */
|
||||
if (frame != TILE_SIZE) return VETSB_CONTINUE;
|
||||
Train *t = Train::From(v);
|
||||
t->track = TRACK_BIT_WORMHOLE;
|
||||
ClrBit(t->gv_flags, GVF_GOINGUP_BIT);
|
||||
@@ -2237,6 +2344,8 @@ static VehicleEnterTileStatus VehicleEnter_TunnelBridge(Vehicle *v, TileIndex ti
|
||||
}
|
||||
|
||||
case VEH_ROAD: {
|
||||
/* Non-train vehicles enter bridge at the last frame inside this tile. */
|
||||
if (frame != TILE_SIZE - 1) return VETSB_CONTINUE;
|
||||
RoadVehicle *rv = RoadVehicle::From(v);
|
||||
if (IsRoadCustomBridgeHeadTile(tile)) {
|
||||
RoadBits bits = ROAD_NONE;
|
||||
@@ -2253,29 +2362,36 @@ static VehicleEnterTileStatus VehicleEnter_TunnelBridge(Vehicle *v, TileIndex ti
|
||||
}
|
||||
|
||||
case VEH_SHIP:
|
||||
/* Non-train vehicles enter bridge at the last frame inside this tile. */
|
||||
if (frame != TILE_SIZE - 1) return VETSB_CONTINUE;
|
||||
Ship::From(v)->state = TRACK_BIT_WORMHOLE;
|
||||
break;
|
||||
|
||||
default: NOT_REACHED();
|
||||
}
|
||||
return VETSB_ENTERED_WORMHOLE;
|
||||
} else if (vdir == ReverseDiagDir(dir)) {
|
||||
v->tile = tile;
|
||||
} else if (v->direction == ReverseDir(bridge_dir)) {
|
||||
switch (v->type) {
|
||||
case VEH_TRAIN: {
|
||||
Train *t = Train::From(v);
|
||||
if (t->track == TRACK_BIT_WORMHOLE) {
|
||||
t->track = DiagDirToDiagTrackBits(vdir);
|
||||
if (t->track & TRACK_BIT_WORMHOLE) {
|
||||
if (IsRailCustomBridgeHeadTile(tile)) {
|
||||
return VETSB_ENTERED_WORMHOLE;
|
||||
} else {
|
||||
v->tile = tile;
|
||||
t->track = DiagDirToDiagTrackBits(DirToDiagDir(v->direction));
|
||||
}
|
||||
return VETSB_ENTERED_WORMHOLE;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
case VEH_ROAD: {
|
||||
v->tile = tile;
|
||||
RoadVehicle *rv = RoadVehicle::From(v);
|
||||
if (rv->state == RVSB_WORMHOLE) {
|
||||
rv->cur_image_valid_dir = INVALID_DIR;
|
||||
rv->state = DiagDirToDiagTrackdir(vdir);
|
||||
rv->state = DiagDirToDiagTrackdir(DirToDiagDir(v->direction));
|
||||
rv->frame = 0;
|
||||
return VETSB_ENTERED_WORMHOLE;
|
||||
}
|
||||
@@ -2283,9 +2399,10 @@ static VehicleEnterTileStatus VehicleEnter_TunnelBridge(Vehicle *v, TileIndex ti
|
||||
}
|
||||
|
||||
case VEH_SHIP: {
|
||||
v->tile = tile;
|
||||
Ship *ship = Ship::From(v);
|
||||
if (ship->state == TRACK_BIT_WORMHOLE) {
|
||||
ship->state = DiagDirToDiagTrackBits(vdir);
|
||||
ship->state = DiagDirToDiagTrackBits(DirToDiagDir(v->direction));
|
||||
return VETSB_ENTERED_WORMHOLE;
|
||||
}
|
||||
break;
|
||||
@@ -2293,6 +2410,29 @@ static VehicleEnterTileStatus VehicleEnter_TunnelBridge(Vehicle *v, TileIndex ti
|
||||
|
||||
default: NOT_REACHED();
|
||||
}
|
||||
} else if (v->type == VEH_TRAIN && IsRailCustomBridgeHeadTile(tile)) {
|
||||
DirDiff dir_diff = DirDifference(v->direction, bridge_dir);
|
||||
DirDiff reverse_dir_diff = DirDifference(v->direction, ReverseDir(bridge_dir));
|
||||
|
||||
if (dir_diff == DIRDIFF_45RIGHT || dir_diff == DIRDIFF_45LEFT) {
|
||||
if (frame != TILE_SIZE) return VETSB_CONTINUE;
|
||||
|
||||
Train *t = Train::From(v);
|
||||
TileIndex other = GetOtherTunnelBridgeEnd(tile);
|
||||
if (GetTunnelBridgeLength(tile, other) == 0 && IsRailCustomBridgeHead(other)) {
|
||||
t->track |= TRACK_BIT_WORMHOLE;
|
||||
} else {
|
||||
t->direction = bridge_dir;
|
||||
t->track = TRACK_BIT_WORMHOLE;
|
||||
}
|
||||
ClrBit(t->gv_flags, GVF_GOINGUP_BIT);
|
||||
ClrBit(t->gv_flags, GVF_GOINGDOWN_BIT);
|
||||
return VETSB_ENTERED_WORMHOLE;
|
||||
}
|
||||
if (reverse_dir_diff == DIRDIFF_45RIGHT || reverse_dir_diff == DIRDIFF_45LEFT) {
|
||||
Train *t = Train::From(v);
|
||||
if (t->track & TRACK_BIT_WORMHOLE) return VETSB_ENTERED_WORMHOLE;
|
||||
}
|
||||
}
|
||||
}
|
||||
return VETSB_CONTINUE;
|
||||
@@ -2318,6 +2458,16 @@ static CommandCost TerraformTile_TunnelBridge(TileIndex tile, DoCommandFlag flag
|
||||
return DoCommand(tile, 0, 0, flags, CMD_LANDSCAPE_CLEAR);
|
||||
}
|
||||
}
|
||||
if (IsRailCustomBridgeHeadTile(tile)) {
|
||||
extern bool IsValidFlatRailBridgeHeadTrackBits(Slope normalised_slope, DiagDirection bridge_direction, TrackBits tracks);
|
||||
|
||||
/* Steep slopes behave the same as slopes with one corner raised. */
|
||||
const Slope normalised_tileh_new = IsSteepSlope(tileh_new) ? SlopeWithOneCornerRaised(GetHighestSlopeCorner(tileh_new)) : tileh_new;
|
||||
|
||||
if (!IsValidFlatRailBridgeHeadTrackBits(normalised_tileh_new, direction, GetCustomBridgeHeadTrackBits(tile))) {
|
||||
return DoCommand(tile, 0, 0, flags, CMD_LANDSCAPE_CLEAR);
|
||||
}
|
||||
}
|
||||
|
||||
/* Check if new slope is valid for bridges in general (so we can safely call GetBridgeFoundation()) */
|
||||
if ((direction == DIAGDIR_NW) || (direction == DIAGDIR_NE)) {
|
||||
|
@@ -16,6 +16,9 @@
|
||||
#include "tunnel_base.h"
|
||||
#include "cmd_helper.h"
|
||||
#include "signal_type.h"
|
||||
#include "tunnel_map.h"
|
||||
#include "track_func.h"
|
||||
#include "core/bitmath_func.hpp"
|
||||
|
||||
|
||||
/**
|
||||
@@ -98,31 +101,34 @@ static inline TileIndex GetOtherTunnelBridgeEnd(TileIndex t)
|
||||
return IsTunnel(t) ? GetOtherTunnelEnd(t) : GetOtherBridgeEnd(t);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Get the reservation state of the rail tunnel/bridge
|
||||
* Get the track bits for a rail tunnel/bridge
|
||||
* @pre IsTileType(t, MP_TUNNELBRIDGE) && GetTunnelBridgeTransportType(t) == TRANSPORT_RAIL
|
||||
* @param t the tile
|
||||
* @return reservation state
|
||||
* @return reserved track bits
|
||||
*/
|
||||
static inline bool HasTunnelBridgeReservation(TileIndex t)
|
||||
static inline TrackBits GetTunnelBridgeTrackBits(TileIndex t)
|
||||
{
|
||||
assert(IsTileType(t, MP_TUNNELBRIDGE));
|
||||
assert(GetTunnelBridgeTransportType(t) == TRANSPORT_RAIL);
|
||||
return HasBit(_m[t].m5, 4);
|
||||
if (IsTunnel(t)) {
|
||||
return DiagDirToDiagTrackBits(GetTunnelBridgeDirection(t));
|
||||
} else {
|
||||
return GetCustomBridgeHeadTrackBits(t);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the reservation state of the rail tunnel/bridge
|
||||
* Get the track bits for a rail tunnel/bridge onto/across the tunnel/bridge
|
||||
* @pre IsTileType(t, MP_TUNNELBRIDGE) && GetTunnelBridgeTransportType(t) == TRANSPORT_RAIL
|
||||
* @param t the tile
|
||||
* @param b the reservation state
|
||||
* @return reserved track bits
|
||||
*/
|
||||
static inline void SetTunnelBridgeReservation(TileIndex t, bool b)
|
||||
static inline TrackBits GetAcrossTunnelBridgeTrackBits(TileIndex t)
|
||||
{
|
||||
assert(IsTileType(t, MP_TUNNELBRIDGE));
|
||||
assert(GetTunnelBridgeTransportType(t) == TRANSPORT_RAIL);
|
||||
SB(_m[t].m5, 4, 1, b ? 1 : 0);
|
||||
if (IsTunnel(t)) {
|
||||
return DiagDirToDiagTrackBits(GetTunnelBridgeDirection(t));
|
||||
} else {
|
||||
return GetCustomBridgeHeadTrackBits(t) & GetAcrossBridgePossibleTrackBits(t);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -133,7 +139,122 @@ static inline void SetTunnelBridgeReservation(TileIndex t, bool b)
|
||||
*/
|
||||
static inline TrackBits GetTunnelBridgeReservationTrackBits(TileIndex t)
|
||||
{
|
||||
return HasTunnelBridgeReservation(t) ? DiagDirToDiagTrackBits(GetTunnelBridgeDirection(t)) : TRACK_BIT_NONE;
|
||||
if (IsTunnel(t)) {
|
||||
return HasTunnelReservation(t) ? DiagDirToDiagTrackBits(GetTunnelBridgeDirection(t)) : TRACK_BIT_NONE;
|
||||
} else {
|
||||
return GetBridgeReservationTrackBits(t);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the reserved track bits for a rail tunnel/bridge onto/across the tunnel/bridge
|
||||
* @pre IsTileType(t, MP_TUNNELBRIDGE) && GetTunnelBridgeTransportType(t) == TRANSPORT_RAIL
|
||||
* @param t the tile
|
||||
* @return reserved track bits
|
||||
*/
|
||||
static inline TrackBits GetAcrossTunnelBridgeReservationTrackBits(TileIndex t)
|
||||
{
|
||||
if (IsTunnel(t)) {
|
||||
return HasTunnelReservation(t) ? DiagDirToDiagTrackBits(GetTunnelBridgeDirection(t)) : TRACK_BIT_NONE;
|
||||
} else {
|
||||
return GetAcrossBridgeReservationTrackBits(t);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get whether there are reserved track bits for a rail tunnel/bridge onto/across the tunnel/bridge
|
||||
* @pre IsTileType(t, MP_TUNNELBRIDGE) && GetTunnelBridgeTransportType(t) == TRANSPORT_RAIL
|
||||
* @param t the tile
|
||||
* @return whether there are reserved track bits
|
||||
*/
|
||||
static inline bool HasAcrossTunnelBridgeReservation(TileIndex t)
|
||||
{
|
||||
if (IsTunnel(t)) {
|
||||
return HasTunnelReservation(t);
|
||||
} else {
|
||||
return GetAcrossBridgeReservationTrackBits(t) != TRACK_BIT_NONE;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the rail infrastructure count of a rail tunnel/bridge head tile (excluding the tunnel/bridge middle)
|
||||
* @param bits the track bits
|
||||
* @return rail infrastructure count
|
||||
*/
|
||||
static inline uint GetTunnelBridgeHeadOnlyRailInfrastructureCountFromTrackBits(TrackBits bits)
|
||||
{
|
||||
uint pieces = CountBits(bits);
|
||||
if (TracksOverlap(bits)) pieces *= pieces;
|
||||
return (TUNNELBRIDGE_TRACKBIT_FACTOR / 2) * (1 + pieces);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the rail infrastructure count of a rail tunnel/bridge head tile (excluding the tunnel/bridge middle)
|
||||
* @pre IsTileType(t, MP_TUNNELBRIDGE) && GetTunnelBridgeTransportType(t) == TRANSPORT_RAIL
|
||||
* @param t the tile
|
||||
* @return rail infrastructure count
|
||||
*/
|
||||
static inline uint GetTunnelBridgeHeadOnlyRailInfrastructureCount(TileIndex t)
|
||||
{
|
||||
return IsBridge(t) ? GetTunnelBridgeHeadOnlyRailInfrastructureCountFromTrackBits(GetTunnelBridgeTrackBits(t)) : TUNNELBRIDGE_TRACKBIT_FACTOR;
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if the given track direction on a rail bridge head tile enters the bridge
|
||||
* @pre IsTileType(t, MP_TUNNELBRIDGE) && GetTunnelBridgeTransportType(t) == TRANSPORT_RAIL
|
||||
* @param t the tile
|
||||
* @param td track direction
|
||||
* @return reservation state
|
||||
*/
|
||||
static inline bool TrackdirEntersTunnelBridge(TileIndex t, Trackdir td)
|
||||
{
|
||||
assert(IsTileType(t, MP_TUNNELBRIDGE));
|
||||
assert(GetTunnelBridgeTransportType(t) == TRANSPORT_RAIL);
|
||||
return TrackdirToExitdir(td) == GetTunnelBridgeDirection(t);
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if the given track direction on a rail bridge head tile exits the bridge
|
||||
* @pre IsTileType(t, MP_TUNNELBRIDGE) && GetTunnelBridgeTransportType(t) == TRANSPORT_RAIL
|
||||
* @param t the tile
|
||||
* @param td track direction
|
||||
* @return reservation state
|
||||
*/
|
||||
static inline bool TrackdirExitsTunnelBridge(TileIndex t, Trackdir td)
|
||||
{
|
||||
assert(IsTileType(t, MP_TUNNELBRIDGE));
|
||||
assert(GetTunnelBridgeTransportType(t) == TRANSPORT_RAIL);
|
||||
return TrackdirToExitdir(ReverseTrackdir(td)) == GetTunnelBridgeDirection(t);
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if the given track on a rail bridge head tile enters/exits the bridge
|
||||
* @pre IsTileType(t, MP_TUNNELBRIDGE) && GetTunnelBridgeTransportType(t) == TRANSPORT_RAIL
|
||||
* @param tile the tile
|
||||
* @param t track
|
||||
* @return reservation state
|
||||
*/
|
||||
static inline bool IsTrackAcrossTunnelBridge(TileIndex tile, Track t)
|
||||
{
|
||||
assert(IsTileType(tile, MP_TUNNELBRIDGE));
|
||||
assert(GetTunnelBridgeTransportType(tile) == TRANSPORT_RAIL);
|
||||
return DiagdirReachesTracks(ReverseDiagDir(GetTunnelBridgeDirection(tile))) & TrackToTrackBits(t);
|
||||
}
|
||||
|
||||
/**
|
||||
* Lift the reservation of a specific track on a tunnel or rail bridge head tile
|
||||
* @pre IsTileType(tile, MP_TUNNELBRIDGE) && GetTunnelBridgeTransportType(tile) == TRANSPORT_RAIL
|
||||
* @param tile the tile
|
||||
*/
|
||||
static inline void UnreserveAcrossRailTunnelBridge(TileIndex tile)
|
||||
{
|
||||
assert(IsTileType(tile, MP_TUNNELBRIDGE));
|
||||
assert(GetTunnelBridgeTransportType(tile) == TRANSPORT_RAIL);
|
||||
if (IsTunnel(tile)) {
|
||||
SetTunnelReservation(tile, false);
|
||||
} else {
|
||||
UnreserveAcrossRailBridgeHead(tile);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
|
@@ -640,11 +640,23 @@ CommandCost EnsureNoRoadVehicleOnGround(TileIndex tile)
|
||||
return CommandCost();
|
||||
}
|
||||
|
||||
struct GetVehicleTunnelBridgeProcData {
|
||||
const Vehicle *v;
|
||||
TileIndex t;
|
||||
bool across_only;
|
||||
};
|
||||
|
||||
/** Procedure called for every vehicle found in tunnel/bridge in the hash map */
|
||||
static Vehicle *GetVehicleTunnelBridgeProc(Vehicle *v, void *data)
|
||||
{
|
||||
const GetVehicleTunnelBridgeProcData *info = (GetVehicleTunnelBridgeProcData*) data;
|
||||
if (v->type != VEH_TRAIN && v->type != VEH_ROAD && v->type != VEH_SHIP) return NULL;
|
||||
if (v == (const Vehicle *)data) return NULL;
|
||||
if (v == info->v) return NULL;
|
||||
|
||||
if (v->type == VEH_TRAIN && info->across_only && IsBridge(info->t)) {
|
||||
TrackBits vehicle_track = Train::From(v)->track;
|
||||
if (!(vehicle_track & TRACK_BIT_WORMHOLE) && !(GetAcrossBridgePossibleTrackBits(info->t) & vehicle_track)) return NULL;
|
||||
}
|
||||
|
||||
return v;
|
||||
}
|
||||
@@ -654,16 +666,24 @@ static Vehicle *GetVehicleTunnelBridgeProc(Vehicle *v, void *data)
|
||||
* @param tile first end
|
||||
* @param endtile second end
|
||||
* @param ignore Ignore this vehicle when searching
|
||||
* @param across_only Only find vehicles which are passing across the bridge/tunnel or on connecting bridge head track pieces
|
||||
* @return Succeeded command (if tunnel/bridge is free) or failed command (if a vehicle is using the tunnel/bridge).
|
||||
*/
|
||||
CommandCost TunnelBridgeIsFree(TileIndex tile, TileIndex endtile, const Vehicle *ignore)
|
||||
CommandCost TunnelBridgeIsFree(TileIndex tile, TileIndex endtile, const Vehicle *ignore, bool across_only)
|
||||
{
|
||||
/* Value v is not safe in MP games, however, it is used to generate a local
|
||||
* error message only (which may be different for different machines).
|
||||
* Such a message does not affect MP synchronisation.
|
||||
*/
|
||||
Vehicle *v = VehicleFromPos(tile, const_cast<Vehicle *>(ignore), &GetVehicleTunnelBridgeProc, true);
|
||||
if (v == NULL) v = VehicleFromPos(endtile, const_cast<Vehicle *>(ignore), &GetVehicleTunnelBridgeProc, true);
|
||||
GetVehicleTunnelBridgeProcData data;
|
||||
data.v = ignore;
|
||||
data.t = tile;
|
||||
data.across_only = across_only;
|
||||
Vehicle *v = VehicleFromPos(tile, &data, &GetVehicleTunnelBridgeProc, true);
|
||||
if (v == NULL) {
|
||||
data.t = endtile;
|
||||
v = VehicleFromPos(endtile, &data, &GetVehicleTunnelBridgeProc, true);
|
||||
}
|
||||
|
||||
if (v != NULL) return_cmd_error(STR_ERROR_TRAIN_IN_THE_WAY + v->type);
|
||||
return CommandCost();
|
||||
@@ -676,6 +696,12 @@ static Vehicle *EnsureNoTrainOnTrackProc(Vehicle *v, void *data)
|
||||
if (v->type != VEH_TRAIN) return NULL;
|
||||
|
||||
Train *t = Train::From(v);
|
||||
if (rail_bits & TRACK_BIT_WORMHOLE) {
|
||||
if (t->track & TRACK_BIT_WORMHOLE) return v;
|
||||
rail_bits &= ~TRACK_BIT_WORMHOLE;
|
||||
} else if (t->track & TRACK_BIT_WORMHOLE) {
|
||||
return NULL;
|
||||
}
|
||||
if ((t->track != rail_bits) && !TracksOverlap(t->track | rail_bits)) return NULL;
|
||||
|
||||
return v;
|
||||
|
@@ -61,7 +61,7 @@ void ViewportAddVehicles(DrawPixelInfo *dpi);
|
||||
void ViewportMapDrawVehicles(DrawPixelInfo *dpi);
|
||||
|
||||
void ShowNewGrfVehicleError(EngineID engine, StringID part1, StringID part2, GRFBugs bug_type, bool critical);
|
||||
CommandCost TunnelBridgeIsFree(TileIndex tile, TileIndex endtile, const Vehicle *ignore = NULL);
|
||||
CommandCost TunnelBridgeIsFree(TileIndex tile, TileIndex endtile, const Vehicle *ignore = NULL, bool across_only = false);
|
||||
|
||||
void DecreaseVehicleValue(Vehicle *v);
|
||||
void CheckVehicleBreakdown(Vehicle *v);
|
||||
|
@@ -103,6 +103,7 @@
|
||||
#include "tunnelbridge_map.h"
|
||||
#include "gui.h"
|
||||
#include "core/container_func.hpp"
|
||||
#include "tunnelbridge_map.h"
|
||||
|
||||
#include <map>
|
||||
#include <vector>
|
||||
@@ -1085,9 +1086,23 @@ static HighLightStyle GetPartOfAutoLine(int px, int py, const Point &selstart, c
|
||||
static void DrawAutorailSelection(const TileInfo *ti, HighLightStyle autorail_type, PaletteID pal = -1)
|
||||
{
|
||||
SpriteID image;
|
||||
int offset;
|
||||
|
||||
FoundationPart foundation_part = FOUNDATION_PART_NORMAL;
|
||||
int offset;
|
||||
bool bridge_head_mode = false;
|
||||
|
||||
if (IsFlatRailBridgeHeadTile(ti->tile)) {
|
||||
extern bool IsValidFlatRailBridgeHeadTrackBits(Slope normalised_slope, DiagDirection bridge_direction, TrackBits tracks);
|
||||
|
||||
offset = _AutorailTilehSprite[SLOPE_FLAT][autorail_type];
|
||||
const Slope real_tileh = GetTileSlope(ti->tile, nullptr);
|
||||
const Slope normalised_tileh = IsSteepSlope(real_tileh) ? SlopeWithOneCornerRaised(GetHighestSlopeCorner(real_tileh)) : real_tileh;
|
||||
if (!IsValidFlatRailBridgeHeadTrackBits(normalised_tileh, GetTunnelBridgeDirection(ti->tile), TrackToTrackBits((Track) autorail_type))) {
|
||||
offset = -offset;
|
||||
}
|
||||
if (!IsRailCustomBridgeHead(ti->tile)) {
|
||||
bridge_head_mode = true;
|
||||
}
|
||||
} else {
|
||||
Slope autorail_tileh = RemoveHalftileSlope(ti->tileh);
|
||||
if (IsHalftileSlope(ti->tileh)) {
|
||||
static const HighLightStyle _lower_rail[CORNER_END] = { HT_DIR_VR, HT_DIR_HU, HT_DIR_VL, HT_DIR_HL }; // CORNER_W, CORNER_S, CORNER_E, CORNER_N
|
||||
@@ -1098,9 +1113,10 @@ static void DrawAutorailSelection(const TileInfo *ti, HighLightStyle autorail_ty
|
||||
autorail_tileh = SlopeWithThreeCornersRaised(OppositeCorner(halftile_corner));
|
||||
}
|
||||
}
|
||||
|
||||
assert(autorail_type < HT_DIR_END);
|
||||
offset = _AutorailTilehSprite[autorail_tileh][autorail_type];
|
||||
}
|
||||
|
||||
if (offset >= 0) {
|
||||
image = SPR_AUTORAIL_BASE + offset;
|
||||
if (pal == (PaletteID)-1) pal = _thd.make_square_red ? PALETTE_SEL_TILE_RED : PAL_NONE;
|
||||
@@ -1109,7 +1125,11 @@ static void DrawAutorailSelection(const TileInfo *ti, HighLightStyle autorail_ty
|
||||
if (pal == (PaletteID)-1) pal = PALETTE_SEL_TILE_RED;
|
||||
}
|
||||
|
||||
if (bridge_head_mode) {
|
||||
AddSortableSpriteToDraw(image, pal, ti->x, ti->y, 16, 16, 0, ti->z + 15);
|
||||
} else {
|
||||
DrawSelectionSprite(image, pal, ti, 7, foundation_part);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
|
Reference in New Issue
Block a user