Mercurial > hg > openttd
changeset 7770:bc46fc63ab88 draft
(svn r11319) -Add: halftile- and anti-zig-zag-foundations. Patch by frosch.
author | rubidium <rubidium@openttd.org> |
---|---|
date | Sat, 20 Oct 2007 21:04:14 +0000 |
parents | ca89a62f72e1 |
children | 004a597e91a1 |
files | src/landscape.cpp src/landscape.h src/rail_cmd.cpp src/slope.h |
diffstat | 4 files changed, 273 insertions(+), 88 deletions(-) [+] |
line wrap: on
line diff
--- a/src/landscape.cpp +++ b/src/landscape.cpp @@ -76,6 +76,16 @@ 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 @@ *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 @@ } /** + * 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 @@ { 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 @@ /* 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 @@ 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);
--- a/src/landscape.h +++ b/src/landscape.h @@ -26,6 +26,7 @@ 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) {
--- a/src/rail_cmd.cpp +++ b/src/rail_cmd.cpp @@ -215,19 +215,35 @@ 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 @@ 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 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) || + 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) || - (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)); + (image = rti->base_sprites.track_ns, track == TRACK_BIT_HORZ) || + (image++, track == TRACK_BIT_VERT) || - /* DrawFoundation() modifies it. - * Default sloped sprites.. */ - if (ti->tileh != SLOPE_FLAT) image = _track_sloped_sprites[ti->tileh - 1] + rti->base_sprites.track_y; - } + (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 @@ 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 @@ 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; - } + /* 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; - /* 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; - - 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 */
--- a/src/slope.h +++ b/src/slope.h @@ -16,7 +16,8 @@ CORNER_S = 1, CORNER_E = 2, CORNER_N = 3, - CORNER_END + CORNER_END, + CORNER_INVALID = 0xFF }; /** @@ -234,8 +235,20 @@ 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 @@ } /** + * 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 @@ 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 */