diff --git a/src/landscape.cpp b/src/landscape.cpp index 544a41876b..9ff4f2b62c 100644 --- a/src/landscape.cpp +++ b/src/landscape.cpp @@ -1043,6 +1043,20 @@ static bool MakeLake(TileIndex tile, void *user_data) return false; } +bool _river_terraform = false; + +/** + * Terraform land around river. + * @param tile tile to terraform + * @param slope corners to terraform (SLOPE_xxx) + * @param dir_up direction; eg up (true) or down (false) + */ +static void RiverTerraform(TileIndex tile, Slope slope, bool dir_up) +{ + AutoRestoreBackup old_river_terraform(_river_terraform, true); + Command::Do(DC_EXEC | DC_AUTO, tile, slope, dir_up); +} + /** * Widen a river by expanding into adjacent tiles via circular tile search. * @param tile The tile to try expanding the river into. @@ -1057,9 +1071,6 @@ static bool RiverMakeWider(TileIndex tile, void *user_data) /* If the tile is already sea or river, don't expand. */ if (IsWaterTile(tile)) return false; - /* If the tile is at height 0 after terraforming but the ocean hasn't flooded yet, don't build river. */ - if (GetTileMaxZ(tile) == 0) return false; - TileIndex origin_tile = *static_cast(user_data); Slope cur_slope = GetTileSlope(tile); Slope desired_slope = GetTileSlope(origin_tile); // Initialize matching the origin tile as a shortcut if no terraforming is needed. @@ -1116,7 +1127,7 @@ static bool RiverMakeWider(TileIndex tile, void *user_data) TileIndex other_tile = TileAddByDiagDir(tile, d); if (IsInclinedSlope(GetTileSlope(other_tile)) && IsWaterTile(other_tile)) return false; } - Command::Do(DC_EXEC | DC_AUTO, tile, ComplementSlope(cur_slope), true); + RiverTerraform(tile, ComplementSlope(cur_slope), true); /* If the river is descending and the adjacent tile has either one or three corners raised, we want to make it match the slope. */ } else if (IsInclinedSlope(desired_slope)) { @@ -1137,14 +1148,14 @@ static bool RiverMakeWider(TileIndex tile, void *user_data) /* Lower unwanted corners first. If only one corner is raised, no corners need lowering. */ if (!IsSlopeWithOneCornerRaised(cur_slope)) { to_change = to_change & ComplementSlope(desired_slope); - Command::Do(DC_EXEC | DC_AUTO, tile, to_change, false); + RiverTerraform(tile, to_change, false); } /* Now check the match and raise any corners needed. */ cur_slope = GetTileSlope(tile); if (cur_slope != desired_slope && IsSlopeWithOneCornerRaised(cur_slope)) { to_change = cur_slope ^ desired_slope; - Command::Do(DC_EXEC | DC_AUTO, tile, to_change, true); + RiverTerraform(tile, to_change, true); } } /* Update cur_slope after possibly terraforming. */ @@ -1161,7 +1172,7 @@ static bool RiverMakeWider(TileIndex tile, void *user_data) /* Don't look outside the map. */ if (!IsValidTile(upstream_tile) || !IsValidTile(downstream_tile)) return false; - /* Downstream might be new ocean created by our terraforming, and it hasn't flooded yet. */ + /* Downstream might be new ocean created by our terraforming. */ bool downstream_is_ocean = GetTileZ(downstream_tile) == 0 && (GetTileSlope(downstream_tile) == SLOPE_FLAT || IsSlopeWithOneCornerRaised(GetTileSlope(downstream_tile))); /* If downstream is dry, flat, and not ocean, try making it a river tile. */ @@ -1422,9 +1433,6 @@ static void CreateRivers() } } - /* Widening rivers may have left some tiles requiring to be watered. */ - ConvertGroundTilesIntoWaterTiles(); - /* Run tile loop to update the ground density. */ for (uint i = 0; i != TILE_UPDATE_FREQUENCY; i++) { if (i % 64 == 0) IncreaseGeneratingWorldProgress(GWP_RIVER); diff --git a/src/landscape.h b/src/landscape.h index 98221c5019..c63b1ddfb8 100644 --- a/src/landscape.h +++ b/src/landscape.h @@ -137,5 +137,6 @@ void RunTileLoop(); void InitializeLandscape(); bool GenerateLandscape(uint8_t mode); +extern bool _river_terraform; #endif /* LANDSCAPE_H */ diff --git a/src/terraform_cmd.cpp b/src/terraform_cmd.cpp index cb37bf57bc..8d543ca8a9 100644 --- a/src/terraform_cmd.cpp +++ b/src/terraform_cmd.cpp @@ -19,6 +19,8 @@ #include "core/backup_type.hpp" #include "terraform_cmd.h" #include "landscape_cmd.h" +#include "water.h" +#include "landscape.h" #include "table/strings.h" @@ -297,6 +299,14 @@ std::tuple CmdTerraformLand(DoCommandFlag flags, SetTileHeight(t, (uint)height); } + if (_river_terraform) { + for (const auto &t : ts.dirty_tiles) { + /* Immediately convert ground tiles into water tiles during river generation. */ + ConvertGroundTileIntoWaterTile(t); + MarkTileDirtyByTile(t); + } + } + if (c != nullptr) c->terraform_limit -= (uint32_t)ts.tile_to_new_height.size() << 16; } return { total_cost, 0, total_cost.Succeeded() ? tile : INVALID_TILE }; diff --git a/src/water.h b/src/water.h index 323ccd5c53..7004988197 100644 --- a/src/water.h +++ b/src/water.h @@ -29,6 +29,7 @@ void ClearNeighbourNonFloodingStates(TileIndex tile); void TileLoop_Water(TileIndex tile); bool FloodHalftile(TileIndex t); +void ConvertGroundTileIntoWaterTile(TileIndex tile); void ConvertGroundTilesIntoWaterTiles(); void DrawShipDepotSprite(int x, int y, Axis axis, DepotPart part); diff --git a/src/water_cmd.cpp b/src/water_cmd.cpp index f15c15666b..978fdb5533 100644 --- a/src/water_cmd.cpp +++ b/src/water_cmd.cpp @@ -1297,38 +1297,45 @@ void TileLoop_Water(TileIndex tile) } } +void ConvertGroundTileIntoWaterTile(TileIndex tile) +{ + assert(tile < Map::Size()); + + auto [slope, z] = GetTileSlopeZ(tile); + if (IsTileType(tile, MP_CLEAR) && z == 0) { + /* Make both water for tiles at level 0 + * and make shore, as that looks much better + * during the generation. */ + switch (slope) { + case SLOPE_FLAT: + MakeSea(tile); + break; + + case SLOPE_N: + case SLOPE_E: + case SLOPE_S: + case SLOPE_W: + MakeShore(tile); + break; + + default: + for (Direction dir : SetBitIterator(_flood_from_dirs[slope & ~SLOPE_STEEP])) { + TileIndex dest = TileAddByDir(tile, dir); + Slope slope_dest = GetTileSlope(dest) & ~SLOPE_STEEP; + if (slope_dest == SLOPE_FLAT || IsSlopeWithOneCornerRaised(slope_dest) || IsTileType(dest, MP_VOID)) { + MakeShore(tile); + break; + } + } + break; + } + } +} + void ConvertGroundTilesIntoWaterTiles() { for (const auto tile : Map::Iterate()) { - auto [slope, z] = GetTileSlopeZ(tile); - if (IsTileType(tile, MP_CLEAR) && z == 0) { - /* Make both water for tiles at level 0 - * and make shore, as that looks much better - * during the generation. */ - switch (slope) { - case SLOPE_FLAT: - MakeSea(tile); - break; - - case SLOPE_N: - case SLOPE_E: - case SLOPE_S: - case SLOPE_W: - MakeShore(tile); - break; - - default: - for (Direction dir : SetBitIterator(_flood_from_dirs[slope & ~SLOPE_STEEP])) { - TileIndex dest = TileAddByDir(tile, dir); - Slope slope_dest = GetTileSlope(dest) & ~SLOPE_STEEP; - if (slope_dest == SLOPE_FLAT || IsSlopeWithOneCornerRaised(slope_dest) || IsTileType(dest, MP_VOID)) { - MakeShore(tile); - break; - } - } - break; - } - } + ConvertGroundTileIntoWaterTile(tile); } }