summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/landscape.cpp85
-rw-r--r--src/landscape.h1
-rw-r--r--src/rail_cmd.cpp188
-rw-r--r--src/slope.h91
4 files changed, 275 insertions, 90 deletions
diff --git a/src/landscape.cpp b/src/landscape.cpp
index ddb1d73a8..c59d4a17c 100644
--- a/src/landscape.cpp
+++ b/src/landscape.cpp
@@ -76,6 +76,16 @@ uint ApplyFoundationToSlope(Foundation f, Slope *s)
return TILE_HEIGHT;
}
+ if (f != FOUNDATION_STEEP_BOTH && IsNonContinuousFoundation(f)) {
+ *s = HalftileSlope(*s, GetHalftileFoundationCorner(f));
+ return 0;
+ }
+
+ if (IsSpecialRailFoundation(f)) {
+ *s = SlopeWithThreeCornersRaised(OppositeCorner(GetRailFoundationCorner(f)));
+ return 0;
+ }
+
uint dz = IsSteepSlope(*s) ? TILE_HEIGHT : 0;
Corner highest_corner = GetHighestSlopeCorner(*s);
@@ -92,8 +102,8 @@ uint ApplyFoundationToSlope(Foundation f, Slope *s)
*s = SlopeWithOneCornerRaised(highest_corner);
break;
- case FOUNDATION_STEEP_HIGHER:
- *s = SlopeWithThreeCornersRaised(OppositeCorner(highest_corner));
+ case FOUNDATION_STEEP_BOTH:
+ *s = HalftileSlope(SlopeWithOneCornerRaised(highest_corner), highest_corner);
break;
default: NOT_REACHED();
@@ -229,6 +239,24 @@ uint GetSlopeZ(int x, int y)
}
/**
+ * Determine the Z height of a corner relative to TileZ.
+ *
+ * @pre The slope must not be a halftile slope.
+ *
+ * @param tileh The slope.
+ * @param corner The corner.
+ * @return Z position of corner relative to TileZ.
+ */
+int GetSlopeZInCorner(Slope tileh, Corner corner)
+{
+ assert(!IsHalftileSlope(tileh));
+ static const int _corner_slopes[4][2] = {
+ { SLOPE_W, SLOPE_STEEP_W }, { SLOPE_S, SLOPE_STEEP_S }, { SLOPE_E, SLOPE_STEEP_E }, { SLOPE_N, SLOPE_STEEP_N }
+ };
+ return ((tileh & _corner_slopes[corner][0]) != 0 ? TILE_HEIGHT : 0) + (tileh == _corner_slopes[corner][1] ? TILE_HEIGHT : 0);
+}
+
+/**
* Determine the Z height of the corners of a specific tile edge
*
* @note If a tile has a non-continuous halftile foundation, a corner can have different heights wrt. it's edges.
@@ -308,6 +336,9 @@ void DrawFoundation(TileInfo *ti, Foundation f)
{
if (!IsFoundation(f)) return;
+ /* Two part foundations must be drawn separately */
+ assert(f != FOUNDATION_STEEP_BOTH);
+
uint sprite_block = 0;
uint z;
Slope slope = GetFoundationSlope(ti->tile, &z);
@@ -324,13 +355,15 @@ void DrawFoundation(TileInfo *ti, Foundation f)
/* Use the original slope sprites if NW and NE borders should be visible */
SpriteID leveled_base = (sprite_block == 0 ? (int)SPR_FOUNDATION_BASE : (SPR_SLOPES_VIRTUAL_BASE + sprite_block * SPR_TRKFOUND_BLOCK_SIZE));
SpriteID inclined_base = SPR_SLOPES_VIRTUAL_BASE + SPR_SLOPES_INCLINED_OFFSET + sprite_block * SPR_TRKFOUND_BLOCK_SIZE;
- //SpriteID halftile_base = SPR_HALFTILE_FOUNDATION_BASE + sprite_block * SPR_HALFTILE_BLOCK_SIZE;
+ SpriteID halftile_base = SPR_HALFTILE_FOUNDATION_BASE + sprite_block * SPR_HALFTILE_BLOCK_SIZE;
if (IsSteepSlope(ti->tileh)) {
- /* Lower part of foundation */
- AddSortableSpriteToDraw(
- leveled_base + (ti->tileh & ~SLOPE_STEEP), PAL_NONE, ti->x, ti->y, 16, 16, 7, ti->z
- );
+ if (!IsNonContinuousFoundation(f)) {
+ /* Lower part of foundation */
+ AddSortableSpriteToDraw(
+ leveled_base + (ti->tileh & ~SLOPE_STEEP), PAL_NONE, ti->x, ti->y, 16, 16, 7, ti->z
+ );
+ }
Corner highest_corner = GetHighestSlopeCorner(ti->tileh);
ti->z += ApplyFoundationToSlope(f, &ti->tileh);
@@ -341,24 +374,42 @@ void DrawFoundation(TileInfo *ti, Foundation f)
AddSortableSpriteToDraw(inclined_base + inclined, PAL_NONE, ti->x, ti->y, 16, 16, 1, ti->z);
OffsetGroundSprite(31, 9);
- } else if (f >= FOUNDATION_STEEP_HIGHER) {
- /* three corners raised:
- * Draw inclined foundations for both axes, that results in the needed image.
- */
- SpriteID upper = inclined_base + highest_corner * 2;
-
- AddSortableSpriteToDraw(upper, PAL_NONE, ti->x, ti->y, 16, 16, 1, ti->z);
- AddChildSpriteScreen(upper + 1, PAL_NONE, 31, 9);
- OffsetGroundSprite(31, 9);
- } else {
+ } else if (f == FOUNDATION_STEEP_LOWER) {
/* one corner raised */
OffsetGroundSprite(31, 1);
+ } else {
+ /* halftile foundation */
+ int x_bb = (((highest_corner == CORNER_W) || (highest_corner == CORNER_S)) ? 8 : 0);
+ int y_bb = (((highest_corner == CORNER_S) || (highest_corner == CORNER_E)) ? 8 : 0);
+
+ AddSortableSpriteToDraw(halftile_base + highest_corner, PAL_NONE, ti->x + x_bb, ti->y + y_bb, 8, 8, 7, ti->z + TILE_HEIGHT);
+ OffsetGroundSprite(31, 9);
}
} else {
if (IsLeveledFoundation(f)) {
/* leveled foundation */
AddSortableSpriteToDraw(leveled_base + ti->tileh, PAL_NONE, ti->x, ti->y, 16, 16, 7, ti->z);
OffsetGroundSprite(31, 1);
+ } else if (IsNonContinuousFoundation(f)) {
+ /* halftile foundation */
+ Corner halftile_corner = GetHalftileFoundationCorner(f);
+ int x_bb = (((halftile_corner == CORNER_W) || (halftile_corner == CORNER_S)) ? 8 : 0);
+ int y_bb = (((halftile_corner == CORNER_S) || (halftile_corner == CORNER_E)) ? 8 : 0);
+
+ AddSortableSpriteToDraw(halftile_base + halftile_corner, PAL_NONE, ti->x + x_bb, ti->y + y_bb, 8, 8, 7, ti->z);
+ OffsetGroundSprite(31, 9);
+ } else if (IsSpecialRailFoundation(f)) {
+ /* anti-zig-zag foundation */
+ SpriteID spr;
+ if (ti->tileh == SLOPE_NS || ti->tileh == SLOPE_EW) {
+ /* half of leveled foundation under track corner */
+ spr = leveled_base + SlopeWithThreeCornersRaised(GetRailFoundationCorner(f));
+ } else {
+ /* tile-slope = sloped along X/Y, foundation-slope = three corners raised */
+ spr = inclined_base + 2 * GetRailFoundationCorner(f) + ((ti->tileh == SLOPE_SW || ti->tileh == SLOPE_NE) ? 1 : 0);
+ }
+ AddSortableSpriteToDraw(spr, PAL_NONE, ti->x, ti->y, 16, 16, 7, ti->z);
+ OffsetGroundSprite(31, 9);
} else {
/* inclined foundation */
byte inclined = GetHighestSlopeCorner(ti->tileh) * 2 + (f == FOUNDATION_INCLINED_Y ? 1 : 0);
diff --git a/src/landscape.h b/src/landscape.h
index a4b558384..81b180d1a 100644
--- a/src/landscape.h
+++ b/src/landscape.h
@@ -26,6 +26,7 @@ bool IsValidTile(TileIndex tile);
uint GetPartialZ(int x, int y, Slope corners);
uint GetSlopeZ(int x, int y);
void GetSlopeZOnEdge(Slope tileh, DiagDirection edge, int *z1, int *z2);
+int GetSlopeZInCorner(Slope tileh, Corner corner);
static inline Point RemapCoords(int x, int y, int z)
{
diff --git a/src/rail_cmd.cpp b/src/rail_cmd.cpp
index 638d70c63..7c7409e5d 100644
--- a/src/rail_cmd.cpp
+++ b/src/rail_cmd.cpp
@@ -215,19 +215,35 @@ Foundation GetRailFoundation(Slope tileh, TrackBits bits)
TrackBits higher_track = CornerToTrackBits(highest_corner);
/* Only higher track? */
- if (bits == higher_track) return FOUNDATION_STEEP_HIGHER;
+ if (bits == higher_track) return HalftileFoundation(highest_corner);
/* Overlap with higher track? */
if (TracksOverlap(bits | higher_track)) return FOUNDATION_INVALID;
/* either lower track or both higher and lower track */
- return ((bits & higher_track) != 0 ? FOUNDATION_INVALID : FOUNDATION_STEEP_LOWER);
+ return ((bits & higher_track) != 0 ? FOUNDATION_STEEP_BOTH : FOUNDATION_STEEP_LOWER);
} else {
if ((~_valid_tracks_without_foundation[tileh] & bits) == 0) return FOUNDATION_NONE;
bool valid_on_leveled = ((~_valid_tracks_on_leveled_foundation[tileh] & bits) == 0);
+ Corner track_corner;
switch (bits) {
+ case TRACK_BIT_LEFT: track_corner = CORNER_W; break;
+ case TRACK_BIT_LOWER: track_corner = CORNER_S; break;
+ case TRACK_BIT_RIGHT: track_corner = CORNER_E; break;
+ case TRACK_BIT_UPPER: track_corner = CORNER_N; break;
+
+ case TRACK_BIT_HORZ:
+ if (tileh == SLOPE_N) return HalftileFoundation(CORNER_N);
+ if (tileh == SLOPE_S) return HalftileFoundation(CORNER_S);
+ return (valid_on_leveled ? FOUNDATION_LEVELED : FOUNDATION_INVALID);
+
+ case TRACK_BIT_VERT:
+ if (tileh == SLOPE_W) return HalftileFoundation(CORNER_W);
+ if (tileh == SLOPE_E) return HalftileFoundation(CORNER_E);
+ return (valid_on_leveled ? FOUNDATION_LEVELED : FOUNDATION_INVALID);
+
case TRACK_BIT_X:
if (HasSlopeHighestCorner(tileh)) return FOUNDATION_INCLINED_X;
return (valid_on_leveled ? FOUNDATION_LEVELED : FOUNDATION_INVALID);
@@ -239,6 +255,19 @@ Foundation GetRailFoundation(Slope tileh, TrackBits bits)
default:
return (valid_on_leveled ? FOUNDATION_LEVELED : FOUNDATION_INVALID);
}
+ /* Single diagonal track */
+
+ /* Track must be at least valid on leveled foundation */
+ if (!valid_on_leveled) return FOUNDATION_INVALID;
+
+ /* If slope has three raised corners, build leveled foundation */
+ if (HasSlopeHighestCorner(ComplementSlope(tileh))) return FOUNDATION_LEVELED;
+
+ /* If neighboured corners of track_corner are lowered, build halftile foundation */
+ if ((tileh & SlopeWithThreeCornersRaised(OppositeCorner(track_corner))) == SlopeWithOneCornerRaised(track_corner)) return HalftileFoundation(track_corner);
+
+ /* else special anti-zig-zag foundation */
+ return SpecialRailFoundation(track_corner);
}
}
@@ -1422,41 +1451,64 @@ static void DrawTrackDetails(const TileInfo* ti)
static void DrawTrackBits(TileInfo* ti, TrackBits track)
{
const RailtypeInfo *rti = GetRailTypeInfo(GetRailType(ti->tile));
+ RailGroundType rgt = GetRailGroundType(ti->tile);
+ Foundation f = GetRailFoundation(ti->tileh, track);
+ Corner halftile_corner = CORNER_INVALID;
+
+ if (IsNonContinuousFoundation(f)) {
+ /* Save halftile corner */
+ halftile_corner = (f == FOUNDATION_STEEP_BOTH ? GetHighestSlopeCorner(ti->tileh) : GetHalftileFoundationCorner(f));
+ /* Draw lower part first */
+ track &= ~CornerToTrackBits(halftile_corner);
+ f = (f == FOUNDATION_STEEP_BOTH ? FOUNDATION_STEEP_LOWER : FOUNDATION_NONE);
+ }
+
+ DrawFoundation(ti, f);
+ /* DrawFoundation modifies ti */
+
SpriteID image;
SpriteID pal = PAL_NONE;
bool junction = false;
/* Select the sprite to use. */
- (image = rti->base_sprites.track_y, track == TRACK_BIT_Y) ||
- (image++, track == TRACK_BIT_X) ||
- (image++, track == TRACK_BIT_UPPER) ||
- (image++, track == TRACK_BIT_LOWER) ||
- (image++, track == TRACK_BIT_RIGHT) ||
- (image++, track == TRACK_BIT_LEFT) ||
- (image++, track == TRACK_BIT_CROSS) ||
-
- (image = rti->base_sprites.track_ns, track == TRACK_BIT_HORZ) ||
- (image++, track == TRACK_BIT_VERT) ||
-
- (junction = true, false) ||
- (image = rti->base_sprites.ground, (track & TRACK_BIT_3WAY_NE) == 0) ||
- (image++, (track & TRACK_BIT_3WAY_SW) == 0) ||
- (image++, (track & TRACK_BIT_3WAY_NW) == 0) ||
- (image++, (track & TRACK_BIT_3WAY_SE) == 0) ||
- (image++, true);
-
- if (ti->tileh != SLOPE_FLAT) {
- DrawFoundation(ti, GetRailFoundation(ti->tileh, track));
-
- /* DrawFoundation() modifies it.
- * Default sloped sprites.. */
- if (ti->tileh != SLOPE_FLAT) image = _track_sloped_sprites[ti->tileh - 1] + rti->base_sprites.track_y;
- }
+ if (track == 0) {
+ /* Clear ground (only track on halftile foundation) */
+ switch (rgt) {
+ case RAIL_GROUND_BARREN: image = SPR_FLAT_BARE_LAND; break;
+ case RAIL_GROUND_ICE_DESERT: image = SPR_FLAT_SNOWY_TILE; break;
+ default: image = SPR_FLAT_GRASS_TILE; break;
+ }
+ image += _tileh_to_sprite[ti->tileh];
+ } else {
+ if (ti->tileh != SLOPE_FLAT) {
+ /* track on non-flat ground */
+ image = _track_sloped_sprites[ti->tileh - 1] + rti->base_sprites.track_y;
+ } else {
+ /* track on flat ground */
+ (image = rti->base_sprites.track_y, track == TRACK_BIT_Y) ||
+ (image++, track == TRACK_BIT_X) ||
+ (image++, track == TRACK_BIT_UPPER) ||
+ (image++, track == TRACK_BIT_LOWER) ||
+ (image++, track == TRACK_BIT_RIGHT) ||
+ (image++, track == TRACK_BIT_LEFT) ||
+ (image++, track == TRACK_BIT_CROSS) ||
+
+ (image = rti->base_sprites.track_ns, track == TRACK_BIT_HORZ) ||
+ (image++, track == TRACK_BIT_VERT) ||
+
+ (junction = true, false) ||
+ (image = rti->base_sprites.ground, (track & TRACK_BIT_3WAY_NE) == 0) ||
+ (image++, (track & TRACK_BIT_3WAY_SW) == 0) ||
+ (image++, (track & TRACK_BIT_3WAY_NW) == 0) ||
+ (image++, (track & TRACK_BIT_3WAY_SE) == 0) ||
+ (image++, true);
+ }
- switch (GetRailGroundType(ti->tile)) {
- case RAIL_GROUND_BARREN: pal = PALETTE_TO_BARE_LAND; break;
- case RAIL_GROUND_ICE_DESERT: image += rti->snow_offset; break;
- default: break;
+ switch (rgt) {
+ case RAIL_GROUND_BARREN: pal = PALETTE_TO_BARE_LAND; break;
+ case RAIL_GROUND_ICE_DESERT: image += rti->snow_offset; break;
+ default: break;
+ }
}
DrawGroundSprite(image, pal);
@@ -1470,6 +1522,30 @@ static void DrawTrackBits(TileInfo* ti, TrackBits track)
if (track & TRACK_BIT_LEFT) DrawGroundSprite(rti->base_sprites.single_w, PAL_NONE);
if (track & TRACK_BIT_RIGHT) DrawGroundSprite(rti->base_sprites.single_e, PAL_NONE);
}
+
+ if (IsValidCorner(halftile_corner)) {
+ DrawFoundation(ti, HalftileFoundation(halftile_corner));
+
+ /* Draw higher halftile-overlay: Use the sloped sprites with three corners raised. They probably best fit the lightning. */
+ Slope fake_slope = SlopeWithThreeCornersRaised(OppositeCorner(halftile_corner));
+ image = _track_sloped_sprites[fake_slope - 1] + rti->base_sprites.track_y;
+ pal = PAL_NONE;
+ switch (rgt) {
+ case RAIL_GROUND_BARREN: pal = PALETTE_TO_BARE_LAND; break;
+ case RAIL_GROUND_ICE_DESERT: image += rti->snow_offset; break;
+ default: break;
+ }
+
+ static const int INF = 1000; // big number compared to tilesprite size
+ static const SubSprite _halftile_sub_sprite[4] = {
+ { -INF , -INF , 32 - 33, INF }, // CORNER_W, clip 33 pixels from right
+ { -INF , 0 + 7, INF , INF }, // CORNER_S, clip 7 pixels from top
+ { -31 + 33, -INF , INF , INF }, // CORNER_E, clip 33 pixels from left
+ { -INF , -INF , INF , 30 - 23 } // CORNER_N, clip 23 pixels from bottom
+ };
+
+ DrawGroundSprite(image, pal, &(_halftile_sub_sprite[halftile_corner]));
+ }
}
static void DrawSignals(TileIndex tile, TrackBits rails)
@@ -2289,52 +2365,24 @@ static CommandCost TerraformTile_Track(TileIndex tile, uint32 flags, uint z_new,
CommandCost autoslope_result = TestAutoslopeOnRailTile(tile, flags, z_old, tileh_old, z_new, tileh_new, rail_bits);
/* When there is only a single horizontal/vertical track, one corner can be terraformed. */
- Slope allowed_corner;
+ Corner allowed_corner;
switch (rail_bits) {
- case TRACK_BIT_RIGHT: allowed_corner = SLOPE_W; break;
- case TRACK_BIT_UPPER: allowed_corner = SLOPE_S; break;
- case TRACK_BIT_LEFT: allowed_corner = SLOPE_E; break;
- case TRACK_BIT_LOWER: allowed_corner = SLOPE_N; break;
+ case TRACK_BIT_RIGHT: allowed_corner = CORNER_W; break;
+ case TRACK_BIT_UPPER: allowed_corner = CORNER_S; break;
+ case TRACK_BIT_LEFT: allowed_corner = CORNER_E; break;
+ case TRACK_BIT_LOWER: allowed_corner = CORNER_N; break;
default: return autoslope_result;
}
- Slope track_corners = ComplementSlope(allowed_corner);
-
Foundation f_old = GetRailFoundation(tileh_old, rail_bits);
- switch (f_old) {
- case FOUNDATION_NONE:
- /* Everything is valid, which only changes allowed_corner */
-
- /* Compute height of track */
- if (tileh_old == track_corners) z_old += TILE_HEIGHT;
- if (tileh_new == track_corners) {
- z_new += TILE_HEIGHT;
- } else {
- /* do not build a foundation */
- if ((tileh_new != SLOPE_FLAT) && (tileh_new != allowed_corner)) return autoslope_result;
- }
-
- /* Track height must remain unchanged */
- if (z_old != z_new) return autoslope_result;
- break;
-
- case FOUNDATION_LEVELED:
- /* Is allowed_corner covered by the foundation? */
- if ((tileh_old & allowed_corner) == 0) return autoslope_result;
-
- /* allowed_corner may only be raised -> steep slope */
- if ((z_old != z_new) || (tileh_new != (tileh_old | SLOPE_STEEP))) return autoslope_result;
- break;
-
- case FOUNDATION_STEEP_LOWER:
- /* Only allow to lower highest corner */
- if ((z_old != z_new) || (tileh_new != (tileh_old & ~SLOPE_STEEP))) return autoslope_result;
- break;
- case FOUNDATION_STEEP_HIGHER:
- return autoslope_result;
+ /* Do not allow terraforming if allowed_corner is part of anti-zig-zag foundations */
+ if (tileh_old != SLOPE_NS && tileh_old != SLOPE_EW && IsSpecialRailFoundation(f_old)) return autoslope_result;
- default: NOT_REACHED();
+ /* Everything is valid, which only changes allowed_corner */
+ for (Corner corner = (Corner)0; corner < CORNER_END; corner = (Corner)(corner + 1)) {
+ if (allowed_corner == corner) continue;
+ if (z_old + GetSlopeZInCorner(tileh_old, corner) != z_new + GetSlopeZInCorner(tileh_new, corner)) return autoslope_result;
}
/* Make the ground dirty */
diff --git a/src/slope.h b/src/slope.h
index 3a983f577..987bf6664 100644
--- a/src/slope.h
+++ b/src/slope.h
@@ -16,7 +16,8 @@ enum Corner {
CORNER_S = 1,
CORNER_E = 2,
CORNER_N = 3,
- CORNER_END
+ CORNER_END,
+ CORNER_INVALID = 0xFF
};
/**
@@ -234,8 +235,20 @@ enum Foundation {
FOUNDATION_LEVELED, ///< The tile is leveled up to a flat slope.
FOUNDATION_INCLINED_X, ///< The tile has an along X-axis inclined foundation.
FOUNDATION_INCLINED_Y, ///< The tile has an along Y-axis inclined foundation.
- FOUNDATION_STEEP_LOWER, ///< The tile has a steep slope. The lowerst corner is raised by a foundation to allow building railroad on the lower halftile.
- FOUNDATION_STEEP_HIGHER, ///< The tile has a steep slope. Three corners are raised by a foundation to allow building railroad on the higher halftile.
+ FOUNDATION_STEEP_LOWER, ///< The tile has a steep slope. The lowest corner is raised by a foundation to allow building railroad on the lower halftile.
+
+/* Halftile foundations */
+ FOUNDATION_STEEP_BOTH, ///< The tile has a steep slope. The lowest corner is raised by a foundation and the upper halftile is leveled.
+ FOUNDATION_HALFTILE_W, ///< Level west halftile non-continuously.
+ FOUNDATION_HALFTILE_S, ///< Level south halftile non-continuously.
+ FOUNDATION_HALFTILE_E, ///< Level east halftile non-continuously.
+ FOUNDATION_HALFTILE_N, ///< Level north halftile non-continuously.
+
+/* Special anti-zig-zag foundations for single horizontal/vertical track */
+ FOUNDATION_RAIL_W, ///< Foundation for TRACK_BIT_LEFT, but not a leveled foundation.
+ FOUNDATION_RAIL_S, ///< Foundation for TRACK_BIT_LOWER, but not a leveled foundation.
+ FOUNDATION_RAIL_E, ///< Foundation for TRACK_BIT_RIGHT, but not a leveled foundation.
+ FOUNDATION_RAIL_N, ///< Foundation for TRACK_BIT_UPPER, but not a leveled foundation.
FOUNDATION_INVALID = 0xFF ///< Used inside "rail_cmd.cpp" to indicate invalid slope/track combination.
};
@@ -274,6 +287,54 @@ static inline bool IsInclinedFoundation(Foundation f)
}
/**
+ * Tests if a foundation is a non-continuous foundation, i.e. halftile-foundation or FOUNDATION_STEEP_BOTH.
+ *
+ * @param f The #Foundation.
+ * @return true iff f is a non-continuous foundation
+ */
+static inline bool IsNonContinuousFoundation(Foundation f)
+{
+ return IS_INT_INSIDE(f, FOUNDATION_STEEP_BOTH, FOUNDATION_HALFTILE_N + 1);
+}
+
+/**
+ * Returns the halftile corner of a halftile-foundation
+ *
+ * @pre f != FOUNDATION_STEEP_BOTH
+ *
+ * @param f The #Foundation.
+ * @return The #Corner with track.
+ */
+static inline Corner GetHalftileFoundationCorner(Foundation f)
+{
+ assert(IS_INT_INSIDE(f, FOUNDATION_HALFTILE_W, FOUNDATION_HALFTILE_N + 1));
+ return (Corner)(f - FOUNDATION_HALFTILE_W);
+}
+
+/**
+ * Tests if a foundation is a special rail foundation for single horizontal/vertical track.
+ *
+ * @param f The #Foundation.
+ * @return true iff f is a special rail foundation for single horizontal/vertical track.
+ */
+static inline bool IsSpecialRailFoundation(Foundation f)
+{
+ return IS_INT_INSIDE(f, FOUNDATION_RAIL_W, FOUNDATION_RAIL_N + 1);
+}
+
+/**
+ * Returns the track corner of a special rail foundation
+ *
+ * @param f The #Foundation.
+ * @return The #Corner with track.
+ */
+static inline Corner GetRailFoundationCorner(Foundation f)
+{
+ assert(IsSpecialRailFoundation(f));
+ return (Corner)(f - FOUNDATION_RAIL_W);
+}
+
+/**
* Returns the foundation needed to flatten a slope.
* The returned foundation is either FOUNDATION_NONE if the tile was already flat, or FOUNDATION_LEVELED.
*
@@ -298,4 +359,28 @@ static inline Foundation InclinedFoundation(Axis axis)
return (axis == AXIS_X ? FOUNDATION_INCLINED_X : FOUNDATION_INCLINED_Y);
}
+/**
+ * Returns the halftile foundation for single horizontal/vertical track.
+ *
+ * @param corner The #Corner with the track.
+ * @return The wanted #Foundation.
+ */
+static inline Foundation HalftileFoundation(Corner corner)
+{
+ assert(IsValidCorner(corner));
+ return (Foundation)(FOUNDATION_HALFTILE_W + corner);
+}
+
+/**
+ * Returns the special rail foundation for single horizontal/vertical track.
+ *
+ * @param corner The #Corner with the track.
+ * @return The wanted #Foundation.
+ */
+static inline Foundation SpecialRailFoundation(Corner corner)
+{
+ assert(IsValidCorner(corner));
+ return (Foundation)(FOUNDATION_RAIL_W + corner);
+}
+
#endif /* SLOPE_H */