Changeset - r26748:90d55b3e0b5c
[Not reviewed]
master
0 1 0
Tyler Trahan - 17 months ago 2023-01-14 13:20:19
tyler@tylertrahan.com
Fix: Various Wide River issues (#10348)
1 file changed with 16 insertions and 3 deletions:
0 comments (0 inline, 0 general)
src/landscape.cpp
Show inline comments
 
@@ -1072,87 +1072,87 @@ static bool MakeLake(TileIndex tile, voi
 
			return false;
 
		}
 
	}
 

	
 
	return false;
 
}
 

	
 
/**
 
 * Widen a river by expanding into adjacent tiles via circular tile search.
 
 * @param tile The tile to try expanding the river into.
 
 * @param data The tile to try surrounding the river around.
 
 * @return Always false, so it continues searching.
 
 */
 
static bool RiverMakeWider(TileIndex tile, void *data)
 
{
 
	/* Don't expand into void tiles. */
 
	if (!IsValidTile(tile)) return false;
 

	
 
	/* 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 = *(TileIndex *)data;;
 
	TileIndex origin_tile = *(TileIndex *)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.
 

	
 
	/* Never flow uphill. */
 
	if (GetTileMaxZ(tile) > GetTileMaxZ(origin_tile)) return false;
 

	
 
	/* If the new tile can't hold a river tile, try terraforming. */
 
	if (!IsTileFlat(tile) && !IsInclinedSlope(cur_slope)) {
 
		/* Don't try to terraform steep slopes. */
 
		if (IsSteepSlope(cur_slope)) return false;
 

	
 
		bool flat_river_found = false;
 
		bool sloped_river_found = false;
 

	
 
		/* There are two common possibilities:
 
		 * 1. River flat, adjacent tile has one corner lowered.
 
		 * 2. River descending, adjacent tile has either one or three corners raised.
 
		 */
 

	
 
		/* First, determine the desired slope based on adjacent river tiles. This doesn't necessarily match the origin tile for the CircularTileSearch. */
 
		for (DiagDirection d = DIAGDIR_BEGIN; d < DIAGDIR_END; d++) {
 
			TileIndex other_tile = TileAddByDiagDir(tile, d);
 
			Slope other_slope = GetTileSlope(other_tile);
 

	
 
			/* Only consider river tiles. */
 
			if (IsWaterTile(other_tile) && IsRiver(other_tile)) {
 
				/* If the adjacent river tile flows downhill, we need to check where we are relative to the slope. */
 
				if (IsInclinedSlope(other_slope) && GetTileMaxZ(tile) == GetTileMaxZ(other_tile)) {
 
					/* Check for a parallel slope. If we don't find one, we're above or below the slope instead. */
 
					if (GetInclinedSlopeDirection(other_slope) == ChangeDiagDir(d, DIAGDIRDIFF_90RIGHT) ||
 
							GetInclinedSlopeDirection(other_slope) == ChangeDiagDir(d, DIAGDIRDIFF_90LEFT)) {
 
						desired_slope = other_slope;
 
						sloped_river_found = true;
 
						break;
 
					}
 
				}
 
				/* If we find an adjacent river tile, remember it. We'll terraform to match it later if we don't find a slope. */
 
				if (IsTileFlat(tile)) flat_river_found = true;
 
				if (IsTileFlat(other_tile)) flat_river_found = true;
 
			}
 
		}
 
		/* We didn't find either an inclined or flat river, so we're climbing the wrong slope. Bail out. */
 
		if (!sloped_river_found && !flat_river_found) return false;
 

	
 
		/* We didn't find an inclined river, but there is a flat river. */
 
		if (!sloped_river_found && flat_river_found) desired_slope = SLOPE_FLAT;
 

	
 
		/* Now that we know the desired slope, it's time to terraform! */
 

	
 
		/* If the river is flat and the adjacent tile has one corner lowered, we want to raise it. */
 
		if (desired_slope == SLOPE_FLAT && IsSlopeWithThreeCornersRaised(cur_slope)) {
 
			/* Make sure we're not affecting an existing river slope tile. */
 
			for (DiagDirection d = DIAGDIR_BEGIN; d < DIAGDIR_END; d++) {
 
				TileIndex other_tile = TileAddByDiagDir(tile, d);
 
				if (IsInclinedSlope(GetTileSlope(other_tile)) && IsWaterTile(other_tile)) return false;
 
			}
 
			Command<CMD_TERRAFORM_LAND>::Do(DC_EXEC | DC_AUTO, 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)) {
 
			/* Don't break existing flat river tiles by terraforming under them. */
 
			DiagDirection river_direction = ReverseDiagDir(GetInclinedSlopeDirection(desired_slope));
 

	
 
@@ -1182,66 +1182,76 @@ static bool RiverMakeWider(TileIndex til
 
		}
 
		/* Update cur_slope after possibly terraforming. */
 
		cur_slope = GetTileSlope(tile);
 
	}
 

	
 
	/* Sloped rivers need water both upstream and downstream. */
 
	if (IsInclinedSlope(cur_slope)) {
 
		DiagDirection slope_direction = GetInclinedSlopeDirection(cur_slope);
 

	
 
		TileIndex upstream_tile = TileAddByDiagDir(tile, slope_direction);
 
		TileIndex downstream_tile = TileAddByDiagDir(tile, ReverseDiagDir(slope_direction));
 

	
 
		/* 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. */
 
		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. */
 
		if (!IsWaterTile(downstream_tile) && !downstream_is_ocean) {
 
			/* If the tile upstream isn't flat, don't bother. */
 
			if (GetTileSlope(downstream_tile) != SLOPE_FLAT) return false;
 

	
 
			MakeRiver(downstream_tile, Random());
 
			MarkTileDirtyByTile(downstream_tile);
 

	
 
			/* Remove desert directly around the river tile. */
 
			TileIndex cur_tile = downstream_tile;
 
			CircularTileSearch(&cur_tile, RIVER_OFFSET_DESERT_DISTANCE, RiverModifyDesertZone, nullptr);
 
		}
 

	
 
		/* If upstream is dry and flat, try making it a river tile. */
 
		if (!IsWaterTile(upstream_tile)) {
 
			/* If the tile upstream isn't flat, don't bother. */
 
			if (GetTileSlope(upstream_tile) != SLOPE_FLAT) return false;
 

	
 
			MakeRiver(upstream_tile, Random());
 
			MarkTileDirtyByTile(upstream_tile);
 

	
 
			/* Remove desert directly around the river tile. */
 
			TileIndex cur_tile = upstream_tile;
 
			CircularTileSearch(&cur_tile, RIVER_OFFSET_DESERT_DISTANCE, RiverModifyDesertZone, nullptr);
 
		}
 
	}
 

	
 
	/* If the tile slope matches the desired slope, add a river tile. */
 
	if (cur_slope == desired_slope) {
 
		MakeRiver(tile, Random());
 
		MarkTileDirtyByTile(tile);
 

	
 
		/* Remove desert directly around the river tile. */
 
		TileIndex cur_tile = tile;
 
		MarkTileDirtyByTile(cur_tile);
 
		CircularTileSearch(&cur_tile, RIVER_OFFSET_DESERT_DISTANCE, RiverModifyDesertZone, nullptr);
 
	}
 

	
 
	/* Always return false to keep searching. */
 
	return false;
 
}
 

	
 
/**
 
 * Check whether a river at begin could (logically) flow down to end.
 
 * @param begin The origin of the flow.
 
 * @param end The destination of the flow.
 
 * @return True iff the water can be flowing down.
 
 */
 
static bool FlowsDown(TileIndex begin, TileIndex end)
 
{
 
	assert(DistanceManhattan(begin, end) == 1);
 

	
 
	int heightBegin;
 
	int heightEnd;
 
	Slope slopeBegin = GetTileSlope(begin, &heightBegin);
 
	Slope slopeEnd   = GetTileSlope(end, &heightEnd);
 

	
 
	return heightEnd <= heightBegin &&
 
			/* Slope either is inclined or flat; rivers don't support other slopes. */
 
@@ -1473,48 +1483,51 @@ static void CreateRivers()
 
	uint wells = ScaleByMapSize(4 << _settings_game.game_creation.amount_of_rivers);
 
	const uint num_short_rivers = wells - std::max(1u, wells / 10);
 
	SetGeneratingWorldProgress(GWP_RIVER, wells + 256 / 64); // Include the tile loop calls below.
 

	
 
	/* Try to create long rivers. */
 
	for (; wells > num_short_rivers; wells--) {
 
		IncreaseGeneratingWorldProgress(GWP_RIVER);
 
		for (int tries = 0; tries < 512; tries++) {
 
			TileIndex t = RandomTile();
 
			if (!CircularTileSearch(&t, 8, FindSpring, nullptr)) continue;
 
			if (std::get<0>(FlowRiver(t, t, _settings_game.game_creation.min_river_length * 4))) break;
 
		}
 
	}
 

	
 
	/* Try to create short rivers. */
 
	for (; wells != 0; wells--) {
 
		IncreaseGeneratingWorldProgress(GWP_RIVER);
 
		for (int tries = 0; tries < 128; tries++) {
 
			TileIndex t = RandomTile();
 
			if (!CircularTileSearch(&t, 8, FindSpring, nullptr)) continue;
 
			if (std::get<0>(FlowRiver(t, t, _settings_game.game_creation.min_river_length))) break;
 
		}
 
	}
 

	
 
	/* 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 != 256; i++) {
 
		if (i % 64 == 0) IncreaseGeneratingWorldProgress(GWP_RIVER);
 
		RunTileLoop();
 
	}
 
}
 

	
 
/**
 
 * Calculate what height would be needed to cover N% of the landmass.
 
 *
 
 * The function allows both snow and desert/tropic line to be calculated. It
 
 * tries to find the closests height which covers N% of the landmass; it can
 
 * be below or above it.
 
 *
 
 * Tropic has a mechanism where water and tropic tiles in mountains grow
 
 * inside the desert. To better approximate the requested coverage, this is
 
 * taken into account via an edge histogram, which tells how many neighbouring
 
 * tiles are lower than the tiles of that height. The multiplier indicates how
 
 * severe this has to be taken into account.
 
 *
 
 * @param coverage A value between 0 and 100 indicating a percentage of landmass that should be covered.
 
 * @param edge_multiplier How much effect neighbouring tiles that are of a lower height level have on the score.
 
 * @return The estimated best height to use to cover N% of the landmass.
 
 */
0 comments (0 inline, 0 general)