changeset 7703:b20195746c34 draft

(svn r11237) -Codechange: reduce code duplication between GetRailFoundation() and CheckRailSlope(). Patch by frosch.
author rubidium <rubidium@openttd.org>
date Tue, 09 Oct 2007 21:11:23 +0000 (2007-10-09)
parents 40591c7d4bd4
children 2732cf9f8b9b
files src/rail.cpp src/rail.h src/rail_cmd.cpp src/slope.h
diffstat 4 files changed, 111 insertions(+), 51 deletions(-) [+]
line wrap: on
line diff
--- a/src/rail.cpp
+++ b/src/rail.cpp
@@ -103,6 +103,10 @@
 	TRACKDIR_X_NE, TRACKDIR_Y_SE, TRACKDIR_X_SW, TRACKDIR_Y_NW,
 };
 
+extern const TrackBits _corner_to_trackbits[] = {
+	TRACK_BIT_LEFT, TRACK_BIT_LOWER, TRACK_BIT_RIGHT, TRACK_BIT_UPPER,
+};
+
 
 RailType GetTileRailType(TileIndex tile)
 {
--- a/src/rail.h
+++ b/src/rail.h
@@ -120,6 +120,19 @@
 	return TrackToTrackBits(AxisToTrack(a));
 }
 
+/**
+ * Returns a single horizontal/vertical trackbit, that is in a specific tile corner.
+ *
+ * @param corner The corner of a tile.
+ * @return The TrackBits of the track in the corner.
+ */
+static inline TrackBits CornerToTrackBits(Corner corner)
+{
+	extern const TrackBits _corner_to_trackbits[];
+	assert(IsValidCorner(corner));
+	return _corner_to_trackbits[corner];
+}
+
 
 /**
  * Enumeration for tracks and directions.
--- a/src/rail_cmd.cpp
+++ b/src/rail_cmd.cpp
@@ -150,10 +150,8 @@
 }
 
 
-static const TrackBits _valid_tileh_slopes[][15] = {
-
-/* set of normal ones */
-{
+/** Valid TrackBits on a specific (non-steep)-slope without foundation */
+static const TrackBits _valid_tracks_without_foundation[15] = {
 	TRACK_BIT_ALL,
 	TRACK_BIT_RIGHT,
 	TRACK_BIT_UPPER,
@@ -172,10 +170,10 @@
 	TRACK_BIT_X,
 	TRACK_BIT_UPPER,
 	TRACK_BIT_RIGHT,
-},
+};
 
-/* allowed rail for an evenly raised platform */
-{
+/** Valid TrackBits on a specific (non-steep)-slope with leveled foundation */
+static const TrackBits _valid_tracks_on_leveled_foundation[15] = {
 	TRACK_BIT_NONE,
 	TRACK_BIT_LEFT,
 	TRACK_BIT_LOWER,
@@ -194,62 +192,82 @@
 	TRACK_BIT_Y | TRACK_BIT_UPPER | TRACK_BIT_RIGHT,
 	TRACK_BIT_ALL,
 	TRACK_BIT_ALL
-}
 };
 
+/**
+ * Checks if a track combination is valid on a specific slope and returns the needed foundation.
+ *
+ * @param tileh Tile slope.
+ * @param bits  Trackbits.
+ * @return Needed foundation or FOUNDATION_INVALID if track/slope combination is not allowed.
+ */
 Foundation GetRailFoundation(Slope tileh, TrackBits bits)
 {
-	if (!IsSteepSlope(tileh)) {
-		if ((~_valid_tileh_slopes[0][tileh] & bits) == 0) return FOUNDATION_NONE;
-		if ((~_valid_tileh_slopes[1][tileh] & bits) == 0) return FOUNDATION_LEVELED;
-	}
+	if (bits == TRACK_BIT_NONE) return FOUNDATION_NONE;
+
+	if (IsSteepSlope(tileh)) {
+		/* Test for inclined foundations */
+		if (bits == TRACK_BIT_X) return FOUNDATION_INCLINED_X;
+		if (bits == TRACK_BIT_Y) return FOUNDATION_INCLINED_Y;
+
+		/* Get higher track */
+		Corner highest_corner = GetHighestSlopeCorner(tileh);
+		TrackBits higher_track = CornerToTrackBits(highest_corner);
+
+		/* Only higher track? */
+		if (bits == higher_track) return FOUNDATION_STEEP_HIGHER;
+
+		/* Overlap with higher track? */
+		if (TracksOverlap(bits | higher_track)) return FOUNDATION_INVALID;
 
-	switch (bits) {
-		default: NOT_REACHED();
-		case TRACK_BIT_X:     return FOUNDATION_INCLINED_X;
-		case TRACK_BIT_Y:     return FOUNDATION_INCLINED_Y;
-		case TRACK_BIT_LEFT:  return (tileh == SLOPE_STEEP_W ? FOUNDATION_STEEP_HIGHER : FOUNDATION_STEEP_LOWER);
-		case TRACK_BIT_LOWER: return (tileh == SLOPE_STEEP_S ? FOUNDATION_STEEP_HIGHER : FOUNDATION_STEEP_LOWER);
-		case TRACK_BIT_RIGHT: return (tileh == SLOPE_STEEP_E ? FOUNDATION_STEEP_HIGHER : FOUNDATION_STEEP_LOWER);
-		case TRACK_BIT_UPPER: return (tileh == SLOPE_STEEP_N ? FOUNDATION_STEEP_HIGHER : FOUNDATION_STEEP_LOWER);
+		/* either lower track or both higher and lower track */
+		return ((bits & higher_track) != 0 ? FOUNDATION_INVALID : 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);
+
+		switch (bits) {
+			case TRACK_BIT_X:
+				if (HasSlopeHighestCorner(tileh)) return FOUNDATION_INCLINED_X;
+				return (valid_on_leveled ? FOUNDATION_LEVELED : FOUNDATION_INVALID);
+
+			case TRACK_BIT_Y:
+				if (HasSlopeHighestCorner(tileh)) return FOUNDATION_INCLINED_Y;
+				return (valid_on_leveled ? FOUNDATION_LEVELED : FOUNDATION_INVALID);
+
+			default:
+				return (valid_on_leveled ? FOUNDATION_LEVELED : FOUNDATION_INVALID);
+		}
 	}
 }
 
 
+/**
+ * Tests if a track can be build on a tile.
+ *
+ * @param tileh Tile slope.
+ * @param rail_bits Tracks to build.
+ * @param existing Tracks already built.
+ * @param tile Tile (used for water test)
+ * @return Error message or cost for foundation building.
+ */
 static CommandCost CheckRailSlope(Slope tileh, TrackBits rail_bits, TrackBits existing, TileIndex tile)
 {
-	if (IsSteepSlope(tileh)) {
-		if (_patches.build_on_slopes && existing == 0) {
-			/* There may only be one track on steep slopes. (Autoslope calls with multiple bits in rail_bits) */
-			if (KILL_FIRST_BIT(rail_bits & TRACK_BIT_MASK) == 0) {
-				TrackBits valid = TRACK_BIT_CROSS | (HASBIT(1 << SLOPE_STEEP_W | 1 << SLOPE_STEEP_E, tileh) ? TRACK_BIT_VERT : TRACK_BIT_HORZ);
-				if (valid & rail_bits) return _price.terraform;
-			}
-		}
-	} else {
-		rail_bits |= existing;
+	/* don't allow building on the lower side of a coast */
+	if (IsTileType(tile, MP_WATER)) {
+		if (!IsSteepSlope(tileh) && ((~_valid_tracks_on_leveled_foundation[tileh] & (rail_bits | existing)) != 0)) return_cmd_error(STR_3807_CAN_T_BUILD_ON_WATER);
+	}
+
+	Foundation f_new = GetRailFoundation(tileh, rail_bits | existing);
 
-		/* don't allow building on the lower side of a coast */
-		if (IsTileType(tile, MP_WATER) &&
-				~_valid_tileh_slopes[1][tileh] & rail_bits) {
-			return_cmd_error(STR_3807_CAN_T_BUILD_ON_WATER);
-		}
+	/* check track/slope combination */
+	if ((f_new == FOUNDATION_INVALID) ||
+	    ((f_new != FOUNDATION_NONE) && (!_patches.build_on_slopes || _is_old_ai_player))
+	   ) return_cmd_error(STR_1000_LAND_SLOPED_IN_WRONG_DIRECTION);
 
-		/* no special foundation */
-		if ((~_valid_tileh_slopes[0][tileh] & rail_bits) == 0) {
-			return CommandCost();
-		} else if (!_patches.build_on_slopes || _is_old_ai_player) {
-			return_cmd_error(STR_1000_LAND_SLOPED_IN_WRONG_DIRECTION);
-		}
-
-		if ((~_valid_tileh_slopes[1][tileh] & rail_bits) == 0 || ( // whole tile is leveled up
-					(rail_bits == TRACK_BIT_X || rail_bits == TRACK_BIT_Y) &&
-					(tileh == SLOPE_W || tileh == SLOPE_S || tileh == SLOPE_E || tileh == SLOPE_N)
-				)) { // partly up
-			return CommandCost((existing != 0) ? 0 : _price.terraform);
-		}
-	}
-	return_cmd_error(STR_1000_LAND_SLOPED_IN_WRONG_DIRECTION);
+	Foundation f_old = GetRailFoundation(tileh, existing);
+	return CommandCost(f_new != f_old ? _price.terraform : 0);
 }
 
 /* Validate functions for rail building */
--- a/src/slope.h
+++ b/src/slope.h
@@ -48,9 +48,21 @@
 	CORNER_S = 1,
 	CORNER_E = 2,
 	CORNER_N = 3,
+	CORNER_END
 };
 
 /**
+ * Rangecheck for Corner enumeration.
+ *
+ * @param corner A #Corner.
+ * @return true iff corner is in a valid range.
+ */
+static inline bool IsValidCorner(Corner corner)
+{
+	return IS_INT_INSIDE(corner, 0, CORNER_END);
+}
+
+/**
  * Checks if a slope is steep.
  *
  * @param s The given #Slope.
@@ -79,6 +91,17 @@
 }
 
 /**
+ * Tests if a slope has a highest corner (i.e. one corner raised or a steep slope).
+ *
+ * @param s The #Slope.
+ * @return  true iff the slope has a highest corner.
+ */
+static inline bool HasSlopeHighestCorner(Slope s)
+{
+	return IsSteepSlope(s) || (s == SLOPE_W) || (s == SLOPE_S) || (s == SLOPE_E) || (s == SLOPE_N);
+}
+
+/**
  * Returns the highest corner of a slope (one corner raised or a steep slope).
  *
  * @pre      The slope must be a slope with one corner raised or a steep slope.
@@ -132,7 +155,7 @@
  */
 static inline Slope SlopeWithOneCornerRaised(Corner corner)
 {
-	assert(IS_INT_INSIDE(corner, 0, 4));
+	assert(IsValidCorner(corner));
 	return (Slope)(1 << corner);
 }
 
@@ -158,6 +181,8 @@
 	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_INVALID = 0xFF    ///< Used inside "rail_cmd.cpp" to indicate invalid slope/track combination.
 };
 
 /**