Merge branch 'custom_bridgeheads' into jgrpp

# Conflicts:
#	docs/landscape.html
#	src/bridge_map.h
#	src/pbs.cpp
#	src/saveload/company_sl.cpp
#	src/saveload/extended_ver_sl.cpp
#	src/settings_type.h
#	src/signal.cpp
#	src/train_cmd.cpp
#	src/tunnel_map.h
#	src/tunnelbridge_cmd.cpp
#	src/tunnelbridge_map.h
#	src/vehicle.cpp
#	src/viewport.cpp
This commit is contained in:
Jonathan G Rennison
2018-07-08 23:04:30 +01:00
29 changed files with 1313 additions and 362 deletions

View File

@@ -56,18 +56,6 @@ RailType _sorted_railtypes[RAILTYPE_END];
uint8 _sorted_railtypes_size;
TileIndex _rail_track_endtile; ///< The end of a rail track; as hidden return from the rail build/remove command for GUI purposes.
/** Enum holding the signal offset in the sprite sheet according to the side it is representing. */
enum SignalOffsets {
SIGNAL_TO_SOUTHWEST,
SIGNAL_TO_NORTHEAST,
SIGNAL_TO_SOUTHEAST,
SIGNAL_TO_NORTHWEST,
SIGNAL_TO_EAST,
SIGNAL_TO_WEST,
SIGNAL_TO_SOUTH,
SIGNAL_TO_NORTH,
};
/**
* Reset all rail type information to its default values.
*/
@@ -435,6 +423,25 @@ static CommandCost CheckRailSlope(Slope tileh, TrackBits rail_bits, TrackBits ex
return CommandCost(EXPENSES_CONSTRUCTION, f_new != f_old ? _price[PR_BUILD_FOUNDATION] : (Money)0);
}
bool IsValidFlatRailBridgeHeadTrackBits(Slope normalised_slope, DiagDirection bridge_direction, TrackBits tracks)
{
/* bridge_direction c1 c2
* 0 0 1
* 1 0 3
* 2 2 3
* 3 2 1
*/
const Corner c1 = (Corner) (bridge_direction & 2);
const Corner c2 = (Corner) (((bridge_direction + 1) & 2) + 1);
auto test_corner = [&](Corner c) -> bool {
if (normalised_slope & SlopeWithOneCornerRaised(c)) return true;
Slope effective_slope = normalised_slope | SlopeWithOneCornerRaised(OppositeCorner(c));
assert(effective_slope < lengthof(_valid_tracks_on_leveled_foundation));
return (_valid_tracks_on_leveled_foundation[effective_slope] & tracks) == tracks;
};
return test_corner(c1) && test_corner(c2);
}
/* Validate functions for rail building */
static inline bool ValParamTrackOrientation(Track track)
{
@@ -454,6 +461,7 @@ CommandCost CmdBuildSingleRail(TileIndex tile, DoCommandFlag flags, uint32 p1, u
{
RailType railtype = Extract<RailType, 0, 5>(p1);
Track track = Extract<Track, 0, 3>(p2);
bool disable_custom_bridge_heads = HasBit(p2, 4);
CommandCost cost(EXPENSES_CONSTRUCTION);
_rail_track_endtile = INVALID_TILE;
@@ -513,6 +521,52 @@ CommandCost CmdBuildSingleRail(TileIndex tile, DoCommandFlag flags, uint32 p1, u
break;
}
case MP_TUNNELBRIDGE: {
CommandCost ret = CheckTileOwnership(tile);
if (ret.Failed()) return ret;
if (disable_custom_bridge_heads || !_settings_game.construction.rail_custom_bridge_heads || !IsFlatRailBridgeHeadTile(tile)) return DoCommand(tile, 0, 0, flags, CMD_LANDSCAPE_CLEAR); // just get appropriate error message
if (!IsCompatibleRail(GetRailType(tile), railtype)) return_cmd_error(STR_ERROR_IMPOSSIBLE_TRACK_COMBINATION);
if (GetRailType(tile) != railtype && !HasPowerOnRail(railtype, GetRailType(tile))) return_cmd_error(STR_ERROR_CAN_T_CONVERT_RAIL);
const DiagDirection entrance_dir = GetTunnelBridgeDirection(tile);
const TrackBits axial_track = DiagDirToDiagTrackBits(entrance_dir);
const TrackBits existing = GetCustomBridgeHeadTrackBits(tile);
const TrackBits future = existing | trackbit;
if (existing == future) return_cmd_error(STR_ERROR_ALREADY_BUILT);
if (flags & DC_NO_RAIL_OVERLAP || IsTunnelBridgeWithSignalSimulation(tile)) {
if (future != TRACK_BIT_HORZ && future != TRACK_BIT_VERT) {
return_cmd_error((flags & DC_NO_RAIL_OVERLAP) ? STR_ERROR_IMPOSSIBLE_TRACK_COMBINATION : STR_ERROR_MUST_REMOVE_SIGNALS_FIRST);
}
}
if ((trackbit & ~axial_track) && !_settings_game.construction.build_on_slopes) {
return_cmd_error(STR_ERROR_LAND_SLOPED_IN_WRONG_DIRECTION);
}
/* Steep slopes behave the same as slopes with one corner raised. */
const Slope normalised_tileh = IsSteepSlope(tileh) ? SlopeWithOneCornerRaised(GetHighestSlopeCorner(tileh)) : tileh;
if (!IsValidFlatRailBridgeHeadTrackBits(normalised_tileh, GetTunnelBridgeDirection(tile), future)) {
return_cmd_error(STR_ERROR_LAND_SLOPED_IN_WRONG_DIRECTION);
}
const TileIndex other_end = GetOtherTunnelBridgeEnd(tile);
ret = TunnelBridgeIsFree(tile, other_end);
if (ret.Failed()) return ret;
if (flags & DC_EXEC) {
SetCustomBridgeHeadTrackBits(tile, future);
Company::Get(GetTileOwner(tile))->infrastructure.rail[GetRailType(tile)] += GetTunnelBridgeHeadOnlyRailInfrastructureCountFromTrackBits(future) - GetTunnelBridgeHeadOnlyRailInfrastructureCountFromTrackBits(existing);
DirtyCompanyInfrastructureWindows(_current_company);
}
break;
}
case MP_ROAD: {
/* Level crossings may only be built on these slopes */
if (!HasBit(VALID_LEVEL_CROSSING_SLOPES, tileh)) return_cmd_error(STR_ERROR_LAND_SLOPED_IN_WRONG_DIRECTION);
@@ -731,6 +785,44 @@ CommandCost CmdRemoveSingleRail(TileIndex tile, DoCommandFlag flags, uint32 p1,
break;
}
case MP_TUNNELBRIDGE: {
CommandCost ret = CheckTileOwnership(tile);
if (ret.Failed()) return ret;
if (!IsFlatRailBridgeHeadTile(tile) || GetCustomBridgeHeadTrackBits(tile) == DiagDirToDiagTrackBits(GetTunnelBridgeDirection(tile))) {
return DoCommand(tile, 0, 0, flags, CMD_LANDSCAPE_CLEAR); // just get appropriate error message
}
const TrackBits present = GetCustomBridgeHeadTrackBits(tile);
if ((present & trackbit) == 0) return_cmd_error(STR_ERROR_THERE_IS_NO_RAILROAD_TRACK);
if (present == (TRACK_BIT_X | TRACK_BIT_Y)) crossing = true;
const TrackBits future = present ^ trackbit;
if ((GetAcrossBridgePossibleTrackBits(tile) & future) == 0) return DoCommand(tile, 0, 0, flags, CMD_LANDSCAPE_CLEAR); // just get appropriate error message
const TileIndex other_end = GetOtherTunnelBridgeEnd(tile);
ret = TunnelBridgeIsFree(tile, other_end);
if (ret.Failed()) return ret;
cost.AddCost(RailClearCost(GetRailType(tile)));
if (flags & DC_EXEC) {
owner = GetTileOwner(tile);
if (HasReservedTracks(tile, trackbit)) {
v = GetTrainForReservation(tile, track);
if (v != NULL) FreeTrainTrackReservation(v);
}
SetCustomBridgeHeadTrackBits(tile, future);
Company::Get(GetTileOwner(tile))->infrastructure.rail[GetRailType(tile)] -= GetTunnelBridgeHeadOnlyRailInfrastructureCountFromTrackBits(present) - GetTunnelBridgeHeadOnlyRailInfrastructureCountFromTrackBits(future);
DirtyCompanyInfrastructureWindows(_current_company);
}
break;
}
default: return_cmd_error(STR_ERROR_THERE_IS_NO_RAILROAD_TRACK);
}
@@ -1084,6 +1176,9 @@ CommandCost CmdBuildSingleSignal(TileIndex tile, DoCommandFlag flags, uint32 p1,
/* You can only build signals on plain rail tiles or tunnel/bridges, and the selected track must exist */
if (IsTileType(tile, MP_TUNNELBRIDGE)) {
if (GetTunnelBridgeTransportType(tile) != TRANSPORT_RAIL) return CMD_ERROR;
if (!ValParamTrackOrientation(track) || !IsTrackAcrossTunnelBridge(tile, track)) {
return_cmd_error(STR_ERROR_THERE_IS_NO_RAILROAD_TRACK);
}
CommandCost ret = EnsureNoTrainOnTrack(GetOtherTunnelBridgeEnd(tile), track);
if (ret.Failed()) return ret;
ret = EnsureNoTrainOnTrack(tile, track);
@@ -1100,19 +1195,24 @@ CommandCost CmdBuildSingleSignal(TileIndex tile, DoCommandFlag flags, uint32 p1,
CommandCost cost;
/* handle signals simulation on tunnel/bridge. */
if (IsTileType(tile, MP_TUNNELBRIDGE)) {
if (TracksOverlap(GetTunnelBridgeTrackBits(tile))) return_cmd_error(STR_ERROR_NO_SUITABLE_RAILROAD_TRACK);
bool bidirectional = HasBit(p1, 18) && (sigtype == SIGTYPE_PBS);
TileIndex tile_exit = GetOtherTunnelBridgeEnd(tile);
cost = CommandCost();
bool flip_variant = false;
bool is_pbs = (sigtype == SIGTYPE_PBS) || (sigtype == SIGTYPE_PBS_ONEWAY);
Trackdir entrance_td = TrackExitdirToTrackdir(track, GetTunnelBridgeDirection(tile));
bool p2_signal_in = p2 & SignalAlongTrackdir(entrance_td);
bool p2_signal_out = p2 & SignalAgainstTrackdir(entrance_td);
bool p2_active = p2_signal_in || p2_signal_out;
if (!IsTunnelBridgeWithSignalSimulation(tile)) { // toggle signal zero costs.
if (convert_signal) return_cmd_error(STR_ERROR_THERE_ARE_NO_SIGNALS);
if (p2 != 12) cost = CommandCost(EXPENSES_CONSTRUCTION, _price[PR_BUILD_SIGNALS] * ((GetTunnelBridgeLength(tile, tile_exit) + 4) >> 2) * (bidirectional ? 2 : 1)); // minimal 1
if (!(p2_signal_in && p2_signal_out)) cost = CommandCost(EXPENSES_CONSTRUCTION, _price[PR_BUILD_SIGNALS] * ((GetTunnelBridgeLength(tile, tile_exit) + 4) >> 2) * (bidirectional ? 2 : 1)); // minimal 1
} else {
if (HasBit(p1, 17)) return CommandCost();
bool is_bidi = IsTunnelBridgeSignalSimulationBidirectional(tile);
bool will_be_bidi = is_bidi;
if (p2 == 0) {
if (!p2_active) {
if (convert_signal) {
will_be_bidi = bidirectional && !ctrl_pressed;
} else if (ctrl_pressed) {
@@ -1121,7 +1221,7 @@ CommandCost CmdBuildSingleSignal(TileIndex tile, DoCommandFlag flags, uint32 p1,
} else if (!is_pbs) {
will_be_bidi = false;
}
if ((p2 != 0 && (sigvar == SIG_SEMAPHORE) != IsTunnelBridgeSemaphore(tile)) ||
if ((!p2_active && (sigvar == SIG_SEMAPHORE) != IsTunnelBridgeSemaphore(tile)) ||
(convert_signal && (ctrl_pressed || (sigvar == SIG_SEMAPHORE) != IsTunnelBridgeSemaphore(tile)))) {
flip_variant = true;
cost = CommandCost(EXPENSES_CONSTRUCTION, ((_price[PR_BUILD_SIGNALS] * (will_be_bidi ? 2 : 1)) + (_price[PR_CLEAR_SIGNALS] * (is_bidi ? 2 : 1))) *
@@ -1144,7 +1244,7 @@ CommandCost CmdBuildSingleSignal(TileIndex tile, DoCommandFlag flags, uint32 p1,
if (flags & DC_EXEC) {
Company * const c = Company::Get(GetTileOwner(tile));
if (IsTunnelBridgeWithSignalSimulation(tile)) c->infrastructure.signal -= GetTunnelBridgeSignalSimulationSignalCount(tile, tile_exit);
if (p2 == 0 && IsTunnelBridgeWithSignalSimulation(tile)) { // Toggle signal if already signals present.
if (!p2_active && IsTunnelBridgeWithSignalSimulation(tile)) { // Toggle signal if already signals present.
if (convert_signal) {
if (flip_variant) {
SetTunnelBridgeSemaphore(tile, !IsTunnelBridgeSemaphore(tile));
@@ -1175,18 +1275,16 @@ CommandCost CmdBuildSingleSignal(TileIndex tile, DoCommandFlag flags, uint32 p1,
}
} else {
/* Create one direction tunnel/bridge if required. */
if (p2 == 0) {
if (!p2_active) {
if (bidirectional) {
set_bidi(tile);
set_bidi(tile_exit);
} else {
SetupBridgeTunnelSignalSimulation(tile, tile_exit);
}
} else if (p2 == 4 || p2 == 8) {
DiagDirection tbdir = GetTunnelBridgeDirection(tile);
} else if (p2_signal_in != p2_signal_out) {
/* If signal only on one side build accoringly one-way tunnel/bridge. */
if ((p2 == 8 && (tbdir == DIAGDIR_NE || tbdir == DIAGDIR_SE)) ||
(p2 == 4 && (tbdir == DIAGDIR_SW || tbdir == DIAGDIR_NW))) {
if (p2_signal_in) {
ClearBridgeTunnelSignalSimulation(tile_exit, tile);
SetupBridgeTunnelSignalSimulation(tile, tile_exit);
} else {
@@ -1194,7 +1292,7 @@ CommandCost CmdBuildSingleSignal(TileIndex tile, DoCommandFlag flags, uint32 p1,
SetupBridgeTunnelSignalSimulation(tile_exit, tile);
}
}
if (p2 == 0 || p2 == 4 || p2 == 8) {
if (!(p2_signal_in && p2_signal_out)) {
SetTunnelBridgeSemaphore(tile, sigvar == SIG_SEMAPHORE);
SetTunnelBridgeSemaphore(tile_exit, sigvar == SIG_SEMAPHORE);
SetTunnelBridgePBS(tile, is_pbs);
@@ -1202,8 +1300,8 @@ CommandCost CmdBuildSingleSignal(TileIndex tile, DoCommandFlag flags, uint32 p1,
if (!IsTunnelBridgePBS(tile)) remove_pbs_bidi();
}
}
if (IsTunnelBridgeSignalSimulationExit(tile) && IsTunnelBridgePBS(tile) && !HasTunnelBridgeReservation(tile)) SetTunnelBridgeExitSignalState(tile, SIGNAL_STATE_RED);
if (IsTunnelBridgeSignalSimulationExit(tile_exit) && IsTunnelBridgePBS(tile_exit) && !HasTunnelBridgeReservation(tile_exit)) SetTunnelBridgeExitSignalState(tile_exit, SIGNAL_STATE_RED);
if (IsTunnelBridgeSignalSimulationExit(tile) && IsTunnelBridgePBS(tile) && !HasAcrossTunnelBridgeReservation(tile)) SetTunnelBridgeExitSignalState(tile, SIGNAL_STATE_RED);
if (IsTunnelBridgeSignalSimulationExit(tile_exit) && IsTunnelBridgePBS(tile_exit) && !HasAcrossTunnelBridgeReservation(tile_exit)) SetTunnelBridgeExitSignalState(tile_exit, SIGNAL_STATE_RED);
MarkBridgeOrTunnelDirty(tile);
AddSideToSignalBuffer(tile, INVALID_DIAGDIR, GetTileOwner(tile));
AddSideToSignalBuffer(tile_exit, INVALID_DIAGDIR, GetTileOwner(tile));
@@ -1393,13 +1491,27 @@ static bool CheckSignalAutoFill(TileIndex &tile, Trackdir &trackdir, int &signal
TileIndex orig_tile = tile; // backup old value
if (GetTunnelBridgeTransportType(tile) != TRANSPORT_RAIL) return false;
if (GetTunnelBridgeDirection(tile) != TrackdirToExitdir(trackdir)) return false;
signal_ctr += IsDiagonalTrackdir(trackdir) ? 2 : 1;
if (GetTunnelBridgeDirection(tile) == TrackdirToExitdir(trackdir)) {
/* Skip to end of tunnel or bridge
* note that tile is a parameter by reference, so it must be updated */
tile = GetOtherTunnelBridgeEnd(tile);
signal_ctr += GetTunnelBridgeLength(orig_tile, tile) * 2;
/* Skip to end of tunnel or bridge
* note that tile is a parameter by reference, so it must be updated */
tile = GetOtherTunnelBridgeEnd(tile);
/* Check for track bits on the new tile */
trackdirbits = TrackStatusToTrackdirBits(GetTileTrackStatus(tile, TRANSPORT_RAIL, 0));
signal_ctr += (GetTunnelBridgeLength(orig_tile, tile) + 2) * 2;
if (TracksOverlap(TrackdirBitsToTrackBits(trackdirbits))) return false;
trackdirbits &= TrackdirReachesTrackdirs(trackdir);
/* Get the first track dir */
trackdir = RemoveFirstTrackdir(&trackdirbits);
/* Any left? It's a junction so we stop */
if (trackdirbits != TRACKDIR_BIT_NONE) return false;
signal_ctr += IsDiagonalTrackdir(trackdir) ? 2 : 1;
}
return true;
}
@@ -1823,6 +1935,24 @@ CommandCost CmdConvertRail(TileIndex tile, DoCommandFlag flags, uint32 p1, uint3
SmallVector<Train *, 2> vehicles_affected;
auto find_train_reservations = [&vehicles_affected, &totype](TileIndex tile, TrackBits reserved) {
Track track;
while ((track = RemoveFirstTrack(&reserved)) != INVALID_TRACK) {
Train *v = GetTrainForReservation(tile, track);
if (v != NULL && !HasPowerOnRail(v->railtype, totype)) {
/* No power on new rail type, reroute. */
FreeTrainTrackReservation(v);
*vehicles_affected.Append() = v;
}
}
};
auto yapf_notify_track_change = [](TileIndex tile, TrackBits tracks) {
while (tracks != TRACK_BIT_NONE) {
YapfNotifyTrackLayoutChange(tile, RemoveFirstTrack(&tracks));
}
};
/* Vehicle on the tile when not converting Rail <-> ElRail
* Tunnels and bridges have special check later */
if (tt != MP_TUNNELBRIDGE) {
@@ -1834,16 +1964,7 @@ CommandCost CmdConvertRail(TileIndex tile, DoCommandFlag flags, uint32 p1, uint3
}
}
if (flags & DC_EXEC) { // we can safely convert, too
TrackBits reserved = GetReservedTrackbits(tile);
Track track;
while ((track = RemoveFirstTrack(&reserved)) != INVALID_TRACK) {
Train *v = GetTrainForReservation(tile, track);
if (v != NULL && !HasPowerOnRail(v->railtype, totype)) {
/* No power on new rail type, reroute. */
FreeTrainTrackReservation(v);
*vehicles_affected.Append() = v;
}
}
find_train_reservations(tile, GetReservedTrackbits(tile));
/* Update the company infrastructure counters. */
if (!IsRailStationTile(tile) || !IsStationTileBlocked(tile)) {
@@ -1884,10 +2005,7 @@ CommandCost CmdConvertRail(TileIndex tile, DoCommandFlag flags, uint32 p1, uint3
default: // RAIL_TILE_NORMAL, RAIL_TILE_SIGNALS
if (flags & DC_EXEC) {
/* notify YAPF about the track layout change */
TrackBits tracks = GetTrackBits(tile);
while (tracks != TRACK_BIT_NONE) {
YapfNotifyTrackLayoutChange(tile, RemoveFirstTrack(&tracks));
}
yapf_notify_track_change(tile, GetTrackBits(tile));
}
cost.AddCost(RailConvertCost(type, totype) * CountBits(GetTrackBits(tile)));
break;
@@ -1916,22 +2034,18 @@ CommandCost CmdConvertRail(TileIndex tile, DoCommandFlag flags, uint32 p1, uint3
}
}
uint middle_len = GetTunnelBridgeLength(tile, endtile);
uint num_raw_pieces = middle_len + CountBits(GetTunnelBridgeTrackBits(tile)) + CountBits(GetTunnelBridgeTrackBits(endtile));
if (flags & DC_EXEC) {
Track track = DiagDirToDiagTrack(GetTunnelBridgeDirection(tile));
if (HasTunnelBridgeReservation(tile)) {
Train *v = GetTrainForReservation(tile, track);
if (v != NULL && !HasPowerOnRail(v->railtype, totype)) {
/* No power on new rail type, reroute. */
FreeTrainTrackReservation(v);
*vehicles_affected.Append() = v;
}
}
find_train_reservations(tile, GetTunnelBridgeReservationTrackBits(tile));
find_train_reservations(endtile, GetTunnelBridgeReservationTrackBits(endtile));
/* Update the company infrastructure counters. */
uint num_pieces = (GetTunnelBridgeLength(tile, endtile) + 2) * TUNNELBRIDGE_TRACKBIT_FACTOR;
uint num_infra_pieces = (middle_len* TUNNELBRIDGE_TRACKBIT_FACTOR) + GetTunnelBridgeHeadOnlyRailInfrastructureCount(tile) + GetTunnelBridgeHeadOnlyRailInfrastructureCount(endtile);
Company *c = Company::Get(GetTileOwner(tile));
c->infrastructure.rail[GetRailType(tile)] -= num_pieces;
c->infrastructure.rail[totype] += num_pieces;
c->infrastructure.rail[GetRailType(tile)] -= num_infra_pieces;
c->infrastructure.rail[totype] += num_infra_pieces;
DirtyCompanyInfrastructureWindows(c->index);
SetRailType(tile, totype);
@@ -1940,8 +2054,9 @@ CommandCost CmdConvertRail(TileIndex tile, DoCommandFlag flags, uint32 p1, uint3
FindVehicleOnPos(tile, &affected_trains, &UpdateTrainPowerProc);
FindVehicleOnPos(endtile, &affected_trains, &UpdateTrainPowerProc);
YapfNotifyTrackLayoutChange(tile, track);
YapfNotifyTrackLayoutChange(endtile, track);
/* notify YAPF about the track layout change */
yapf_notify_track_change(tile, GetTunnelBridgeTrackBits(tile));
yapf_notify_track_change(endtile, GetTunnelBridgeTrackBits(endtile));
if (IsBridge(tile)) {
MarkBridgeDirty(tile, ZOOM_LVL_DRAW_MAP);
@@ -1951,7 +2066,7 @@ CommandCost CmdConvertRail(TileIndex tile, DoCommandFlag flags, uint32 p1, uint3
}
}
cost.AddCost((GetTunnelBridgeLength(tile, endtile) + 2) * RailConvertCost(type, totype));
cost.AddCost(num_raw_pieces * RailConvertCost(type, totype));
break;
}
@@ -2089,7 +2204,7 @@ static uint GetSaveSlopeZ(uint x, uint y, Track track)
return GetSlopePixelZ(x, y);
}
static void DrawSingleSignal(TileIndex tile, const RailtypeInfo *rti, Track track, SignalState condition, SignalOffsets image, uint pos)
void DrawSingleSignal(TileIndex tile, const RailtypeInfo *rti, Track track, SignalState condition, SignalOffsets image, uint pos, SignalType type, SignalVariant variant, bool show_restricted)
{
bool side;
switch (_settings_game.construction.train_signal_side) {
@@ -2114,11 +2229,6 @@ static void DrawSingleSignal(TileIndex tile, const RailtypeInfo *rti, Track trac
uint x = TileX(tile) * TILE_SIZE + SignalPositions[side][pos].x;
uint y = TileY(tile) * TILE_SIZE + SignalPositions[side][pos].y;
SignalType type = GetSignalType(tile, track);
SignalVariant variant = GetSignalVariant(tile, track);
bool show_restricted = (variant == SIG_ELECTRIC) && IsRestrictedSignal(tile) && (GetExistingTraceRestrictProgram(tile, track) != NULL);
SpriteID sprite = GetCustomSignalSprite(rti, tile, type, variant, condition);
bool is_custom_sprite = (sprite != 0);
if (sprite != 0) {
@@ -2164,6 +2274,15 @@ static void DrawSingleSignal(TileIndex tile, const RailtypeInfo *rti, Track trac
}
}
static void DrawSingleSignal(TileIndex tile, const RailtypeInfo *rti, Track track, SignalState condition, SignalOffsets image, uint pos)
{
SignalType type = GetSignalType(tile, track);
SignalVariant variant = GetSignalVariant(tile, track);
bool show_restricted = (variant == SIG_ELECTRIC) && IsRestrictedSignal(tile) && (GetExistingTraceRestrictProgram(tile, track) != NULL);
DrawSingleSignal(tile, rti, track, condition, image, pos, type, variant, show_restricted);
}
static uint32 _drawtile_track_palette;
@@ -2325,10 +2444,19 @@ static inline void DrawTrackSprite(SpriteID sprite, PaletteID pal, const TileInf
DrawGroundSprite(sprite, pal, NULL, 0, (ti->tileh & s) ? -8 : 0);
}
static RailGroundType GetRailOrBridgeGroundType(TileInfo *ti) {
if (IsTileType(ti->tile, MP_TUNNELBRIDGE)) {
return HasTunnelBridgeSnowOrDesert(ti->tile) ? RAIL_GROUND_ICE_DESERT : RAIL_GROUND_GRASS;
} else {
return GetRailGroundType(ti->tile);
}
}
static void DrawTrackBitsOverlay(TileInfo *ti, TrackBits track, const RailtypeInfo *rti)
{
RailGroundType rgt = GetRailGroundType(ti->tile);
Foundation f = GetRailFoundation(ti->tileh, track);
const bool is_bridge = IsTileType(ti->tile, MP_TUNNELBRIDGE);
RailGroundType rgt = GetRailOrBridgeGroundType(ti);
Foundation f = is_bridge ? FOUNDATION_LEVELED : GetRailFoundation(ti->tileh, track);
Corner halftile_corner = CORNER_INVALID;
if (IsNonContinuousFoundation(f)) {
@@ -2367,7 +2495,10 @@ static void DrawTrackBitsOverlay(TileInfo *ti, TrackBits track, const RailtypeIn
SpriteID overlay = GetCustomRailSprite(rti, ti->tile, RTSG_OVERLAY);
SpriteID ground = GetCustomRailSprite(rti, ti->tile, RTSG_GROUND);
TrackBits pbs = _settings_client.gui.show_track_reservation ? GetRailReservationTrackBits(ti->tile) : TRACK_BIT_NONE;
TrackBits pbs = TRACK_BIT_NONE;
if (_settings_client.gui.show_track_reservation) {
pbs = is_bridge ? GetTunnelBridgeReservationTrackBits(ti->tile) : GetRailReservationTrackBits(ti->tile);
}
if (track == TRACK_BIT_NONE) {
/* Half-tile foundation, no track here? */
@@ -2477,7 +2608,7 @@ static void DrawTrackBitsOverlay(TileInfo *ti, TrackBits track, const RailtypeIn
* @param ti TileInfo
* @param track TrackBits to draw
*/
static void DrawTrackBits(TileInfo *ti, TrackBits track)
void DrawTrackBits(TileInfo *ti, TrackBits track)
{
const RailtypeInfo *rti = GetRailTypeInfo(GetRailType(ti->tile));
@@ -2486,8 +2617,9 @@ static void DrawTrackBits(TileInfo *ti, TrackBits track)
return;
}
RailGroundType rgt = GetRailGroundType(ti->tile);
Foundation f = GetRailFoundation(ti->tileh, track);
const bool is_bridge = IsTileType(ti->tile, MP_TUNNELBRIDGE);
RailGroundType rgt = GetRailOrBridgeGroundType(ti);
Foundation f = is_bridge ? FOUNDATION_LEVELED : GetRailFoundation(ti->tileh, track);
Corner halftile_corner = CORNER_INVALID;
if (IsNonContinuousFoundation(f)) {
@@ -2578,7 +2710,7 @@ static void DrawTrackBits(TileInfo *ti, TrackBits track)
/* PBS debugging, draw reserved tracks darker */
if (_game_mode != GM_MENU && _settings_client.gui.show_track_reservation) {
/* Get reservation, but mask track on halftile slope */
TrackBits pbs = GetRailReservationTrackBits(ti->tile) & track;
TrackBits pbs = (is_bridge ? GetTunnelBridgeReservationTrackBits(ti->tile) : GetRailReservationTrackBits(ti->tile)) & track;
if (pbs & TRACK_BIT_X) {
if (ti->tileh == SLOPE_FLAT || ti->tileh == SLOPE_ELEVATED) {
DrawGroundSprite(rti->base_sprites.single_x, PALETTE_CRASH);