From 6cebf4aa53a4eafb79b8ea9969aafda44d4fb0cd Mon Sep 17 00:00:00 2001 From: rubidium Date: Tue, 9 Oct 2007 21:11:23 +0000 Subject: (svn r11237) -Codechange: reduce code duplication between GetRailFoundation() and CheckRailSlope(). Patch by frosch. --- src/rail.cpp | 4 ++ src/rail.h | 13 +++++++ src/rail_cmd.cpp | 116 ++++++++++++++++++++++++++++++++----------------------- src/slope.h | 27 ++++++++++++- 4 files changed, 110 insertions(+), 50 deletions(-) (limited to 'src') diff --git a/src/rail.cpp b/src/rail.cpp index e1fa6792a..b172ea499 100644 --- a/src/rail.cpp +++ b/src/rail.cpp @@ -103,6 +103,10 @@ extern const Trackdir _dir_to_diag_trackdir[] = { 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) { diff --git a/src/rail.h b/src/rail.h index 94ab46853..c0912d807 100644 --- a/src/rail.h +++ b/src/rail.h @@ -120,6 +120,19 @@ static inline TrackBits AxisToTrackBits(Axis a) 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. diff --git a/src/rail_cmd.cpp b/src/rail_cmd.cpp index a2f07fd5a..92753c05c 100644 --- a/src/rail_cmd.cpp +++ b/src/rail_cmd.cpp @@ -150,10 +150,8 @@ static bool CheckTrackCombination(TileIndex tile, TrackBits to_build, uint flags } -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 @@ static const TrackBits _valid_tileh_slopes[][15] = { 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 @@ static const TrackBits _valid_tileh_slopes[][15] = { 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; - 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); + 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; + + /* 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); + } - /* 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); - } + Foundation f_new = GetRailFoundation(tileh, rail_bits | existing); - /* 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); - } + /* 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); - 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 */ diff --git a/src/slope.h b/src/slope.h index db8b17a12..cc359d8c8 100644 --- a/src/slope.h +++ b/src/slope.h @@ -48,8 +48,20 @@ enum Corner { 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. * @@ -78,6 +90,17 @@ static inline Slope ComplementSlope(Slope s) return (Slope)(0xF ^ s); } +/** + * 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). * @@ -132,7 +155,7 @@ static inline Corner OppositeCorner(Corner corner) */ static inline Slope SlopeWithOneCornerRaised(Corner corner) { - assert(IS_INT_INSIDE(corner, 0, 4)); + assert(IsValidCorner(corner)); return (Slope)(1 << corner); } @@ -158,6 +181,8 @@ enum 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_INVALID = 0xFF ///< Used inside "rail_cmd.cpp" to indicate invalid slope/track combination. }; /** -- cgit v1.2.3-54-g00ecf