diff --git a/src/clear_cmd.cpp b/src/clear_cmd.cpp --- a/src/clear_cmd.cpp +++ b/src/clear_cmd.cpp @@ -127,7 +127,7 @@ static void DrawTile_Clear(TileInfo *ti) DrawBridgeMiddle(ti); } -static int GetSlopePixelZ_Clear(TileIndex tile, uint x, uint y) +static int GetSlopePixelZ_Clear(TileIndex tile, uint x, uint y, bool ground_vehicle) { int z; Slope tileh = GetTilePixelSlope(tile, &z); diff --git a/src/elrail.cpp b/src/elrail.cpp --- a/src/elrail.cpp +++ b/src/elrail.cpp @@ -233,7 +233,7 @@ static int GetPCPElevation(TileIndex til */ int z = GetSlopePixelZ(TileX(tile) * TILE_SIZE + std::min(x_pcp_offsets[PCPpos], TILE_SIZE - 1), - TileY(tile) * TILE_SIZE + std::min(y_pcp_offsets[PCPpos], TILE_SIZE - 1)); + TileY(tile) * TILE_SIZE + std::min(y_pcp_offsets[PCPpos], TILE_SIZE - 1), true); /* Round the Z to the nearest half tile height. */ static const uint HALF_TILE_HEIGHT = TILE_HEIGHT / 2; return (z + HALF_TILE_HEIGHT / 2) / HALF_TILE_HEIGHT * HALF_TILE_HEIGHT; @@ -491,7 +491,7 @@ static void DrawRailCatenaryRailway(cons * down to the nearest full height change. */ AddSortableSpriteToDraw(wire_base + sss->image_offset, PAL_NONE, ti->x + sss->x_offset, ti->y + sss->y_offset, - sss->x_size, sss->y_size, sss->z_size, (GetSlopePixelZ(ti->x + sss->x_offset, ti->y + sss->y_offset) + 4) / 8 * 8 + sss->z_offset, + sss->x_size, sss->y_size, sss->z_size, (GetSlopePixelZ(ti->x + sss->x_offset, ti->y + sss->y_offset, true) + 4) / 8 * 8 + sss->z_offset, IsTransparencySet(TO_CATENARY)); } } diff --git a/src/ground_vehicle.hpp b/src/ground_vehicle.hpp --- a/src/ground_vehicle.hpp +++ b/src/ground_vehicle.hpp @@ -134,7 +134,7 @@ struct GroundVehicle : public Specialize */ inline void UpdateZPositionAndInclination() { - this->z_pos = GetSlopePixelZ(this->x_pos, this->y_pos); + this->z_pos = GetSlopePixelZ(this->x_pos, this->y_pos, true); ClrBit(this->gv_flags, GVF_GOINGUP_BIT); ClrBit(this->gv_flags, GVF_GOINGDOWN_BIT); @@ -143,7 +143,7 @@ struct GroundVehicle : public Specialize * direction it is sloped, we get the 'z' at the center of * the tile (middle_z) and the edge of the tile (old_z), * which we then can compare. */ - int middle_z = GetSlopePixelZ((this->x_pos & ~TILE_UNIT_MASK) | (TILE_SIZE / 2), (this->y_pos & ~TILE_UNIT_MASK) | (TILE_SIZE / 2)); + int middle_z = GetSlopePixelZ((this->x_pos & ~TILE_UNIT_MASK) | (TILE_SIZE / 2), (this->y_pos & ~TILE_UNIT_MASK) | (TILE_SIZE / 2), true); if (middle_z != this->z_pos) { SetBit(this->gv_flags, (middle_z > this->z_pos) ? GVF_GOINGUP_BIT : GVF_GOINGDOWN_BIT); @@ -200,7 +200,7 @@ struct GroundVehicle : public Specialize if (HasBit(this->gv_flags, GVF_GOINGUP_BIT) || HasBit(this->gv_flags, GVF_GOINGDOWN_BIT)) { if (T::From(this)->HasToUseGetSlopePixelZ()) { /* In some cases, we have to use GetSlopePixelZ() */ - this->z_pos = GetSlopePixelZ(this->x_pos, this->y_pos); + this->z_pos = GetSlopePixelZ(this->x_pos, this->y_pos, true); return; } /* DirToDiagDir() is a simple right shift */ @@ -220,7 +220,7 @@ struct GroundVehicle : public Specialize this->z_pos += HasBit(this->gv_flags, GVF_GOINGUP_BIT) ? d : -d; } - assert(this->z_pos == GetSlopePixelZ(this->x_pos, this->y_pos)); + assert(this->z_pos == GetSlopePixelZ(this->x_pos, this->y_pos, true)); } /** diff --git a/src/industry_cmd.cpp b/src/industry_cmd.cpp --- a/src/industry_cmd.cpp +++ b/src/industry_cmd.cpp @@ -385,7 +385,7 @@ static void DrawTile_Industry(TileInfo * } } -static int GetSlopePixelZ_Industry(TileIndex tile, uint x, uint y) +static int GetSlopePixelZ_Industry(TileIndex tile, uint x, uint y, bool ground_vehicle) { return GetTileMaxPixelZ(tile); } diff --git a/src/landscape.cpp b/src/landscape.cpp --- a/src/landscape.cpp +++ b/src/landscape.cpp @@ -343,11 +343,22 @@ uint GetPartialPixelZ(int x, int y, Slop return z; } -int GetSlopePixelZ(int x, int y) +/** + * Return world \c Z coordinate of a given point of a tile. Normally this is the + * Z of the ground/foundation at the given location, but in some cases the + * ground/foundation can differ from the Z coordinate that the (ground) vehicle + * passing over it would take. For example when entering a tunnel or bridge. + * + * @param x World X coordinate in tile "units". + * @param y World Y coordinate in tile "units". + * @param ground_vehicle Whether to get the Z coordinate of the ground vehicle, or the ground. + * @return World Z coordinate at tile ground (vehicle) level, including slopes and foundations. + */ +int GetSlopePixelZ(int x, int y, bool ground_vehicle) { TileIndex tile = TileVirtXY(x, y); - return _tile_type_procs[GetTileType(tile)]->get_slope_z_proc(tile, x, y); + return _tile_type_procs[GetTileType(tile)]->get_slope_z_proc(tile, x, y, ground_vehicle); } /** @@ -361,9 +372,9 @@ int GetSlopePixelZ(int x, int y) int GetSlopePixelZOutsideMap(int x, int y) { if (IsInsideBS(x, 0, Map::SizeX() * TILE_SIZE) && IsInsideBS(y, 0, Map::SizeY() * TILE_SIZE)) { - return GetSlopePixelZ(x, y); + return GetSlopePixelZ(x, y, false); } else { - return _tile_type_procs[MP_VOID]->get_slope_z_proc(INVALID_TILE, x, y); + return _tile_type_procs[MP_VOID]->get_slope_z_proc(INVALID_TILE, x, y, false); } } diff --git a/src/landscape.h b/src/landscape.h --- a/src/landscape.h +++ b/src/landscape.h @@ -37,7 +37,7 @@ int GetSlopeZInCorner(Slope tileh, Corne Slope GetFoundationSlope(TileIndex tile, int *z = nullptr); uint GetPartialPixelZ(int x, int y, Slope corners); -int GetSlopePixelZ(int x, int y); +int GetSlopePixelZ(int x, int y, bool ground_vehicle = false); int GetSlopePixelZOutsideMap(int x, int y); void GetSlopePixelZOnEdge(Slope tileh, DiagDirection edge, int *z1, int *z2); @@ -97,7 +97,7 @@ static inline Point RemapCoords(int x, i */ static inline Point RemapCoords2(int x, int y) { - return RemapCoords(x, y, GetSlopePixelZ(x, y)); + return RemapCoords(x, y, GetSlopePixelZ(x, y, false)); } /** diff --git a/src/object_cmd.cpp b/src/object_cmd.cpp --- a/src/object_cmd.cpp +++ b/src/object_cmd.cpp @@ -486,7 +486,7 @@ static void DrawTile_Object(TileInfo *ti DrawBridgeMiddle(ti); } -static int GetSlopePixelZ_Object(TileIndex tile, uint x, uint y) +static int GetSlopePixelZ_Object(TileIndex tile, uint x, uint y, bool ground_vehicle) { if (IsObjectType(tile, OBJECT_OWNED_LAND)) { int z; diff --git a/src/pathfinder/npf/npf.cpp b/src/pathfinder/npf/npf.cpp --- a/src/pathfinder/npf/npf.cpp +++ b/src/pathfinder/npf/npf.cpp @@ -245,8 +245,8 @@ static uint NPFSlopeCost(AyStarNode *cur /* Get the height on both sides of the tile edge. * Avoid testing the height on the tile-center. This will fail for halftile-foundations. */ - int z1 = GetSlopePixelZ(x1 + dx4, y1 + dy4); - int z2 = GetSlopePixelZ(x2 - dx4, y2 - dy4); + int z1 = GetSlopePixelZ(x1 + dx4, y1 + dy4, true); + int z2 = GetSlopePixelZ(x2 - dx4, y2 - dy4, true); if (z2 - z1 > 1) { /* Slope up */ diff --git a/src/pathfinder/yapf/yapf_road.cpp b/src/pathfinder/yapf/yapf_road.cpp --- a/src/pathfinder/yapf/yapf_road.cpp +++ b/src/pathfinder/yapf/yapf_road.cpp @@ -40,12 +40,12 @@ protected: /* height of the center of the current tile */ int x1 = TileX(tile) * TILE_SIZE; int y1 = TileY(tile) * TILE_SIZE; - int z1 = GetSlopePixelZ(x1 + TILE_SIZE / 2, y1 + TILE_SIZE / 2); + int z1 = GetSlopePixelZ(x1 + TILE_SIZE / 2, y1 + TILE_SIZE / 2, true); /* height of the center of the next tile */ int x2 = TileX(next_tile) * TILE_SIZE; int y2 = TileY(next_tile) * TILE_SIZE; - int z2 = GetSlopePixelZ(x2 + TILE_SIZE / 2, y2 + TILE_SIZE / 2); + int z2 = GetSlopePixelZ(x2 + TILE_SIZE / 2, y2 + TILE_SIZE / 2, true); if (z2 - z1 > 1) { /* Slope up */ diff --git a/src/rail_cmd.cpp b/src/rail_cmd.cpp --- a/src/rail_cmd.cpp +++ b/src/rail_cmd.cpp @@ -2550,7 +2550,7 @@ void DrawTrainDepotSprite(int x, int y, DrawRailTileSeqInGUI(x, y, dts, offset, 0, palette); } -static int GetSlopePixelZ_Track(TileIndex tile, uint x, uint y) +static int GetSlopePixelZ_Track(TileIndex tile, uint x, uint y, bool ground_vehicle) { if (IsPlainRail(tile)) { int z; diff --git a/src/road_cmd.cpp b/src/road_cmd.cpp --- a/src/road_cmd.cpp +++ b/src/road_cmd.cpp @@ -1886,7 +1886,7 @@ void UpdateNearestTownForRoadTiles(bool } } -static int GetSlopePixelZ_Road(TileIndex tile, uint x, uint y) +static int GetSlopePixelZ_Road(TileIndex tile, uint x, uint y, bool ground_vehicle) { if (IsNormalRoad(tile)) { diff --git a/src/roadveh_cmd.cpp b/src/roadveh_cmd.cpp --- a/src/roadveh_cmd.cpp +++ b/src/roadveh_cmd.cpp @@ -277,7 +277,7 @@ CommandCost CmdBuildRoadVehicle(DoComman int y = TileY(tile) * TILE_SIZE + TILE_SIZE / 2; v->x_pos = x; v->y_pos = y; - v->z_pos = GetSlopePixelZ(x, y); + v->z_pos = GetSlopePixelZ(x, y, true); v->state = RVSB_IN_DEPOT; v->vehstatus = VS_HIDDEN | VS_STOPPED | VS_DEFPAL; diff --git a/src/saveload/afterload.cpp b/src/saveload/afterload.cpp --- a/src/saveload/afterload.cpp +++ b/src/saveload/afterload.cpp @@ -510,12 +510,12 @@ static uint FixVehicleInclination(Vehicl case INVALID_DIR: break; default: NOT_REACHED(); } - byte entry_z = GetSlopePixelZ(entry_x, entry_y); + byte entry_z = GetSlopePixelZ(entry_x, entry_y, true); /* Compute middle of the tile. */ int middle_x = (v->x_pos & ~TILE_UNIT_MASK) + TILE_SIZE / 2; int middle_y = (v->y_pos & ~TILE_UNIT_MASK) + TILE_SIZE / 2; - byte middle_z = GetSlopePixelZ(middle_x, middle_y); + byte middle_z = GetSlopePixelZ(middle_x, middle_y, true); /* middle_z == entry_z, no height change. */ if (middle_z == entry_z) return 0; @@ -1249,7 +1249,7 @@ bool AfterLoadGame() case DIAGDIR_SW: if ((v->x_pos & 0xF) != TILE_SIZE - 1) continue; break; case DIAGDIR_NW: if ((v->y_pos & 0xF) != 0) continue; break; } - } else if (v->z_pos > GetSlopePixelZ(v->x_pos, v->y_pos)) { + } else if (v->z_pos > GetSlopePixelZ(v->x_pos, v->y_pos, true)) { v->tile = GetNorthernBridgeEnd(v->tile); v->UpdatePosition(); } else { @@ -2515,7 +2515,7 @@ bool AfterLoadGame() if (!IsTunnelTile(vtile)) continue; /* Are we actually in this tunnel? Or maybe a lower tunnel? */ - if (GetSlopePixelZ(v->x_pos, v->y_pos) != v->z_pos) continue; + if (GetSlopePixelZ(v->x_pos, v->y_pos, true) != v->z_pos) continue; /* What way are we going? */ const DiagDirection dir = GetTunnelBridgeDirection(vtile); @@ -2661,7 +2661,7 @@ bool AfterLoadGame() /* In old versions, z_pos was 1 unit lower on bridge heads. * However, this invalid state could be converted to new savegames * by loading and saving the game in a new version. */ - v->z_pos = GetSlopePixelZ(v->x_pos, v->y_pos); + v->z_pos = GetSlopePixelZ(v->x_pos, v->y_pos, true); DiagDirection dir = GetTunnelBridgeDirection(v->tile); if (v->type == VEH_TRAIN && !(v->vehstatus & VS_CRASHED) && v->direction != DiagDirToDir(dir)) { @@ -2675,7 +2675,7 @@ bool AfterLoadGame() /* If the vehicle is really above v->tile (not in a wormhole), * it should have set v->z_pos correctly. */ - assert(v->tile != TileVirtXY(v->x_pos, v->y_pos) || v->z_pos == GetSlopePixelZ(v->x_pos, v->y_pos)); + assert(v->tile != TileVirtXY(v->x_pos, v->y_pos) || v->z_pos == GetSlopePixelZ(v->x_pos, v->y_pos, true)); } /* Fill Vehicle::cur_real_order_index */ @@ -3183,7 +3183,7 @@ bool AfterLoadGame() int y = TileY(closestDepot.location) * TILE_SIZE + TILE_SIZE / 2; u->x_pos = x; u->y_pos = y; - u->z_pos = GetSlopePixelZ(x, y); + u->z_pos = GetSlopePixelZ(x, y, true); u->vehstatus |= VS_HIDDEN; u->state = RVSB_IN_DEPOT; diff --git a/src/station_cmd.cpp b/src/station_cmd.cpp --- a/src/station_cmd.cpp +++ b/src/station_cmd.cpp @@ -3269,7 +3269,7 @@ void StationPickerDrawSprite(int x, int DrawRailTileSeqInGUI(x, y, t, st == STATION_WAYPOINT ? 0 : total_offset, 0, pal); } -static int GetSlopePixelZ_Station(TileIndex tile, uint x, uint y) +static int GetSlopePixelZ_Station(TileIndex tile, uint x, uint y, bool ground_vehicle) { return GetTileMaxPixelZ(tile); } diff --git a/src/tile_cmd.h b/src/tile_cmd.h --- a/src/tile_cmd.h +++ b/src/tile_cmd.h @@ -73,7 +73,19 @@ struct TileDesc { * @param ti Information about the tile to draw */ typedef void DrawTileProc(TileInfo *ti); -typedef int GetSlopeZProc(TileIndex tile, uint x, uint y); + +/** + * Tile callback function signature for obtaining the world \c Z coordinate of a given + * point of a tile. + * + * @param tile The queries tile for the Z coordinate. + * @param x World X coordinate in tile "units". + * @param y World Y coordinate in tile "units". + * @param ground_vehicle Whether to get the Z coordinate of the ground vehicle, or the ground. + * @return World Z coordinate at tile ground (vehicle) level, including slopes and foundations. + * @see GetSlopePixelZ + */ +typedef int GetSlopeZProc(TileIndex tile, uint x, uint y, bool ground_vehicle); typedef CommandCost ClearTileProc(TileIndex tile, DoCommandFlag flags); /** diff --git a/src/town_cmd.cpp b/src/town_cmd.cpp --- a/src/town_cmd.cpp +++ b/src/town_cmd.cpp @@ -306,7 +306,7 @@ static void DrawTile_Town(TileInfo *ti) } } -static int GetSlopePixelZ_Town(TileIndex tile, uint x, uint y) +static int GetSlopePixelZ_Town(TileIndex tile, uint x, uint y, bool ground_vehicle) { return GetTileMaxPixelZ(tile); } diff --git a/src/train_cmd.cpp b/src/train_cmd.cpp --- a/src/train_cmd.cpp +++ b/src/train_cmd.cpp @@ -635,7 +635,7 @@ static CommandCost CmdBuildRailWagon(DoC v->x_pos = x; v->y_pos = y; - v->z_pos = GetSlopePixelZ(x, y); + v->z_pos = GetSlopePixelZ(x, y, true); v->owner = _current_company; v->track = TRACK_BIT_DEPOT; v->vehstatus = VS_HIDDEN | VS_DEFPAL; @@ -761,7 +761,7 @@ CommandCost CmdBuildRailVehicle(DoComman v->owner = _current_company; v->x_pos = x; v->y_pos = y; - v->z_pos = GetSlopePixelZ(x, y); + v->z_pos = GetSlopePixelZ(x, y, true); v->track = TRACK_BIT_DEPOT; v->vehstatus = VS_HIDDEN | VS_STOPPED | VS_DEFPAL; v->spritenum = rvi->image_index; diff --git a/src/tree_cmd.cpp b/src/tree_cmd.cpp --- a/src/tree_cmd.cpp +++ b/src/tree_cmd.cpp @@ -586,7 +586,7 @@ static void DrawTile_Trees(TileInfo *ti) } -static int GetSlopePixelZ_Trees(TileIndex tile, uint x, uint y) +static int GetSlopePixelZ_Trees(TileIndex tile, uint x, uint y, bool ground_vehicle) { int z; Slope tileh = GetTilePixelSlope(tile, &z); diff --git a/src/tunnelbridge_cmd.cpp b/src/tunnelbridge_cmd.cpp --- a/src/tunnelbridge_cmd.cpp +++ b/src/tunnelbridge_cmd.cpp @@ -1663,7 +1663,7 @@ void DrawBridgeMiddle(const TileInfo *ti } -static int GetSlopePixelZ_TunnelBridge(TileIndex tile, uint x, uint y) +static int GetSlopePixelZ_TunnelBridge(TileIndex tile, uint x, uint y, bool ground_vehicle) { int z; Slope tileh = GetTilePixelSlope(tile, &z); @@ -1672,18 +1672,14 @@ static int GetSlopePixelZ_TunnelBridge(T y &= 0xF; if (IsTunnel(tile)) { - uint pos = (DiagDirToAxis(GetTunnelBridgeDirection(tile)) == AXIS_X ? y : x); - /* In the tunnel entrance? */ - if (5 <= pos && pos <= 10) return z; + if (ground_vehicle) return z; } else { // IsBridge(tile) DiagDirection dir = GetTunnelBridgeDirection(tile); - uint pos = (DiagDirToAxis(dir) == AXIS_X ? y : x); - z += ApplyPixelFoundationToSlope(GetBridgeFoundation(tileh, DiagDirToAxis(dir)), &tileh); /* On the bridge ramp? */ - if (5 <= pos && pos <= 10) { + if (ground_vehicle) { int delta; if (tileh != SLOPE_FLAT) return z + TILE_HEIGHT; @@ -1881,7 +1877,7 @@ extern const byte _tunnel_visibility_fra static VehicleEnterTileStatus VehicleEnter_TunnelBridge(Vehicle *v, TileIndex tile, int x, int y) { - int z = GetSlopePixelZ(x, y) - v->z_pos; + int z = GetSlopePixelZ(x, y, true) - v->z_pos; if (abs(z) > 2) return VETSB_CANNOT_ENTER; /* Direction into the wormhole */ diff --git a/src/void_cmd.cpp b/src/void_cmd.cpp --- a/src/void_cmd.cpp +++ b/src/void_cmd.cpp @@ -25,7 +25,7 @@ static void DrawTile_Void(TileInfo *ti) } -static int GetSlopePixelZ_Void(TileIndex tile, uint x, uint y) +static int GetSlopePixelZ_Void(TileIndex tile, uint x, uint y, bool ground_vehicle) { /* This function may be called on tiles outside the map, don't assume * that 'tile' is a valid tile index. See GetSlopePixelZOutsideMap. */ diff --git a/src/water_cmd.cpp b/src/water_cmd.cpp --- a/src/water_cmd.cpp +++ b/src/water_cmd.cpp @@ -936,7 +936,7 @@ void DrawShipDepotSprite(int x, int y, A } -static int GetSlopePixelZ_Water(TileIndex tile, uint x, uint y) +static int GetSlopePixelZ_Water(TileIndex tile, uint x, uint y, bool ground_vehicle) { int z; Slope tileh = GetTilePixelSlope(tile, &z);