Initial support for rail custom bridge heads
This commit is contained in:
@@ -1473,10 +1473,76 @@
|
|||||||
</tr>
|
</tr>
|
||||||
</table>
|
</table>
|
||||||
</li>
|
</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>m3 bits 7..4: <a href="#OwnershipInfo">owner</a> of tram</li>
|
||||||
<li>m3 bits 3..0: <a href="#TrackType">track type</a> for railway</li>
|
<li>m3 bits 3..0: <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:
|
||||||
<li>m5 bits 7 clear: tunnel entrance/exit</li>
|
<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
|
<li>m5 bit 7 set: bridge ramp
|
||||||
<ul>
|
<ul>
|
||||||
<li>m6 bits 5..2: <a name="BridgeType">bridge type</a>:
|
<li>m6 bits 5..2: <a name="BridgeType">bridge type</a>:
|
||||||
|
@@ -347,7 +347,7 @@ 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"><span class="free">OOOO OOOO</span> <span class="used_p">PPPP PPPP</span></td>
|
<td class="bits"><span class="free">OOOO OOOO</span> <span class="used_p">PPPP PPPP</span></td>
|
||||||
<td class="bits">-inherit-</td>
|
<td class="bits">-inherit-</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">-inherit-</td>
|
||||||
<td class="bits"><span class="free">OO</span>XX XX<span class="free">OO</span></td>
|
<td class="bits"><span class="free">OO</span>XX XX<span class="free">OO</span></td>
|
||||||
<td class="bits">-inherit-</td>
|
<td class="bits">-inherit-</td>
|
||||||
|
206
src/bridge_map.h
206
src/bridge_map.h
@@ -171,9 +171,22 @@ static inline void MakeRoadBridgeRamp(TileIndex t, Owner o, Owner owner_road, Ow
|
|||||||
* @param d the direction this ramp must be facing
|
* @param d the direction this ramp must be facing
|
||||||
* @param r the rail type of the bridge
|
* @param r the rail type of the bridge
|
||||||
*/
|
*/
|
||||||
static inline void MakeRailBridgeRamp(TileIndex t, Owner o, BridgeType bridgetype, DiagDirection d, RailType r)
|
static inline void MakeRailBridgeRamp(TileIndex t, Owner o, BridgeType bridgetype, DiagDirection d, RailType r, bool upgrade)
|
||||||
{
|
{
|
||||||
|
// Backup custom bridgehead data.
|
||||||
|
uint custom_bridge_head_reservation_backup = GB(_m[t].m2, 0, 4);
|
||||||
|
uint custom_bridge_head_tracks_backup = GB(_m[t].m4, 0, 6);
|
||||||
|
|
||||||
MakeBridgeRamp(t, o, bridgetype, d, TRANSPORT_RAIL, r);
|
MakeBridgeRamp(t, o, bridgetype, d, TRANSPORT_RAIL, r);
|
||||||
|
|
||||||
|
if (upgrade) {
|
||||||
|
// Restore custom bridgehead data if we're upgrading an existing bridge.
|
||||||
|
SB(_m[t].m2, 0, 4, custom_bridge_head_reservation_backup);
|
||||||
|
SB(_m[t].m4, 0, 6, custom_bridge_head_tracks_backup);
|
||||||
|
} else {
|
||||||
|
// Set bridge head tracks to axial track only.
|
||||||
|
SB(_m[t].m4, 0, 6, DiagDirToDiagTrackBits(d));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -255,4 +268,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 */
|
#endif /* BRIDGE_MAP_H */
|
||||||
|
@@ -103,7 +103,7 @@ static TrackBits GetRailTrackBitsUniversal(TileIndex t, byte *override)
|
|||||||
if (override != NULL && (IsTunnel(t) || GetTunnelBridgeLength(t, GetOtherBridgeEnd(t)) > 0)) {
|
if (override != NULL && (IsTunnel(t) || GetTunnelBridgeLength(t, GetOtherBridgeEnd(t)) > 0)) {
|
||||||
*override = 1 << GetTunnelBridgeDirection(t);
|
*override = 1 << GetTunnelBridgeDirection(t);
|
||||||
}
|
}
|
||||||
return DiagDirToDiagTrackBits(GetTunnelBridgeDirection(t));
|
return GetTunnelBridgeTrackBits(t);
|
||||||
|
|
||||||
case MP_ROAD:
|
case MP_ROAD:
|
||||||
if (!IsLevelCrossing(t)) return TRACK_BIT_NONE;
|
if (!IsLevelCrossing(t)) return TRACK_BIT_NONE;
|
||||||
@@ -199,6 +199,8 @@ static void AdjustTileh(TileIndex tile, Slope *tileh)
|
|||||||
if (IsTileType(tile, MP_TUNNELBRIDGE)) {
|
if (IsTileType(tile, MP_TUNNELBRIDGE)) {
|
||||||
if (IsTunnel(tile)) {
|
if (IsTunnel(tile)) {
|
||||||
*tileh = SLOPE_STEEP; // XXX - Hack to make tunnel entrances to always have a pylon
|
*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) {
|
} else if (*tileh != SLOPE_FLAT) {
|
||||||
*tileh = SLOPE_FLAT;
|
*tileh = SLOPE_FLAT;
|
||||||
} else {
|
} else {
|
||||||
|
@@ -352,7 +352,7 @@ Slope GetFoundationSlope(TileIndex tile, int *z)
|
|||||||
|
|
||||||
bool HasFoundationNW(TileIndex tile, Slope slope_here, uint z_here)
|
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;
|
int z;
|
||||||
|
|
||||||
@@ -371,7 +371,7 @@ bool HasFoundationNW(TileIndex tile, Slope slope_here, uint z_here)
|
|||||||
|
|
||||||
bool HasFoundationNE(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;
|
int z;
|
||||||
|
|
||||||
|
@@ -1703,6 +1703,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 :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_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
|
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 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. */
|
* 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;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -125,7 +125,7 @@ struct CFollowTrackT
|
|||||||
m_old_td = old_td;
|
m_old_td = old_td;
|
||||||
m_err = EC_NONE;
|
m_err = EC_NONE;
|
||||||
assert(((TrackStatusToTrackdirBits(GetTileTrackStatus(m_old_tile, TT(), IsRoadTT() ? RoadVehicle::From(m_veh)->compatible_roadtypes : 0)) & TrackdirToTrackdirBits(m_old_td)) != 0) ||
|
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);
|
m_exitdir = TrackdirToExitdir(m_old_td);
|
||||||
if (ForcedReverse()) return true;
|
if (ForcedReverse()) return true;
|
||||||
if (!CanExitOldTile()) return false;
|
if (!CanExitOldTile()) return false;
|
||||||
@@ -153,7 +153,7 @@ struct CFollowTrackT
|
|||||||
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
if (!Allow90degTurns()) {
|
if (!Allow90degTurns() && m_tiles_skipped == 0) {
|
||||||
m_new_td_bits &= (TrackdirBits)~(int)TrackdirCrossesTrackdirs(m_old_td);
|
m_new_td_bits &= (TrackdirBits)~(int)TrackdirCrossesTrackdirs(m_old_td);
|
||||||
if (m_new_td_bits == TRACKDIR_BIT_NONE) {
|
if (m_new_td_bits == TRACKDIR_BIT_NONE) {
|
||||||
m_err = EC_90DEG;
|
m_err = EC_90DEG;
|
||||||
@@ -216,7 +216,7 @@ protected:
|
|||||||
m_tiles_skipped = GetTunnelBridgeLength(m_new_tile, m_old_tile);
|
m_tiles_skipped = GetTunnelBridgeLength(m_new_tile, m_old_tile);
|
||||||
return;
|
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 */
|
/* normal or station tile, do one step */
|
||||||
@@ -365,13 +365,22 @@ protected:
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else { // IsBridge(m_new_tile)
|
} 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 (!m_is_bridge && IsRoadTT() && IsRoadCustomBridgeHeadTile(m_new_tile)) {
|
||||||
if (!(DiagDirToRoadBits(ReverseDiagDir(m_exitdir)) & GetCustomBridgeHeadRoadBits(m_new_tile, IsTram() ? ROADTYPE_TRAM : ROADTYPE_ROAD))) {
|
if (!(DiagDirToRoadBits(ReverseDiagDir(m_exitdir)) & GetCustomBridgeHeadRoadBits(m_new_tile, IsTram() ? ROADTYPE_TRAM : ROADTYPE_ROAD))) {
|
||||||
m_err = EC_NO_WAY;
|
m_err = EC_NO_WAY;
|
||||||
return false;
|
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) {
|
} else if (!m_is_bridge) {
|
||||||
DiagDirection ramp_enderdir = GetTunnelBridgeDirection(m_new_tile);
|
|
||||||
if (ramp_enderdir != m_exitdir) {
|
if (ramp_enderdir != m_exitdir) {
|
||||||
m_err = EC_NO_WAY;
|
m_err = EC_NO_WAY;
|
||||||
return false;
|
return false;
|
||||||
|
@@ -564,7 +564,7 @@ bool YapfTrainCheckReverse(const Train *v)
|
|||||||
|
|
||||||
int reverse_penalty = 0;
|
int reverse_penalty = 0;
|
||||||
|
|
||||||
if (v->track == TRACK_BIT_WORMHOLE) {
|
if (v->track & TRACK_BIT_WORMHOLE) {
|
||||||
/* front in tunnel / on bridge */
|
/* front in tunnel / on bridge */
|
||||||
DiagDirection dir_into_wormhole = GetTunnelBridgeDirection(tile);
|
DiagDirection dir_into_wormhole = GetTunnelBridgeDirection(tile);
|
||||||
|
|
||||||
@@ -579,7 +579,7 @@ bool YapfTrainCheckReverse(const Train *v)
|
|||||||
reverse_penalty -= DistanceManhattan(cur_tile, tile) * YAPF_TILE_LENGTH;
|
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 */
|
/* back in tunnel / on bridge */
|
||||||
DiagDirection dir_into_wormhole = GetTunnelBridgeDirection(tile_rev);
|
DiagDirection dir_into_wormhole = GetTunnelBridgeDirection(tile_rev);
|
||||||
|
|
||||||
|
22
src/pbs.cpp
22
src/pbs.cpp
@@ -81,7 +81,8 @@ void SetRailStationPlatformReservation(TileIndex start, DiagDirection dir, bool
|
|||||||
*/
|
*/
|
||||||
bool TryReserveRailTrack(TileIndex tile, Track t, bool trigger_stations)
|
bool TryReserveRailTrack(TileIndex tile, Track t, bool trigger_stations)
|
||||||
{
|
{
|
||||||
assert((GetTileTrackStatus(tile, TRANSPORT_RAIL, 0) & TrackToTrackBits(t)) != 0);
|
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) {
|
if (_settings_client.gui.show_track_reservation) {
|
||||||
/* show the reserved rail if needed */
|
/* show the reserved rail if needed */
|
||||||
@@ -123,10 +124,15 @@ bool TryReserveRailTrack(TileIndex tile, Track t, bool trigger_stations)
|
|||||||
break;
|
break;
|
||||||
|
|
||||||
case MP_TUNNELBRIDGE:
|
case MP_TUNNELBRIDGE:
|
||||||
if (GetTunnelBridgeTransportType(tile) == TRANSPORT_RAIL && !GetTunnelBridgeReservationTrackBits(tile)) {
|
if (GetTunnelBridgeTransportType(tile) == TRANSPORT_RAIL) {
|
||||||
SetTunnelBridgeReservation(tile, true);
|
if (IsTunnel(tile) && !HasTunnelReservation(tile)) {
|
||||||
|
SetTunnelReservation(tile, true);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
if (IsBridge(tile)) {
|
||||||
|
return TryReserveRailBridgeHead(tile, t);
|
||||||
|
}
|
||||||
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
@@ -177,7 +183,13 @@ void UnreserveRailTrack(TileIndex tile, Track t)
|
|||||||
break;
|
break;
|
||||||
|
|
||||||
case MP_TUNNELBRIDGE:
|
case MP_TUNNELBRIDGE:
|
||||||
if (GetTunnelBridgeTransportType(tile) == TRANSPORT_RAIL) SetTunnelBridgeReservation(tile, false);
|
if (GetTunnelBridgeTransportType(tile) == TRANSPORT_RAIL) {
|
||||||
|
if (IsTunnel(tile)) {
|
||||||
|
SetTunnelReservation(tile, false);
|
||||||
|
} else {
|
||||||
|
UnreserveRailBridgeHeadTrack(tile, t);
|
||||||
|
}
|
||||||
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
@@ -270,7 +282,7 @@ static Vehicle *FindTrainOnTrackEnum(Vehicle *v, void *data)
|
|||||||
if (v->type != VEH_TRAIN || (v->vehstatus & VS_CRASHED)) return NULL;
|
if (v->type != VEH_TRAIN || (v->vehstatus & VS_CRASHED)) return NULL;
|
||||||
|
|
||||||
Train *t = Train::From(v);
|
Train *t = Train::From(v);
|
||||||
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();
|
t = t->First();
|
||||||
|
|
||||||
/* ALWAYS return the lowest ID (anti-desync!) */
|
/* ALWAYS return the lowest ID (anti-desync!) */
|
||||||
|
212
src/rail_cmd.cpp
212
src/rail_cmd.cpp
@@ -424,6 +424,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);
|
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 */
|
/* Validate functions for rail building */
|
||||||
static inline bool ValParamTrackOrientation(Track track)
|
static inline bool ValParamTrackOrientation(Track track)
|
||||||
{
|
{
|
||||||
@@ -443,6 +462,7 @@ CommandCost CmdBuildSingleRail(TileIndex tile, DoCommandFlag flags, uint32 p1, u
|
|||||||
{
|
{
|
||||||
RailType railtype = Extract<RailType, 0, 4>(p1);
|
RailType railtype = Extract<RailType, 0, 4>(p1);
|
||||||
Track track = Extract<Track, 0, 3>(p2);
|
Track track = Extract<Track, 0, 3>(p2);
|
||||||
|
bool disable_custom_bridge_heads = HasBit(p2, 4);
|
||||||
CommandCost cost(EXPENSES_CONSTRUCTION);
|
CommandCost cost(EXPENSES_CONSTRUCTION);
|
||||||
|
|
||||||
if (!ValParamRailtype(railtype) || !ValParamTrackOrientation(track)) return CMD_ERROR;
|
if (!ValParamRailtype(railtype) || !ValParamTrackOrientation(track)) return CMD_ERROR;
|
||||||
@@ -497,6 +517,52 @@ CommandCost CmdBuildSingleRail(TileIndex tile, DoCommandFlag flags, uint32 p1, u
|
|||||||
break;
|
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) {
|
||||||
|
if (future != TRACK_BIT_HORZ && future != TRACK_BIT_VERT) {
|
||||||
|
return_cmd_error(STR_ERROR_IMPOSSIBLE_TRACK_COMBINATION);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
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: {
|
case MP_ROAD: {
|
||||||
/* Level crossings may only be built on these slopes */
|
/* 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);
|
if (!HasBit(VALID_LEVEL_CROSSING_SLOPES, tileh)) return_cmd_error(STR_ERROR_LAND_SLOPED_IN_WRONG_DIRECTION);
|
||||||
@@ -710,6 +776,44 @@ CommandCost CmdRemoveSingleRail(TileIndex tile, DoCommandFlag flags, uint32 p1,
|
|||||||
break;
|
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);
|
default: return_cmd_error(STR_ERROR_THERE_IS_NO_RAILROAD_TRACK);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1224,13 +1328,27 @@ static bool CheckSignalAutoFill(TileIndex &tile, Trackdir &trackdir, int &signal
|
|||||||
TileIndex orig_tile = tile; // backup old value
|
TileIndex orig_tile = tile; // backup old value
|
||||||
|
|
||||||
if (GetTunnelBridgeTransportType(tile) != TRANSPORT_RAIL) return false;
|
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
|
/* Skip to end of tunnel or bridge
|
||||||
* note that tile is a parameter by reference, so it must be updated */
|
* note that tile is a parameter by reference, so it must be updated */
|
||||||
tile = GetOtherTunnelBridgeEnd(tile);
|
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;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1599,6 +1717,24 @@ CommandCost CmdConvertRail(TileIndex tile, DoCommandFlag flags, uint32 p1, uint3
|
|||||||
|
|
||||||
SmallVector<Train *, 2> vehicles_affected;
|
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
|
/* Vehicle on the tile when not converting Rail <-> ElRail
|
||||||
* Tunnels and bridges have special check later */
|
* Tunnels and bridges have special check later */
|
||||||
if (tt != MP_TUNNELBRIDGE) {
|
if (tt != MP_TUNNELBRIDGE) {
|
||||||
@@ -1610,16 +1746,7 @@ CommandCost CmdConvertRail(TileIndex tile, DoCommandFlag flags, uint32 p1, uint3
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (flags & DC_EXEC) { // we can safely convert, too
|
if (flags & DC_EXEC) { // we can safely convert, too
|
||||||
TrackBits reserved = GetReservedTrackbits(tile);
|
find_train_reservations(tile, 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;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Update the company infrastructure counters. */
|
/* Update the company infrastructure counters. */
|
||||||
if (!IsRailStationTile(tile) || !IsStationTileBlocked(tile)) {
|
if (!IsRailStationTile(tile) || !IsStationTileBlocked(tile)) {
|
||||||
@@ -1660,10 +1787,7 @@ CommandCost CmdConvertRail(TileIndex tile, DoCommandFlag flags, uint32 p1, uint3
|
|||||||
default: // RAIL_TILE_NORMAL, RAIL_TILE_SIGNALS
|
default: // RAIL_TILE_NORMAL, RAIL_TILE_SIGNALS
|
||||||
if (flags & DC_EXEC) {
|
if (flags & DC_EXEC) {
|
||||||
/* notify YAPF about the track layout change */
|
/* notify YAPF about the track layout change */
|
||||||
TrackBits tracks = GetTrackBits(tile);
|
yapf_notify_track_change(tile, GetTrackBits(tile));
|
||||||
while (tracks != TRACK_BIT_NONE) {
|
|
||||||
YapfNotifyTrackLayoutChange(tile, RemoveFirstTrack(&tracks));
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
cost.AddCost(RailConvertCost(type, totype) * CountBits(GetTrackBits(tile)));
|
cost.AddCost(RailConvertCost(type, totype) * CountBits(GetTrackBits(tile)));
|
||||||
break;
|
break;
|
||||||
@@ -1692,22 +1816,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) {
|
if (flags & DC_EXEC) {
|
||||||
Track track = DiagDirToDiagTrack(GetTunnelBridgeDirection(tile));
|
find_train_reservations(tile, GetTunnelBridgeReservationTrackBits(tile));
|
||||||
if (HasTunnelBridgeReservation(tile)) {
|
find_train_reservations(endtile, GetTunnelBridgeReservationTrackBits(endtile));
|
||||||
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;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Update the company infrastructure counters. */
|
/* 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));
|
Company *c = Company::Get(GetTileOwner(tile));
|
||||||
c->infrastructure.rail[GetRailType(tile)] -= num_pieces;
|
c->infrastructure.rail[GetRailType(tile)] -= num_infra_pieces;
|
||||||
c->infrastructure.rail[totype] += num_pieces;
|
c->infrastructure.rail[totype] += num_infra_pieces;
|
||||||
DirtyCompanyInfrastructureWindows(c->index);
|
DirtyCompanyInfrastructureWindows(c->index);
|
||||||
|
|
||||||
SetRailType(tile, totype);
|
SetRailType(tile, totype);
|
||||||
@@ -1716,8 +1836,9 @@ CommandCost CmdConvertRail(TileIndex tile, DoCommandFlag flags, uint32 p1, uint3
|
|||||||
FindVehicleOnPos(tile, &affected_trains, &UpdateTrainPowerProc);
|
FindVehicleOnPos(tile, &affected_trains, &UpdateTrainPowerProc);
|
||||||
FindVehicleOnPos(endtile, &affected_trains, &UpdateTrainPowerProc);
|
FindVehicleOnPos(endtile, &affected_trains, &UpdateTrainPowerProc);
|
||||||
|
|
||||||
YapfNotifyTrackLayoutChange(tile, track);
|
/* notify YAPF about the track layout change */
|
||||||
YapfNotifyTrackLayoutChange(endtile, track);
|
yapf_notify_track_change(tile, GetTunnelBridgeTrackBits(tile));
|
||||||
|
yapf_notify_track_change(endtile, GetTunnelBridgeTrackBits(endtile));
|
||||||
|
|
||||||
if (IsBridge(tile)) {
|
if (IsBridge(tile)) {
|
||||||
MarkBridgeDirty(tile);
|
MarkBridgeDirty(tile);
|
||||||
@@ -1727,7 +1848,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;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -2061,10 +2182,19 @@ static inline void DrawTrackSprite(SpriteID sprite, PaletteID pal, const TileInf
|
|||||||
DrawGroundSprite(sprite, pal, NULL, 0, (ti->tileh & s) ? -8 : 0);
|
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)
|
static void DrawTrackBitsOverlay(TileInfo *ti, TrackBits track, const RailtypeInfo *rti)
|
||||||
{
|
{
|
||||||
RailGroundType rgt = GetRailGroundType(ti->tile);
|
const bool is_bridge = IsTileType(ti->tile, MP_TUNNELBRIDGE);
|
||||||
Foundation f = GetRailFoundation(ti->tileh, track);
|
RailGroundType rgt = GetRailOrBridgeGroundType(ti);
|
||||||
|
Foundation f = is_bridge ? FOUNDATION_LEVELED : GetRailFoundation(ti->tileh, track);
|
||||||
Corner halftile_corner = CORNER_INVALID;
|
Corner halftile_corner = CORNER_INVALID;
|
||||||
|
|
||||||
if (IsNonContinuousFoundation(f)) {
|
if (IsNonContinuousFoundation(f)) {
|
||||||
@@ -2103,7 +2233,10 @@ static void DrawTrackBitsOverlay(TileInfo *ti, TrackBits track, const RailtypeIn
|
|||||||
|
|
||||||
SpriteID overlay = GetCustomRailSprite(rti, ti->tile, RTSG_OVERLAY);
|
SpriteID overlay = GetCustomRailSprite(rti, ti->tile, RTSG_OVERLAY);
|
||||||
SpriteID ground = GetCustomRailSprite(rti, ti->tile, RTSG_GROUND);
|
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) {
|
if (track == TRACK_BIT_NONE) {
|
||||||
/* Half-tile foundation, no track here? */
|
/* Half-tile foundation, no track here? */
|
||||||
@@ -2213,7 +2346,7 @@ static void DrawTrackBitsOverlay(TileInfo *ti, TrackBits track, const RailtypeIn
|
|||||||
* @param ti TileInfo
|
* @param ti TileInfo
|
||||||
* @param track TrackBits to draw
|
* @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));
|
const RailtypeInfo *rti = GetRailTypeInfo(GetRailType(ti->tile));
|
||||||
|
|
||||||
@@ -2222,8 +2355,9 @@ static void DrawTrackBits(TileInfo *ti, TrackBits track)
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
RailGroundType rgt = GetRailGroundType(ti->tile);
|
const bool is_bridge = IsTileType(ti->tile, MP_TUNNELBRIDGE);
|
||||||
Foundation f = GetRailFoundation(ti->tileh, track);
|
RailGroundType rgt = GetRailOrBridgeGroundType(ti);
|
||||||
|
Foundation f = is_bridge ? FOUNDATION_LEVELED : GetRailFoundation(ti->tileh, track);
|
||||||
Corner halftile_corner = CORNER_INVALID;
|
Corner halftile_corner = CORNER_INVALID;
|
||||||
|
|
||||||
if (IsNonContinuousFoundation(f)) {
|
if (IsNonContinuousFoundation(f)) {
|
||||||
@@ -2314,7 +2448,7 @@ static void DrawTrackBits(TileInfo *ti, TrackBits track)
|
|||||||
/* PBS debugging, draw reserved tracks darker */
|
/* PBS debugging, draw reserved tracks darker */
|
||||||
if (_game_mode != GM_MENU && _settings_client.gui.show_track_reservation) {
|
if (_game_mode != GM_MENU && _settings_client.gui.show_track_reservation) {
|
||||||
/* Get reservation, but mask track on halftile slope */
|
/* 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 (pbs & TRACK_BIT_X) {
|
||||||
if (ti->tileh == SLOPE_FLAT || ti->tileh == SLOPE_ELEVATED) {
|
if (ti->tileh == SLOPE_FLAT || ti->tileh == SLOPE_ELEVATED) {
|
||||||
DrawGroundSprite(rti->base_sprites.single_x, PALETTE_CRASH);
|
DrawGroundSprite(rti->base_sprites.single_x, PALETTE_CRASH);
|
||||||
|
@@ -1212,6 +1212,17 @@ bool AfterLoadGame()
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
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 */
|
/* Elrails got added in rev 24 */
|
||||||
if (IsSavegameVersionBefore(24)) {
|
if (IsSavegameVersionBefore(24)) {
|
||||||
RailType min_rail = RAILTYPE_ELECTRIC;
|
RailType min_rail = RAILTYPE_ELECTRIC;
|
||||||
@@ -1924,7 +1935,7 @@ bool AfterLoadGame()
|
|||||||
break;
|
break;
|
||||||
|
|
||||||
case MP_TUNNELBRIDGE: // Clear PBS reservation on tunnels/bridges
|
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;
|
break;
|
||||||
|
|
||||||
default: break;
|
default: break;
|
||||||
|
@@ -201,12 +201,11 @@ void AfterLoadCompanyStats()
|
|||||||
/* Count each tunnel/bridge TUNNELBRIDGE_TRACKBIT_FACTOR times to simulate
|
/* Count each tunnel/bridge TUNNELBRIDGE_TRACKBIT_FACTOR times to simulate
|
||||||
* the higher structural maintenance needs, and don't forget the end tiles. */
|
* 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 middle_len = GetTunnelBridgeLength(tile, other_end) * TUNNELBRIDGE_TRACKBIT_FACTOR;
|
||||||
const uint len = middle_len + (2 * TUNNELBRIDGE_TRACKBIT_FACTOR);
|
|
||||||
|
|
||||||
switch (GetTunnelBridgeTransportType(tile)) {
|
switch (GetTunnelBridgeTransportType(tile)) {
|
||||||
case TRANSPORT_RAIL:
|
case TRANSPORT_RAIL:
|
||||||
c = Company::GetIfValid(GetTileOwner(tile));
|
c = Company::GetIfValid(GetTileOwner(tile));
|
||||||
if (c != NULL) c->infrastructure.rail[GetRailType(tile)] += len;
|
if (c != NULL) c->infrastructure.rail[GetRailType(tile)] += middle_len + GetTunnelBridgeHeadOnlyRailInfrastructureCount(tile) + GetTunnelBridgeHeadOnlyRailInfrastructureCount(other_end);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case TRANSPORT_ROAD: {
|
case TRANSPORT_ROAD: {
|
||||||
@@ -216,7 +215,7 @@ void AfterLoadCompanyStats()
|
|||||||
|
|
||||||
case TRANSPORT_WATER:
|
case TRANSPORT_WATER:
|
||||||
c = Company::GetIfValid(GetTileOwner(tile));
|
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;
|
break;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
|
@@ -45,7 +45,7 @@ std::vector<uint32> _sl_xv_discardable_chunk_ids; ///< list of chunks
|
|||||||
static const uint32 _sl_xv_slxi_chunk_version = 0; ///< current version os SLXI chunk
|
static const uint32 _sl_xv_slxi_chunk_version = 0; ///< current version os SLXI chunk
|
||||||
|
|
||||||
const SlxiSubChunkInfo _sl_xv_sub_chunk_infos[] = {
|
const SlxiSubChunkInfo _sl_xv_sub_chunk_infos[] = {
|
||||||
{ 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_NULL, XSCF_NULL, 0, 0, NULL, NULL, NULL, NULL },// This is the end marker
|
{ XSLFI_NULL, XSCF_NULL, 0, 0, NULL, NULL, NULL, NULL },// This is the end marker
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@@ -312,6 +312,7 @@ struct ConstructionSettings {
|
|||||||
uint8 extra_tree_placement; ///< (dis)allow building extra trees in-game
|
uint8 extra_tree_placement; ///< (dis)allow building extra trees in-game
|
||||||
uint8 command_pause_level; ///< level/amount of commands that can't be executed while paused
|
uint8 command_pause_level; ///< level/amount of commands that can't be executed while paused
|
||||||
uint8 road_custom_bridge_heads; ///< allow construction of road custom bridge heads
|
uint8 road_custom_bridge_heads; ///< allow construction of road custom bridge heads
|
||||||
|
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?
|
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?
|
uint16 terraform_frame_burst; ///< how many tile heights may, over a short period, be terraformed?
|
||||||
|
@@ -374,22 +374,45 @@ static SigFlags ExploreSegment(Owner owner)
|
|||||||
case MP_TUNNELBRIDGE: {
|
case MP_TUNNELBRIDGE: {
|
||||||
if (GetTileOwner(tile) != owner) continue;
|
if (GetTileOwner(tile) != owner) continue;
|
||||||
if (GetTunnelBridgeTransportType(tile) != TRANSPORT_RAIL) 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 (enterdir == INVALID_DIAGDIR) { // incoming from the wormhole
|
if (enterdir == INVALID_DIAGDIR) { // incoming from the wormhole
|
||||||
if (!(flags & SF_TRAIN) && HasVehicleOnPos(tile, NULL, &TrainOnTileEnum)) flags |= SF_TRAIN;
|
if (!(flags & SF_TRAIN) && check_train_present(tunnel_bridge_dir)) flags |= SF_TRAIN;
|
||||||
enterdir = dir;
|
enterdir = tunnel_bridge_dir;
|
||||||
exitdir = ReverseDiagDir(dir);
|
} else if (enterdir != tunnel_bridge_dir) { // NOT incoming from the wormhole!
|
||||||
tile += TileOffsByDiagDir(exitdir); // just skip to next tile
|
if (tracks_masked == TRACK_BIT_NONE) continue; // no incidating track
|
||||||
} else { // NOT incoming from the wormhole!
|
if (!(flags & SF_TRAIN) && check_train_present(enterdir)) flags |= SF_TRAIN;
|
||||||
if (ReverseDiagDir(enterdir) != dir) continue;
|
}
|
||||||
if (!(flags & SF_TRAIN) && HasVehicleOnPos(tile, NULL, &TrainOnTileEnum)) flags |= SF_TRAIN;
|
for (DiagDirection dir = DIAGDIR_BEGIN; dir < DIAGDIR_END; dir++) { // test all possible exit directions
|
||||||
tile = GetOtherTunnelBridgeEnd(tile); // just skip to exit tile
|
if (dir != enterdir && (tracks & _enterdir_to_trackbits[dir])) { // any track incidating?
|
||||||
enterdir = INVALID_DIAGDIR;
|
if (dir == tunnel_bridge_dir) {
|
||||||
exitdir = INVALID_DIAGDIR;
|
if (!MaybeAddToTodoSet(GetOtherTunnelBridgeEnd(tile), INVALID_DIAGDIR, tile, INVALID_DIAGDIR)) return flags | SF_FULL;
|
||||||
|
} 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)) return flags | SF_FULL;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
break;
|
}
|
||||||
|
continue; // continue the while() loop
|
||||||
|
}
|
||||||
|
|
||||||
default:
|
default:
|
||||||
continue; // continue the while() loop
|
continue; // continue the while() loop
|
||||||
@@ -489,16 +512,20 @@ static SigSegState UpdateSignalsInBuffer(Owner owner)
|
|||||||
* train entering/leaving block, train leaving depot...
|
* train entering/leaving block, train leaving depot...
|
||||||
*/
|
*/
|
||||||
switch (GetTileType(tile)) {
|
switch (GetTileType(tile)) {
|
||||||
case MP_TUNNELBRIDGE:
|
case MP_TUNNELBRIDGE: {
|
||||||
/* 'optimization assert' - do not try to update signals when it is not needed */
|
/* 'optimization assert' - do not try to update signals when it is not needed */
|
||||||
assert(GetTunnelBridgeTransportType(tile) == TRANSPORT_RAIL);
|
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
|
_tbdset.Add(tile, INVALID_DIAGDIR); // we can safely start from wormhole centre
|
||||||
_tbdset.Add(GetOtherTunnelBridgeEnd(tile), INVALID_DIAGDIR);
|
_tbdset.Add(GetOtherTunnelBridgeEnd(tile), INVALID_DIAGDIR);
|
||||||
break;
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
/* FALL THROUGH */
|
||||||
case MP_RAILWAY:
|
case MP_RAILWAY:
|
||||||
if (IsRailDepot(tile)) {
|
if (IsRailDepotTile(tile)) {
|
||||||
/* 'optimization assert' do not try to update signals in other cases */
|
/* 'optimization assert' do not try to update signals in other cases */
|
||||||
assert(dir == INVALID_DIAGDIR || dir == GetRailDepotDirection(tile));
|
assert(dir == INVALID_DIAGDIR || dir == GetRailDepotDirection(tile));
|
||||||
_tbdset.Add(tile, INVALID_DIAGDIR); // start from depot inside
|
_tbdset.Add(tile, INVALID_DIAGDIR); // start from depot inside
|
||||||
@@ -591,8 +618,13 @@ void AddTrackToSignalBuffer(TileIndex tile, Track track, Owner owner)
|
|||||||
|
|
||||||
_last_owner = owner;
|
_last_owner = owner;
|
||||||
|
|
||||||
_globset.Add(tile, _search_dir_1[track]);
|
DiagDirection wormhole_dir = IsTileType(tile, MP_TUNNELBRIDGE) ? GetTunnelBridgeDirection(tile) : INVALID_DIAGDIR;
|
||||||
_globset.Add(tile, _search_dir_2[track]);
|
|
||||||
|
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) {
|
if (_globset.Items() >= SIG_GLOB_UPDATE) {
|
||||||
/* too many items, force update */
|
/* too many items, force update */
|
||||||
|
@@ -1238,6 +1238,15 @@ str = STR_CONFIG_SETTING_ENABLE_ROAD_CUSTOM_BRIDGE_HEADS
|
|||||||
strhelp = STR_CONFIG_SETTING_ENABLE_ROAD_CUSTOM_BRIDGE_HEADS_HELPTEXT
|
strhelp = STR_CONFIG_SETTING_ENABLE_ROAD_CUSTOM_BRIDGE_HEADS_HELPTEXT
|
||||||
patxname = ""custom_bridge_heads.construction.road_custom_bridge_heads""
|
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]
|
[SDT_BOOL]
|
||||||
base = GameSettings
|
base = GameSettings
|
||||||
var = station.adjacent_stations
|
var = station.adjacent_stations
|
||||||
|
@@ -246,7 +246,7 @@ protected: // These functions should not be called outside acceleration code.
|
|||||||
inline byte GetAirDragArea() const
|
inline byte GetAirDragArea() const
|
||||||
{
|
{
|
||||||
/* Air drag is higher in tunnels due to the limited cross-section. */
|
/* 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;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@@ -427,7 +427,7 @@ int Train::GetCurrentMaxSpeed() const
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* Vehicle is on the middle part of a bridge. */
|
/* 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);
|
max_speed = min(max_speed, GetBridgeSpec(GetBridgeType(u->tile))->speed);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1568,17 +1568,17 @@ static void UpdateStatusAfterSwap(Train *v)
|
|||||||
if (v->track != TRACK_BIT_DEPOT) v->direction = ReverseDir(v->direction);
|
if (v->track != TRACK_BIT_DEPOT) v->direction = ReverseDir(v->direction);
|
||||||
|
|
||||||
/* Call the proper EnterTile function unless we are in a wormhole. */
|
/* 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);
|
VehicleEnterTile(v, v->tile, v->x_pos, v->y_pos);
|
||||||
} else {
|
} 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).
|
* 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,
|
* 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. */
|
* when we shouldn't have. Check if this is the case. */
|
||||||
TileIndex vt = TileVirtXY(v->x_pos, v->y_pos);
|
TileIndex vt = TileVirtXY(v->x_pos, v->y_pos);
|
||||||
if (IsTileType(vt, MP_TUNNELBRIDGE)) {
|
if (IsTileType(vt, MP_TUNNELBRIDGE)) {
|
||||||
VehicleEnterTile(v, vt, v->x_pos, v->y_pos);
|
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
|
/* We have just left the wormhole, possibly set the
|
||||||
* "goingdown" bit. UpdateInclination() can be used
|
* "goingdown" bit. UpdateInclination() can be used
|
||||||
* because we are at the border of the tile. */
|
* because we are at the border of the tile. */
|
||||||
@@ -1875,7 +1875,7 @@ void ReverseTrainDirection(Train *v)
|
|||||||
/* TrainExitDir does not always produce the desired dir for depots and
|
/* TrainExitDir does not always produce the desired dir for depots and
|
||||||
* tunnels/bridges that is needed for UpdateSignalsOnSegment. */
|
* tunnels/bridges that is needed for UpdateSignalsOnSegment. */
|
||||||
DiagDirection dir = TrainExitDir(v->direction, v->track);
|
DiagDirection dir = TrainExitDir(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 (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
|
/* If we are currently on a tile with conventional signals, we can't treat the
|
||||||
@@ -2216,17 +2216,15 @@ static bool CheckTrainStayInDepot(Train *v)
|
|||||||
*/
|
*/
|
||||||
static void ClearPathReservation(const Train *v, TileIndex tile, Trackdir track_dir)
|
static void ClearPathReservation(const Train *v, TileIndex tile, Trackdir track_dir)
|
||||||
{
|
{
|
||||||
DiagDirection dir = TrackdirToExitdir(track_dir);
|
|
||||||
|
|
||||||
if (IsTileType(tile, MP_TUNNELBRIDGE)) {
|
if (IsTileType(tile, MP_TUNNELBRIDGE)) {
|
||||||
/* Are we just leaving a tunnel/bridge? */
|
/* Are we just leaving a tunnel/bridge? */
|
||||||
if (GetTunnelBridgeDirection(tile) == ReverseDiagDir(dir)) {
|
if (TrackdirExitsTunnelBridge(tile, track_dir)) {
|
||||||
TileIndex end = GetOtherTunnelBridgeEnd(tile);
|
TileIndex end = GetOtherTunnelBridgeEnd(tile);
|
||||||
|
|
||||||
if (TunnelBridgeIsFree(tile, end, v).Succeeded()) {
|
if (TunnelBridgeIsFree(tile, end, v, true).Succeeded()) {
|
||||||
/* Free the reservation only if no other train is on the tiles. */
|
/* Free the reservation only if no other train is on the tiles. */
|
||||||
SetTunnelBridgeReservation(tile, false);
|
UnreserveAcrossRailTunnelBridge(tile);
|
||||||
SetTunnelBridgeReservation(end, false);
|
UnreserveAcrossRailTunnelBridge(end);
|
||||||
|
|
||||||
if (_settings_client.gui.show_track_reservation) {
|
if (_settings_client.gui.show_track_reservation) {
|
||||||
if (IsBridge(tile)) {
|
if (IsBridge(tile)) {
|
||||||
@@ -2237,8 +2235,11 @@ static void ClearPathReservation(const Train *v, TileIndex tile, Trackdir track_
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
} else if (TrackdirToExitdir(track_dir) != GetTunnelBridgeDirection(tile)) {
|
||||||
|
UnreserveRailTrack(tile, TrackdirToTrack(track_dir));
|
||||||
}
|
}
|
||||||
} else if (IsRailStationTile(tile)) {
|
} else if (IsRailStationTile(tile)) {
|
||||||
|
DiagDirection dir = TrackdirToExitdir(track_dir);
|
||||||
TileIndex new_tile = TileAddByDiagDir(tile, dir);
|
TileIndex new_tile = TileAddByDiagDir(tile, dir);
|
||||||
/* If the new tile is not a further tile of the same station, we
|
/* If the new tile is not a further tile of the same station, we
|
||||||
* clear the reservation for the whole platform. */
|
* clear the reservation for the whole platform. */
|
||||||
@@ -2764,7 +2765,7 @@ bool TryPathReserve(Train *v, bool mark_as_stuck, bool first_tile_okay)
|
|||||||
static bool CheckReverseTrain(const Train *v)
|
static bool CheckReverseTrain(const Train *v)
|
||||||
{
|
{
|
||||||
if (_settings_game.difficulty.line_reverse_mode != 0 ||
|
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)) {
|
!(v->direction & 1)) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
@@ -2924,15 +2925,18 @@ static bool TrainMovedChangeSignals(TileIndex tile, DiagDirection dir)
|
|||||||
void Train::ReserveTrackUnderConsist() const
|
void Train::ReserveTrackUnderConsist() const
|
||||||
{
|
{
|
||||||
for (const Train *u = this; u != NULL; u = u->Next()) {
|
for (const Train *u = this; u != NULL; u = u->Next()) {
|
||||||
switch (u->track) {
|
if (u->track & TRACK_BIT_WORMHOLE) {
|
||||||
case TRACK_BIT_WORMHOLE:
|
if (IsRailCustomBridgeHeadTile(u->tile)) {
|
||||||
|
/* reserve the first available track */
|
||||||
|
TrackBits bits = GetAcrossBridgePossibleTrackBits(u->tile) & GetCustomBridgeHeadTrackBits(u->tile);
|
||||||
|
Track first_track = RemoveFirstTrack(&bits);
|
||||||
|
assert(IsValidTrack(first_track));
|
||||||
|
TryReserveRailTrack(u->tile, first_track);
|
||||||
|
} else {
|
||||||
TryReserveRailTrack(u->tile, DiagDirToDiagTrack(GetTunnelBridgeDirection(u->tile)));
|
TryReserveRailTrack(u->tile, DiagDirToDiagTrack(GetTunnelBridgeDirection(u->tile)));
|
||||||
break;
|
}
|
||||||
case TRACK_BIT_DEPOT:
|
} else if (u->track != TRACK_BIT_DEPOT) {
|
||||||
break;
|
|
||||||
default:
|
|
||||||
TryReserveRailTrack(u->tile, TrackBitsToTrack(u->track));
|
TryReserveRailTrack(u->tile, TrackBitsToTrack(u->track));
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -2957,7 +2961,7 @@ uint Train::Crash(bool flooded)
|
|||||||
if (IsTileType(v->tile, MP_TUNNELBRIDGE)) {
|
if (IsTileType(v->tile, MP_TUNNELBRIDGE)) {
|
||||||
/* ClearPathReservation will not free the wormhole exit
|
/* ClearPathReservation will not free the wormhole exit
|
||||||
* if the train has just entered the wormhole. */
|
* if the train has just entered the wormhole. */
|
||||||
SetTunnelBridgeReservation(GetOtherTunnelBridgeEnd(v->tile), false);
|
UnreserveAcrossRailTunnelBridge(GetOtherTunnelBridgeEnd(v->tile));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -3064,14 +3068,14 @@ static bool CheckTrainCollision(Train *v)
|
|||||||
/* can't collide in depot */
|
/* can't collide in depot */
|
||||||
if (v->track == TRACK_BIT_DEPOT) return false;
|
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;
|
TrainCollideChecker tcc;
|
||||||
tcc.v = v;
|
tcc.v = v;
|
||||||
tcc.num = 0;
|
tcc.num = 0;
|
||||||
|
|
||||||
/* find colliding vehicles */
|
/* find colliding vehicles */
|
||||||
if (v->track == TRACK_BIT_WORMHOLE) {
|
if (v->track & TRACK_BIT_WORMHOLE) {
|
||||||
FindVehicleOnPos(v->tile, &tcc, FindTrainCollideEnum);
|
FindVehicleOnPos(v->tile, &tcc, FindTrainCollideEnum);
|
||||||
FindVehicleOnPos(GetOtherTunnelBridgeEnd(v->tile), &tcc, FindTrainCollideEnum);
|
FindVehicleOnPos(GetOtherTunnelBridgeEnd(v->tile), &tcc, FindTrainCollideEnum);
|
||||||
} else {
|
} else {
|
||||||
@@ -3116,14 +3120,37 @@ bool TrainController(Train *v, Vehicle *nomove, bool reverse)
|
|||||||
Train *first = v->First();
|
Train *first = v->First();
|
||||||
Train *prev;
|
Train *prev;
|
||||||
bool direction_changed = false; // has direction of any part changed?
|
bool direction_changed = false; // has direction of any part changed?
|
||||||
|
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;
|
||||||
|
};
|
||||||
|
|
||||||
/* For every vehicle after and including the given vehicle */
|
/* For every vehicle after and including the given vehicle */
|
||||||
for (prev = v->Previous(); v != nomove; prev = v, v = v->Next()) {
|
for (prev = v->Previous(); v != nomove; prev = v, v = v->Next()) {
|
||||||
|
old_direction = v->direction;
|
||||||
|
old_trackbits = v->track;
|
||||||
DiagDirection enterdir = DIAGDIR_BEGIN;
|
DiagDirection enterdir = DIAGDIR_BEGIN;
|
||||||
bool update_signals_crossing = false; // will we update signals or crossing state?
|
bool update_signals_crossing = false; // will we update signals or crossing state?
|
||||||
|
|
||||||
GetNewVehiclePosResult gp = GetNewVehiclePos(v);
|
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 */
|
/* Not inside tunnel */
|
||||||
if (gp.old_tile == gp.new_tile) {
|
if (gp.old_tile == gp.new_tile) {
|
||||||
/* Staying in the old tile */
|
/* Staying in the old tile */
|
||||||
@@ -3145,6 +3172,7 @@ bool TrainController(Train *v, Vehicle *nomove, bool reverse)
|
|||||||
/* The new position is the end of the platform */
|
/* The new position is the end of the platform */
|
||||||
TrainEnterStation(v, r >> VETS_STATION_ID_OFFSET);
|
TrainEnterStation(v, r >> VETS_STATION_ID_OFFSET);
|
||||||
}
|
}
|
||||||
|
if (old_direction != v->direction) notify_direction_changed(old_direction, v->direction);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
/* A new tile is about to be entered. */
|
/* A new tile is about to be entered. */
|
||||||
@@ -3153,9 +3181,11 @@ bool TrainController(Train *v, Vehicle *nomove, bool reverse)
|
|||||||
enterdir = DiagdirBetweenTiles(gp.old_tile, gp.new_tile);
|
enterdir = DiagdirBetweenTiles(gp.old_tile, gp.new_tile);
|
||||||
assert(IsValidDiagDirection(enterdir));
|
assert(IsValidDiagDirection(enterdir));
|
||||||
|
|
||||||
|
enter_new_tile:
|
||||||
|
|
||||||
/* Get the status of the tracks in the new tile and mask
|
/* Get the status of the tracks in the new tile and mask
|
||||||
* away the bits that aren't reachable. */
|
* 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 reachable_trackdirs = DiagdirReachesTrackdirs(enterdir);
|
||||||
|
|
||||||
TrackdirBits trackdirbits = TrackStatusToTrackdirBits(ts) & reachable_trackdirs;
|
TrackdirBits trackdirbits = TrackStatusToTrackdirBits(ts) & reachable_trackdirs;
|
||||||
@@ -3165,7 +3195,11 @@ bool TrainController(Train *v, Vehicle *nomove, bool reverse)
|
|||||||
if (_settings_game.pf.forbid_90_deg && prev == NULL) {
|
if (_settings_game.pf.forbid_90_deg && prev == NULL) {
|
||||||
/* We allow wagons to make 90 deg turns, because forbid_90_deg
|
/* We allow wagons to make 90 deg turns, because forbid_90_deg
|
||||||
* can be switched on halfway a turn */
|
* can be switched on halfway a turn */
|
||||||
|
if (!(v->track & TRACK_BIT_WORMHOLE)) {
|
||||||
bits &= ~TrackCrossesTracks(FindFirstTrack(v->track));
|
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;
|
if (bits == TRACK_BIT_NONE) goto invalid_rail;
|
||||||
@@ -3240,9 +3274,9 @@ bool TrainController(Train *v, Vehicle *nomove, bool reverse)
|
|||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
/* The wagon is active, simply follow the prev vehicle. */
|
/* 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 */
|
/* 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.
|
/* Vehicles entering tunnels enter the wormhole earlier than for bridges.
|
||||||
* However, just choose the track into the wormhole. */
|
* However, just choose the track into the wormhole. */
|
||||||
assert(IsTunnel(prev->tile));
|
assert(IsTunnel(prev->tile));
|
||||||
@@ -3264,7 +3298,7 @@ bool TrainController(Train *v, Vehicle *nomove, bool reverse)
|
|||||||
{TRACK_BIT_NONE, TRACK_BIT_RIGHT, TRACK_BIT_X, TRACK_BIT_UPPER},
|
{TRACK_BIT_NONE, TRACK_BIT_RIGHT, TRACK_BIT_X, TRACK_BIT_UPPER},
|
||||||
{TRACK_BIT_RIGHT, TRACK_BIT_NONE, TRACK_BIT_LOWER, TRACK_BIT_Y }
|
{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));
|
assert(IsValidDiagDirection(exitdir));
|
||||||
chosen_track = _connecting_track[enterdir][exitdir];
|
chosen_track = _connecting_track[enterdir][exitdir];
|
||||||
}
|
}
|
||||||
@@ -3284,7 +3318,7 @@ bool TrainController(Train *v, Vehicle *nomove, bool reverse)
|
|||||||
Direction chosen_dir = (Direction)b[2];
|
Direction chosen_dir = (Direction)b[2];
|
||||||
|
|
||||||
/* Call the landscape function and tell it that the vehicle entered the tile */
|
/* 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)) {
|
if (HasBit(r, VETS_CANNOT_ENTER)) {
|
||||||
goto invalid_rail;
|
goto invalid_rail;
|
||||||
}
|
}
|
||||||
@@ -3315,12 +3349,7 @@ bool TrainController(Train *v, Vehicle *nomove, bool reverse)
|
|||||||
update_signals_crossing = true;
|
update_signals_crossing = true;
|
||||||
|
|
||||||
if (chosen_dir != v->direction) {
|
if (chosen_dir != v->direction) {
|
||||||
if (prev == NULL && _settings_game.vehicle.train_acceleration_model == AM_ORIGINAL) {
|
notify_direction_changed(v->direction, chosen_dir);
|
||||||
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;
|
|
||||||
v->direction = chosen_dir;
|
v->direction = chosen_dir;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -3343,6 +3372,10 @@ bool TrainController(Train *v, Vehicle *nomove, bool reverse)
|
|||||||
} else {
|
} else {
|
||||||
if (IsTileType(gp.new_tile, MP_TUNNELBRIDGE) && HasBit(VehicleEnterTile(v, gp.new_tile, gp.x, gp.y), VETS_ENTERED_WORMHOLE)) {
|
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. */
|
/* Perform look-ahead on tunnel exit. */
|
||||||
|
if (IsRailCustomBridgeHeadTile(gp.new_tile)) {
|
||||||
|
enterdir = ReverseDiagDir(GetTunnelBridgeDirection(gp.new_tile));
|
||||||
|
goto enter_new_tile;
|
||||||
|
}
|
||||||
if (v->IsFrontEngine()) {
|
if (v->IsFrontEngine()) {
|
||||||
TryReserveRailTrack(gp.new_tile, DiagDirToDiagTrack(GetTunnelBridgeDirection(gp.new_tile)));
|
TryReserveRailTrack(gp.new_tile, DiagDirToDiagTrack(GetTunnelBridgeDirection(gp.new_tile)));
|
||||||
CheckNextTrainTile(v);
|
CheckNextTrainTile(v);
|
||||||
@@ -3416,6 +3449,11 @@ invalid_rail:
|
|||||||
if (prev != NULL) error("Disconnecting train");
|
if (prev != NULL) error("Disconnecting train");
|
||||||
|
|
||||||
reverse_train_direction:
|
reverse_train_direction:
|
||||||
|
if ((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) {
|
if (reverse) {
|
||||||
v->wait_counter = 0;
|
v->wait_counter = 0;
|
||||||
v->cur_speed = 0;
|
v->cur_speed = 0;
|
||||||
@@ -3426,6 +3464,21 @@ reverse_train_direction:
|
|||||||
return false;
|
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
|
* Collect trackbits of all crashed train vehicles on a tile
|
||||||
* @param v Vehicle passed from Find/HasVehicleOnPos()
|
* @param v Vehicle passed from Find/HasVehicleOnPos()
|
||||||
@@ -3437,12 +3490,8 @@ static Vehicle *CollectTrackbitsFromCrashedVehiclesEnum(Vehicle *v, void *data)
|
|||||||
TrackBits *trackbits = (TrackBits *)data;
|
TrackBits *trackbits = (TrackBits *)data;
|
||||||
|
|
||||||
if (v->type == VEH_TRAIN && (v->vehstatus & VS_CRASHED) != 0) {
|
if (v->type == VEH_TRAIN && (v->vehstatus & VS_CRASHED) != 0) {
|
||||||
TrackBits train_tbits = Train::From(v)->track;
|
if (Train::From(v)->track != TRACK_BIT_DEPOT) {
|
||||||
if (train_tbits == TRACK_BIT_WORMHOLE) {
|
*trackbits |= GetTrackbitsFromCrashedVehicle(Train::From(v));
|
||||||
/* 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;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -3479,18 +3528,14 @@ static void DeleteLastWagon(Train *v)
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* 'v' shouldn't be accessed after it has been deleted */
|
/* 'v' shouldn't be accessed after it has been deleted */
|
||||||
TrackBits trackbits = v->track;
|
const TrackBits orig_trackbits = v->track;
|
||||||
TileIndex tile = v->tile;
|
TrackBits trackbits = GetTrackbitsFromCrashedVehicle(v);
|
||||||
Owner owner = v->owner;
|
const TileIndex tile = v->tile;
|
||||||
|
const Owner owner = v->owner;
|
||||||
|
|
||||||
delete v;
|
delete v;
|
||||||
v = NULL; // make sure nobody will try to read 'v' anymore
|
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);
|
Track track = TrackBitsToTrack(trackbits);
|
||||||
if (HasReservedTracks(tile, trackbits)) {
|
if (HasReservedTracks(tile, trackbits)) {
|
||||||
UnreserveRailTrack(tile, track);
|
UnreserveRailTrack(tile, track);
|
||||||
@@ -3509,7 +3554,7 @@ static void DeleteLastWagon(Train *v)
|
|||||||
if (IsLevelCrossingTile(tile)) UpdateLevelCrossing(tile);
|
if (IsLevelCrossingTile(tile)) UpdateLevelCrossing(tile);
|
||||||
|
|
||||||
/* Update signals */
|
/* Update signals */
|
||||||
if (IsTileType(tile, MP_TUNNELBRIDGE) || IsRailDepotTile(tile)) {
|
if ((orig_trackbits & TRACK_BIT_WORMHOLE) || IsRailDepotTile(tile)) {
|
||||||
UpdateSignalsOnSegment(tile, INVALID_DIAGDIR, owner);
|
UpdateSignalsOnSegment(tile, INVALID_DIAGDIR, owner);
|
||||||
} else {
|
} else {
|
||||||
SetSignalsOnBothDir(tile, track, owner);
|
SetSignalsOnBothDir(tile, track, owner);
|
||||||
@@ -3533,7 +3578,7 @@ static void ChangeTrainDirRandomly(Train *v)
|
|||||||
/* Refrain from updating the z position of the vehicle when on
|
/* Refrain from updating the z position of the vehicle when on
|
||||||
* a bridge, because UpdateInclination() will put the vehicle under
|
* a bridge, because UpdateInclination() will put the vehicle under
|
||||||
* the bridge in that case */
|
* the bridge in that case */
|
||||||
if (v->track != TRACK_BIT_WORMHOLE) {
|
if (!(v->track & TRACK_BIT_WORMHOLE)) {
|
||||||
v->UpdatePosition();
|
v->UpdatePosition();
|
||||||
v->UpdateInclination(false, true);
|
v->UpdateInclination(false, true);
|
||||||
} else {
|
} else {
|
||||||
@@ -3648,7 +3693,7 @@ static bool TrainApproachingLineEnd(Train *v, bool signal, bool reverse)
|
|||||||
static bool TrainCanLeaveTile(const Train *v)
|
static bool TrainCanLeaveTile(const Train *v)
|
||||||
{
|
{
|
||||||
/* Exit if inside a tunnel/bridge or a depot */
|
/* 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;
|
TileIndex tile = v->tile;
|
||||||
|
|
||||||
@@ -3656,6 +3701,13 @@ static bool TrainCanLeaveTile(const Train *v)
|
|||||||
if (IsTileType(tile, MP_TUNNELBRIDGE)) {
|
if (IsTileType(tile, MP_TUNNELBRIDGE)) {
|
||||||
DiagDirection dir = GetTunnelBridgeDirection(tile);
|
DiagDirection dir = GetTunnelBridgeDirection(tile);
|
||||||
if (DiagDirToDir(dir) == v->direction) return false;
|
if (DiagDirToDir(dir) == v->direction) return false;
|
||||||
|
if (IsRailCustomBridgeHeadTile(tile) && TrainExitDir(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? */
|
/* entering a depot? */
|
||||||
@@ -4042,6 +4094,8 @@ Trackdir Train::GetVehicleTrackdir() const
|
|||||||
if (this->track == TRACK_BIT_WORMHOLE) {
|
if (this->track == TRACK_BIT_WORMHOLE) {
|
||||||
/* train in tunnel or on bridge, so just use his direction and assume a diagonal track */
|
/* train in tunnel or on bridge, so just use his direction and assume a diagonal track */
|
||||||
return DiagDirToDiagTrackdir(DirToDiagDir(this->direction));
|
return DiagDirToDiagTrackdir(DirToDiagDir(this->direction));
|
||||||
|
} else if (this->track & TRACK_BIT_WORMHOLE) {
|
||||||
|
return TrackDirectionToTrackdir(FindFirstTrack(this->track & TRACK_BIT_MASK), this->direction);
|
||||||
}
|
}
|
||||||
|
|
||||||
return TrackDirectionToTrackdir(FindFirstTrack(this->track), this->direction);
|
return TrackDirectionToTrackdir(FindFirstTrack(this->track), this->direction);
|
||||||
|
@@ -37,6 +37,40 @@ static inline bool IsTunnelTile(TileIndex t)
|
|||||||
return IsTileType(t, MP_TUNNELBRIDGE) && IsTunnel(t);
|
return IsTileType(t, MP_TUNNELBRIDGE) && IsTunnel(t);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 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);
|
TileIndex GetOtherTunnelEnd(TileIndex);
|
||||||
bool IsTunnelInWay(TileIndex, int z);
|
bool IsTunnelInWay(TileIndex, int z);
|
||||||
bool IsTunnelInWayDir(TileIndex tile, int z, DiagDirection dir);
|
bool IsTunnelInWayDir(TileIndex tile, int z, DiagDirection dir);
|
||||||
|
@@ -52,6 +52,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) */
|
/** Z position of the bridge sprites relative to bridge height (downwards) */
|
||||||
static const int BRIDGE_Z_START = 3;
|
static const int BRIDGE_Z_START = 3;
|
||||||
|
|
||||||
|
extern void DrawTrackBits(TileInfo *ti, TrackBits track);
|
||||||
extern void DrawRoadBits(TileInfo *ti);
|
extern void DrawRoadBits(TileInfo *ti);
|
||||||
extern const RoadBits _invalid_tileh_slopes_road[2][15];
|
extern const RoadBits _invalid_tileh_slopes_road[2][15];
|
||||||
|
|
||||||
@@ -315,7 +316,6 @@ CommandCost CmdBuildBridge(TileIndex end_tile, DoCommandFlag flags, uint32 p1, u
|
|||||||
int z_end;
|
int z_end;
|
||||||
Slope tileh_start = GetTileSlope(tile_start, &z_start);
|
Slope tileh_start = GetTileSlope(tile_start, &z_start);
|
||||||
Slope tileh_end = GetTileSlope(tile_end, &z_end);
|
Slope tileh_end = GetTileSlope(tile_end, &z_end);
|
||||||
bool pbs_reservation = false;
|
|
||||||
|
|
||||||
CommandCost terraform_cost_north = CheckBridgeSlopeNorth(direction, &tileh_start, &z_start);
|
CommandCost terraform_cost_north = CheckBridgeSlopeNorth(direction, &tileh_start, &z_start);
|
||||||
CommandCost terraform_cost_south = CheckBridgeSlopeSouth(direction, &tileh_end, &z_end);
|
CommandCost terraform_cost_south = CheckBridgeSlopeSouth(direction, &tileh_end, &z_end);
|
||||||
@@ -369,15 +369,6 @@ CommandCost CmdBuildBridge(TileIndex end_tile, DoCommandFlag flags, uint32 p1, u
|
|||||||
is_new_owner = (owner == OWNER_NONE);
|
is_new_owner = (owner == OWNER_NONE);
|
||||||
if (is_new_owner) owner = company;
|
if (is_new_owner) owner = company;
|
||||||
|
|
||||||
switch (transport_type) {
|
|
||||||
case TRANSPORT_RAIL:
|
|
||||||
/* Keep the reservation, the path stays valid. */
|
|
||||||
pbs_reservation = HasTunnelBridgeReservation(tile_start);
|
|
||||||
break;
|
|
||||||
|
|
||||||
default: break;
|
|
||||||
}
|
|
||||||
|
|
||||||
is_upgrade = true;
|
is_upgrade = true;
|
||||||
} else {
|
} else {
|
||||||
/* Build a new bridge. */
|
/* Build a new bridge. */
|
||||||
@@ -491,11 +482,9 @@ CommandCost CmdBuildBridge(TileIndex end_tile, DoCommandFlag flags, uint32 p1, u
|
|||||||
switch (transport_type) {
|
switch (transport_type) {
|
||||||
case TRANSPORT_RAIL:
|
case TRANSPORT_RAIL:
|
||||||
/* Add to company infrastructure count if required. */
|
/* 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_start, owner, bridge_type, dir, railtype);
|
MakeRailBridgeRamp(tile_end, owner, bridge_type, ReverseDiagDir(dir), railtype, is_upgrade);
|
||||||
MakeRailBridgeRamp(tile_end, owner, bridge_type, ReverseDiagDir(dir), railtype);
|
if (is_new_owner && c != NULL) c->infrastructure.rail[railtype] += (bridge_len * TUNNELBRIDGE_TRACKBIT_FACTOR) + GetTunnelBridgeHeadOnlyRailInfrastructureCount(tile_start) + GetTunnelBridgeHeadOnlyRailInfrastructureCount(tile_end);
|
||||||
SetTunnelBridgeReservation(tile_start, pbs_reservation);
|
|
||||||
SetTunnelBridgeReservation(tile_end, pbs_reservation);
|
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case TRANSPORT_ROAD: {
|
case TRANSPORT_ROAD: {
|
||||||
@@ -834,7 +823,7 @@ static CommandCost DoClearTunnel(TileIndex tile, DoCommandFlag flags)
|
|||||||
Owner owner = GetTileOwner(tile);
|
Owner owner = GetTileOwner(tile);
|
||||||
|
|
||||||
Train *v = NULL;
|
Train *v = NULL;
|
||||||
if (HasTunnelBridgeReservation(tile)) {
|
if (HasTunnelReservation(tile)) {
|
||||||
v = GetTrainForReservation(tile, track);
|
v = GetTrainForReservation(tile, track);
|
||||||
if (v != NULL) FreeTrainTrackReservation(v);
|
if (v != NULL) FreeTrainTrackReservation(v);
|
||||||
}
|
}
|
||||||
@@ -909,24 +898,48 @@ static CommandCost DoClearBridge(TileIndex tile, DoCommandFlag flags)
|
|||||||
ChangeTownRating(t, RATING_TUNNEL_BRIDGE_DOWN_STEP, RATING_TUNNEL_BRIDGE_MINIMUM, 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];
|
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) {
|
if (flags & DC_EXEC) {
|
||||||
/* read this value before actual removal of bridge */
|
/* read this value before actual removal of bridge */
|
||||||
bool rail = GetTunnelBridgeTransportType(tile) == TRANSPORT_RAIL;
|
|
||||||
Owner owner = GetTileOwner(tile);
|
Owner owner = GetTileOwner(tile);
|
||||||
int height = GetBridgeHeight(tile);
|
int height = GetBridgeHeight(tile);
|
||||||
Train *v = NULL;
|
SmallVector<Train *, 2> vehicles_affected;
|
||||||
|
|
||||||
if (rail && HasTunnelBridgeReservation(tile)) {
|
if (rail) {
|
||||||
v = GetTrainForReservation(tile, DiagDirToDiagTrack(direction));
|
auto find_train_reservations = [&vehicles_affected](TileIndex tile) {
|
||||||
if (v != NULL) FreeTrainTrackReservation(v);
|
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. */
|
/* Update company infrastructure counts. */
|
||||||
if (rail) {
|
if (rail) {
|
||||||
if (Company::IsValidID(owner)) Company::Get(owner)->infrastructure.rail[GetRailType(tile)] -= len * TUNNELBRIDGE_TRACKBIT_FACTOR;
|
if (Company::IsValidID(owner)) Company::Get(owner)->infrastructure.rail[GetRailType(tile)] -= (middle_len * TUNNELBRIDGE_TRACKBIT_FACTOR) + GetTunnelBridgeHeadOnlyRailInfrastructureCount(tile) + GetTunnelBridgeHeadOnlyRailInfrastructureCount(endtile);
|
||||||
} else if (GetTunnelBridgeTransportType(tile) == TRANSPORT_ROAD) {
|
} else if (GetTunnelBridgeTransportType(tile) == TRANSPORT_ROAD) {
|
||||||
SubtractRoadTunnelBridgeInfrastructure(tile, endtile);
|
SubtractRoadTunnelBridgeInfrastructure(tile, endtile);
|
||||||
} else { // Aqueduct
|
} else { // Aqueduct
|
||||||
@@ -948,18 +961,28 @@ static CommandCost DoClearBridge(TileIndex tile, DoCommandFlag flags)
|
|||||||
|
|
||||||
if (rail) {
|
if (rail) {
|
||||||
/* cannot use INVALID_DIAGDIR for signal update because the bridge doesn't exist anymore */
|
/* 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);
|
auto notify_track_change = [owner](TileIndex tile, DiagDirection direction, TrackBits tracks) {
|
||||||
YapfNotifyTrackLayoutChange(tile, track);
|
auto check_dir = [&](DiagDirection d) {
|
||||||
YapfNotifyTrackLayoutChange(endtile, track);
|
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;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -1202,7 +1225,7 @@ static void DrawTile_TunnelBridge(TileInfo *ti)
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* PBS debugging, draw reserved tracks darker */
|
/* 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()) {
|
if (rti->UsesOverlay()) {
|
||||||
SpriteID overlay = GetCustomRailSprite(rti, ti->tile, RTSG_OVERLAY);
|
SpriteID overlay = GetCustomRailSprite(rti, ti->tile, RTSG_OVERLAY);
|
||||||
DrawGroundSprite(overlay + RTO_X + DiagDirToAxis(tunnelbridge_direction), PALETTE_CRASH);
|
DrawGroundSprite(overlay + RTO_X + DiagDirToAxis(tunnelbridge_direction), PALETTE_CRASH);
|
||||||
@@ -1241,6 +1264,14 @@ static void DrawTile_TunnelBridge(TileInfo *ti)
|
|||||||
DrawBridgeMiddle(ti);
|
DrawBridgeMiddle(ti);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
if (transport_type == TRANSPORT_RAIL && IsRailCustomBridgeHead(ti->tile)) {
|
||||||
|
DrawTrackBits(ti, GetCustomBridgeHeadTrackBits(ti->tile));
|
||||||
|
if (HasRailCatenaryDrawn(GetRailType(ti->tile))) {
|
||||||
|
DrawRailCatenary(ti);
|
||||||
|
}
|
||||||
|
DrawBridgeMiddle(ti);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
const PalSpriteID *psid;
|
const PalSpriteID *psid;
|
||||||
int base_offset;
|
int base_offset;
|
||||||
@@ -1324,7 +1355,7 @@ static void DrawTile_TunnelBridge(TileInfo *ti)
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* PBS debugging, draw reserved tracks darker */
|
/* 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()) {
|
if (rti->UsesOverlay()) {
|
||||||
SpriteID overlay = GetCustomRailSprite(rti, ti->tile, RTSG_OVERLAY);
|
SpriteID overlay = GetCustomRailSprite(rti, ti->tile, RTSG_OVERLAY);
|
||||||
if (HasBridgeFlatRamp(ti->tileh, DiagDirToAxis(tunnelbridge_direction))) {
|
if (HasBridgeFlatRamp(ti->tileh, DiagDirToAxis(tunnelbridge_direction))) {
|
||||||
@@ -1489,7 +1520,7 @@ void DrawBridgeMiddle(const TileInfo *ti)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (_game_mode != GM_MENU && _settings_client.gui.show_track_reservation && !IsInvisibilitySet(TO_BRIDGES) && HasTunnelBridgeReservation(rampnorth)) {
|
if (_game_mode != GM_MENU && _settings_client.gui.show_track_reservation && !IsInvisibilitySet(TO_BRIDGES) && (HasAcrossBridgeReservation(rampnorth) || HasAcrossBridgeReservation(rampsouth))) {
|
||||||
if (rti->UsesOverlay()) {
|
if (rti->UsesOverlay()) {
|
||||||
SpriteID overlay = GetCustomRailSprite(rti, ti->tile, RTSG_OVERLAY);
|
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));
|
AddSortableSpriteToDraw(overlay + RTO_X + axis, PALETTE_CRASH, ti->x, ti->y, 16, 16, 0, bridge_z, IsTransparencySet(TO_BRIDGES));
|
||||||
@@ -1556,7 +1587,7 @@ static int GetSlopePixelZ_TunnelBridge(TileIndex tile, uint x, uint y)
|
|||||||
/* In the tunnel entrance? */
|
/* In the tunnel entrance? */
|
||||||
if (5 <= pos && pos <= 10) return z;
|
if (5 <= pos && pos <= 10) return z;
|
||||||
} else { // IsBridge(tile)
|
} else { // IsBridge(tile)
|
||||||
if (IsRoadCustomBridgeHeadTile(tile)) {
|
if (IsCustomBridgeHeadTile(tile)) {
|
||||||
return z + TILE_HEIGHT + (IsSteepSlope(tileh) ? TILE_HEIGHT : 0);
|
return z + TILE_HEIGHT + (IsSteepSlope(tileh) ? TILE_HEIGHT : 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1587,7 +1618,7 @@ static int GetSlopePixelZ_TunnelBridge(TileIndex tile, uint x, uint y)
|
|||||||
|
|
||||||
static Foundation GetFoundation_TunnelBridge(TileIndex tile, Slope tileh)
|
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)));
|
return IsTunnel(tile) ? FOUNDATION_NONE : GetBridgeFoundation(tileh, DiagDirToAxis(GetTunnelBridgeDirection(tile)));
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1677,15 +1708,14 @@ static TrackStatus GetTileTrackStatus_TunnelBridge(TileIndex tile, TransportType
|
|||||||
|
|
||||||
DiagDirection dir = GetTunnelBridgeDirection(tile);
|
DiagDirection dir = GetTunnelBridgeDirection(tile);
|
||||||
|
|
||||||
if (mode == TRANSPORT_ROAD && IsRoadCustomBridgeHeadTile(tile)) {
|
|
||||||
if (side != INVALID_DIAGDIR && side == dir) return 0;
|
if (side != INVALID_DIAGDIR && side == dir) return 0;
|
||||||
|
if (mode == TRANSPORT_ROAD && IsRoadCustomBridgeHeadTile(tile)) {
|
||||||
TrackBits bits = TRACK_BIT_NONE;
|
TrackBits bits = TRACK_BIT_NONE;
|
||||||
if (sub_mode & ROADTYPES_TRAM) bits |= _road_trackbits[GetCustomBridgeHeadRoadBits(tile, ROADTYPE_TRAM)];
|
if (sub_mode & ROADTYPES_TRAM) bits |= _road_trackbits[GetCustomBridgeHeadRoadBits(tile, ROADTYPE_TRAM)];
|
||||||
if (sub_mode & ROADTYPES_ROAD) bits |= _road_trackbits[GetCustomBridgeHeadRoadBits(tile, ROADTYPE_ROAD)];
|
if (sub_mode & ROADTYPES_ROAD) bits |= _road_trackbits[GetCustomBridgeHeadRoadBits(tile, ROADTYPE_ROAD)];
|
||||||
return CombineTrackStatus(TrackBitsToTrackdirBits(bits), TRACKDIR_BIT_NONE);
|
return CombineTrackStatus(TrackBitsToTrackdirBits(bits), TRACKDIR_BIT_NONE);
|
||||||
}
|
}
|
||||||
if (side != INVALID_DIAGDIR && side != ReverseDiagDir(dir)) return 0;
|
return CombineTrackStatus(TrackBitsToTrackdirBits(mode == TRANSPORT_RAIL ? GetTunnelBridgeTrackBits(tile) : DiagDirToDiagTrackBits(dir)), TRACKDIR_BIT_NONE);
|
||||||
return CombineTrackStatus(TrackBitsToTrackdirBits(DiagDirToDiagTrackBits(dir)), TRACKDIR_BIT_NONE);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static void UpdateRoadTunnelBridgeInfrastructure(TileIndex begin, TileIndex end, bool add) {
|
static void UpdateRoadTunnelBridgeInfrastructure(TileIndex begin, TileIndex end, bool add) {
|
||||||
@@ -1743,9 +1773,6 @@ void SubtractRoadTunnelBridgeInfrastructure(TileIndex begin, TileIndex end) {
|
|||||||
static void ChangeTileOwner_TunnelBridge(TileIndex tile, Owner old_owner, Owner new_owner)
|
static void ChangeTileOwner_TunnelBridge(TileIndex tile, Owner old_owner, Owner new_owner)
|
||||||
{
|
{
|
||||||
const TileIndex other_end = GetOtherTunnelBridgeEnd(tile);
|
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);
|
const TransportType tt = GetTunnelBridgeTransportType(tile);
|
||||||
|
|
||||||
if (tt == TRANSPORT_ROAD && tile < other_end) {
|
if (tt == TRANSPORT_ROAD && tile < other_end) {
|
||||||
@@ -1772,9 +1799,15 @@ static void ChangeTileOwner_TunnelBridge(TileIndex tile, Owner old_owner, Owner
|
|||||||
|
|
||||||
Company *old = Company::Get(old_owner);
|
Company *old = Company::Get(old_owner);
|
||||||
if (tt == TRANSPORT_RAIL) {
|
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;
|
old->infrastructure.rail[GetRailType(tile)] -= num_pieces;
|
||||||
if (new_owner != INVALID_OWNER) Company::Get(new_owner)->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) {
|
} 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;
|
old->infrastructure.water -= num_pieces;
|
||||||
if (new_owner != INVALID_OWNER) Company::Get(new_owner)->infrastructure.water += num_pieces;
|
if (new_owner != INVALID_OWNER) Company::Get(new_owner)->infrastructure.water += num_pieces;
|
||||||
}
|
}
|
||||||
@@ -1813,23 +1846,31 @@ extern const byte _tunnel_visibility_frame[DIAGDIR_END] = {12, 8, 8, 12};
|
|||||||
|
|
||||||
static VehicleEnterTileStatus VehicleEnter_TunnelBridge(Vehicle *v, TileIndex tile, int x, int y)
|
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;
|
int z = GetSlopePixelZ(x, y) - v->z_pos;
|
||||||
|
|
||||||
if (abs(z) > 2) return VETSB_CANNOT_ENTER;
|
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)) {
|
if (IsTunnel(tile)) {
|
||||||
|
/* Direction of the vehicle */
|
||||||
|
const DiagDirection vdir = DirToDiagDir(v->direction);
|
||||||
if (v->type == VEH_TRAIN) {
|
if (v->type == VEH_TRAIN) {
|
||||||
Train *t = Train::From(v);
|
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 (t->IsFrontEngine() && frame == TUNNEL_SOUND_FRAME) {
|
||||||
if (!PlayVehicleSound(t, VSE_TUNNEL) && RailVehInfo(t->engine_type)->engclass == 0) {
|
if (!PlayVehicleSound(t, VSE_TUNNEL) && RailVehInfo(t->engine_type)->engclass == 0) {
|
||||||
SndPlayVehicleFx(SND_05_TRAIN_THROUGH_TUNNEL, v);
|
SndPlayVehicleFx(SND_05_TRAIN_THROUGH_TUNNEL, v);
|
||||||
@@ -1844,7 +1885,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 ?? */
|
/* We're at the tunnel exit ?? */
|
||||||
t->tile = tile;
|
t->tile = tile;
|
||||||
t->track = DiagDirToDiagTrackBits(vdir);
|
t->track = DiagDirToDiagTrackBits(vdir);
|
||||||
@@ -1870,7 +1911,7 @@ static VehicleEnterTileStatus VehicleEnter_TunnelBridge(Vehicle *v, TileIndex ti
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* We're at the tunnel exit ?? */
|
/* 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) {
|
||||||
rv->tile = tile;
|
rv->tile = tile;
|
||||||
rv->state = DiagDirToDiagTrackdir(vdir);
|
rv->state = DiagDirToDiagTrackdir(vdir);
|
||||||
rv->frame = frame;
|
rv->frame = frame;
|
||||||
@@ -1888,11 +1929,12 @@ static VehicleEnterTileStatus VehicleEnter_TunnelBridge(Vehicle *v, TileIndex ti
|
|||||||
first->cur_speed = min(first->cur_speed, spd);
|
first->cur_speed = min(first->cur_speed, spd);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (vdir == dir) {
|
const Direction bridge_dir = DiagDirToDir(dir);
|
||||||
/* Vehicle enters bridge at the last frame inside this tile. */
|
if (v->direction == bridge_dir) {
|
||||||
if (frame != TILE_SIZE - 1) return VETSB_CONTINUE;
|
|
||||||
switch (v->type) {
|
switch (v->type) {
|
||||||
case VEH_TRAIN: {
|
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);
|
Train *t = Train::From(v);
|
||||||
t->track = TRACK_BIT_WORMHOLE;
|
t->track = TRACK_BIT_WORMHOLE;
|
||||||
ClrBit(t->gv_flags, GVF_GOINGUP_BIT);
|
ClrBit(t->gv_flags, GVF_GOINGUP_BIT);
|
||||||
@@ -1901,6 +1943,8 @@ static VehicleEnterTileStatus VehicleEnter_TunnelBridge(Vehicle *v, TileIndex ti
|
|||||||
}
|
}
|
||||||
|
|
||||||
case VEH_ROAD: {
|
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);
|
RoadVehicle *rv = RoadVehicle::From(v);
|
||||||
if (IsRoadCustomBridgeHeadTile(tile)) {
|
if (IsRoadCustomBridgeHeadTile(tile)) {
|
||||||
RoadBits bits = ROAD_NONE;
|
RoadBits bits = ROAD_NONE;
|
||||||
@@ -1916,28 +1960,35 @@ static VehicleEnterTileStatus VehicleEnter_TunnelBridge(Vehicle *v, TileIndex ti
|
|||||||
}
|
}
|
||||||
|
|
||||||
case VEH_SHIP:
|
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;
|
Ship::From(v)->state = TRACK_BIT_WORMHOLE;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
default: NOT_REACHED();
|
default: NOT_REACHED();
|
||||||
}
|
}
|
||||||
return VETSB_ENTERED_WORMHOLE;
|
return VETSB_ENTERED_WORMHOLE;
|
||||||
} else if (vdir == ReverseDiagDir(dir)) {
|
} else if (v->direction == ReverseDir(bridge_dir)) {
|
||||||
v->tile = tile;
|
|
||||||
switch (v->type) {
|
switch (v->type) {
|
||||||
case VEH_TRAIN: {
|
case VEH_TRAIN: {
|
||||||
Train *t = Train::From(v);
|
Train *t = Train::From(v);
|
||||||
if (t->track == TRACK_BIT_WORMHOLE) {
|
if (t->track & TRACK_BIT_WORMHOLE) {
|
||||||
t->track = DiagDirToDiagTrackBits(vdir);
|
if (IsRailCustomBridgeHeadTile(tile)) {
|
||||||
|
return VETSB_ENTERED_WORMHOLE;
|
||||||
|
} else {
|
||||||
|
v->tile = tile;
|
||||||
|
t->track = DiagDirToDiagTrackBits(DirToDiagDir(v->direction));
|
||||||
|
}
|
||||||
return VETSB_ENTERED_WORMHOLE;
|
return VETSB_ENTERED_WORMHOLE;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
case VEH_ROAD: {
|
case VEH_ROAD: {
|
||||||
|
v->tile = tile;
|
||||||
RoadVehicle *rv = RoadVehicle::From(v);
|
RoadVehicle *rv = RoadVehicle::From(v);
|
||||||
if (rv->state == RVSB_WORMHOLE) {
|
if (rv->state == RVSB_WORMHOLE) {
|
||||||
rv->state = DiagDirToDiagTrackdir(vdir);
|
rv->state = DiagDirToDiagTrackdir(DirToDiagDir(v->direction));
|
||||||
rv->frame = 0;
|
rv->frame = 0;
|
||||||
return VETSB_ENTERED_WORMHOLE;
|
return VETSB_ENTERED_WORMHOLE;
|
||||||
}
|
}
|
||||||
@@ -1945,9 +1996,10 @@ static VehicleEnterTileStatus VehicleEnter_TunnelBridge(Vehicle *v, TileIndex ti
|
|||||||
}
|
}
|
||||||
|
|
||||||
case VEH_SHIP: {
|
case VEH_SHIP: {
|
||||||
|
v->tile = tile;
|
||||||
Ship *ship = Ship::From(v);
|
Ship *ship = Ship::From(v);
|
||||||
if (ship->state == TRACK_BIT_WORMHOLE) {
|
if (ship->state == TRACK_BIT_WORMHOLE) {
|
||||||
ship->state = DiagDirToDiagTrackBits(vdir);
|
ship->state = DiagDirToDiagTrackBits(DirToDiagDir(v->direction));
|
||||||
return VETSB_ENTERED_WORMHOLE;
|
return VETSB_ENTERED_WORMHOLE;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
@@ -1955,6 +2007,29 @@ static VehicleEnterTileStatus VehicleEnter_TunnelBridge(Vehicle *v, TileIndex ti
|
|||||||
|
|
||||||
default: NOT_REACHED();
|
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;
|
return VETSB_CONTINUE;
|
||||||
@@ -1980,6 +2055,16 @@ static CommandCost TerraformTile_TunnelBridge(TileIndex tile, DoCommandFlag flag
|
|||||||
return DoCommand(tile, 0, 0, flags, CMD_LANDSCAPE_CLEAR);
|
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()) */
|
/* Check if new slope is valid for bridges in general (so we can safely call GetBridgeFoundation()) */
|
||||||
if ((direction == DIAGDIR_NW) || (direction == DIAGDIR_NE)) {
|
if ((direction == DIAGDIR_NW) || (direction == DIAGDIR_NE)) {
|
||||||
|
@@ -14,6 +14,8 @@
|
|||||||
|
|
||||||
#include "bridge_map.h"
|
#include "bridge_map.h"
|
||||||
#include "tunnel_map.h"
|
#include "tunnel_map.h"
|
||||||
|
#include "track_func.h"
|
||||||
|
#include "core/bitmath_func.hpp"
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -83,31 +85,34 @@ static inline TileIndex GetOtherTunnelBridgeEnd(TileIndex t)
|
|||||||
return IsTunnel(t) ? GetOtherTunnelEnd(t) : GetOtherBridgeEnd(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
|
* @pre IsTileType(t, MP_TUNNELBRIDGE) && GetTunnelBridgeTransportType(t) == TRANSPORT_RAIL
|
||||||
* @param t the tile
|
* @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));
|
if (IsTunnel(t)) {
|
||||||
assert(GetTunnelBridgeTransportType(t) == TRANSPORT_RAIL);
|
return DiagDirToDiagTrackBits(GetTunnelBridgeDirection(t));
|
||||||
return HasBit(_m[t].m5, 4);
|
} 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
|
* @pre IsTileType(t, MP_TUNNELBRIDGE) && GetTunnelBridgeTransportType(t) == TRANSPORT_RAIL
|
||||||
* @param t the tile
|
* @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));
|
if (IsTunnel(t)) {
|
||||||
assert(GetTunnelBridgeTransportType(t) == TRANSPORT_RAIL);
|
return DiagDirToDiagTrackBits(GetTunnelBridgeDirection(t));
|
||||||
SB(_m[t].m5, 4, 1, b ? 1 : 0);
|
} else {
|
||||||
|
return GetCustomBridgeHeadTrackBits(t) & GetAcrossBridgePossibleTrackBits(t);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -118,7 +123,122 @@ static inline void SetTunnelBridgeReservation(TileIndex t, bool b)
|
|||||||
*/
|
*/
|
||||||
static inline TrackBits GetTunnelBridgeReservationTrackBits(TileIndex t)
|
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);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void AddRoadTunnelBridgeInfrastructure(TileIndex begin, TileIndex end);
|
void AddRoadTunnelBridgeInfrastructure(TileIndex begin, TileIndex end);
|
||||||
|
@@ -525,11 +525,23 @@ CommandCost EnsureNoVehicleOnGround(TileIndex tile)
|
|||||||
return CommandCost();
|
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 */
|
/** Procedure called for every vehicle found in tunnel/bridge in the hash map */
|
||||||
static Vehicle *GetVehicleTunnelBridgeProc(Vehicle *v, void *data)
|
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->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;
|
return v;
|
||||||
}
|
}
|
||||||
@@ -539,16 +551,24 @@ static Vehicle *GetVehicleTunnelBridgeProc(Vehicle *v, void *data)
|
|||||||
* @param tile first end
|
* @param tile first end
|
||||||
* @param endtile second end
|
* @param endtile second end
|
||||||
* @param ignore Ignore this vehicle when searching
|
* @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).
|
* @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
|
/* 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).
|
* error message only (which may be different for different machines).
|
||||||
* Such a message does not affect MP synchronisation.
|
* Such a message does not affect MP synchronisation.
|
||||||
*/
|
*/
|
||||||
Vehicle *v = VehicleFromPos(tile, const_cast<Vehicle *>(ignore), &GetVehicleTunnelBridgeProc, true);
|
GetVehicleTunnelBridgeProcData data;
|
||||||
if (v == NULL) v = VehicleFromPos(endtile, const_cast<Vehicle *>(ignore), &GetVehicleTunnelBridgeProc, true);
|
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);
|
if (v != NULL) return_cmd_error(STR_ERROR_TRAIN_IN_THE_WAY + v->type);
|
||||||
return CommandCost();
|
return CommandCost();
|
||||||
@@ -561,6 +581,12 @@ static Vehicle *EnsureNoTrainOnTrackProc(Vehicle *v, void *data)
|
|||||||
if (v->type != VEH_TRAIN) return NULL;
|
if (v->type != VEH_TRAIN) return NULL;
|
||||||
|
|
||||||
Train *t = Train::From(v);
|
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;
|
if ((t->track != rail_bits) && !TracksOverlap(t->track | rail_bits)) return NULL;
|
||||||
|
|
||||||
return v;
|
return v;
|
||||||
|
@@ -60,7 +60,7 @@ byte GetBestFittingSubType(Vehicle *v_from, Vehicle *v_for, CargoID dest_cargo_t
|
|||||||
void ViewportAddVehicles(DrawPixelInfo *dpi);
|
void ViewportAddVehicles(DrawPixelInfo *dpi);
|
||||||
|
|
||||||
void ShowNewGrfVehicleError(EngineID engine, StringID part1, StringID part2, GRFBugs bug_type, bool critical);
|
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 DecreaseVehicleValue(Vehicle *v);
|
||||||
void CheckVehicleBreakdown(Vehicle *v);
|
void CheckVehicleBreakdown(Vehicle *v);
|
||||||
|
@@ -84,6 +84,7 @@
|
|||||||
#include "linkgraph/linkgraph_gui.h"
|
#include "linkgraph/linkgraph_gui.h"
|
||||||
#include "viewport_sprite_sorter.h"
|
#include "viewport_sprite_sorter.h"
|
||||||
#include "bridge_map.h"
|
#include "bridge_map.h"
|
||||||
|
#include "tunnelbridge_map.h"
|
||||||
|
|
||||||
#include <map>
|
#include <map>
|
||||||
|
|
||||||
@@ -976,11 +977,23 @@ static const HighLightStyle _autorail_type[6][2] = {
|
|||||||
*/
|
*/
|
||||||
static void DrawAutorailSelection(const TileInfo *ti, uint autorail_type)
|
static void DrawAutorailSelection(const TileInfo *ti, uint autorail_type)
|
||||||
{
|
{
|
||||||
SpriteID image;
|
|
||||||
PaletteID pal;
|
|
||||||
int offset;
|
|
||||||
|
|
||||||
FoundationPart foundation_part = FOUNDATION_PART_NORMAL;
|
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);
|
Slope autorail_tileh = RemoveHalftileSlope(ti->tileh);
|
||||||
if (IsHalftileSlope(ti->tileh)) {
|
if (IsHalftileSlope(ti->tileh)) {
|
||||||
static const uint _lower_rail[4] = { 5U, 2U, 4U, 3U };
|
static const uint _lower_rail[4] = { 5U, 2U, 4U, 3U };
|
||||||
@@ -991,8 +1004,11 @@ static void DrawAutorailSelection(const TileInfo *ti, uint autorail_type)
|
|||||||
autorail_tileh = SlopeWithThreeCornersRaised(OppositeCorner(halftile_corner));
|
autorail_tileh = SlopeWithThreeCornersRaised(OppositeCorner(halftile_corner));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
offset = _AutorailTilehSprite[autorail_tileh][autorail_type];
|
offset = _AutorailTilehSprite[autorail_tileh][autorail_type];
|
||||||
|
}
|
||||||
|
|
||||||
|
SpriteID image;
|
||||||
|
PaletteID pal;
|
||||||
if (offset >= 0) {
|
if (offset >= 0) {
|
||||||
image = SPR_AUTORAIL_BASE + offset;
|
image = SPR_AUTORAIL_BASE + offset;
|
||||||
pal = PAL_NONE;
|
pal = PAL_NONE;
|
||||||
@@ -1001,7 +1017,11 @@ static void DrawAutorailSelection(const TileInfo *ti, uint autorail_type)
|
|||||||
pal = PALETTE_SEL_TILE_RED;
|
pal = PALETTE_SEL_TILE_RED;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (bridge_head_mode) {
|
||||||
|
AddSortableSpriteToDraw(image, _thd.make_square_red ? PALETTE_SEL_TILE_RED : pal, ti->x, ti->y, 16, 16, 0, ti->z + 15);
|
||||||
|
} else {
|
||||||
DrawSelectionSprite(image, _thd.make_square_red ? PALETTE_SEL_TILE_RED : pal, ti, 7, foundation_part);
|
DrawSelectionSprite(image, _thd.make_square_red ? PALETTE_SEL_TILE_RED : pal, ti, 7, foundation_part);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
Reference in New Issue
Block a user