/**
* Check whether a river could (logically) flow into a lock.
* @param tile the middle tile of a lock.
* @recursive whether the function is being called recursively.
* @return true iff the water can be flowing into a lock.
*/
bool FlowsLock(TileIndex tile, bool recursive = false)
{
DiagDirection dir = GetInclinedSlopeDirection(GetTileSlope(tile));
if (dir == INVALID_DIAGDIR) return false;
int delta_mid = TileOffsByDiagDir(dir);
if (!IsTileFlat(tile + delta_mid)) return false;
if (!IsTileFlat(tile - delta_mid)) return false;
if (!recursive) return true;
DiagDirection dir_rot = ChangeDiagDir(dir, DIAGDIRDIFF_90RIGHT);
int delta = TileOffsByDiagDir(dir_rot);
for (int m = -1; m <= 1; m += 2) {
TileIndex t_dm = tile + m * delta_mid;
if (IsValidTile(t_dm)) {
if (DistanceFromEdgeDir(t_dm, dir) == 0 || DistanceFromEdgeDir(t_dm, ReverseDiagDir(dir)) == 0) {
return false;
}
for (int d = -1; d <= 1; d += 2) {
if (IsValidTile(t_dm + d * delta)) {
if (!IsTileFlat(t_dm + d * delta) &&
(GetInclinedSlopeDirection(GetTileSlope(t_dm + d * delta)) == dir_rot ||
GetInclinedSlopeDirection(GetTileSlope(t_dm + d * delta)) == ReverseDiagDir(dir_rot)) &&
FlowsLock(t_dm + d * delta)) {
return false;
}
if (IsValidTile(t_dm + d * 2 * delta)) {
if (!IsTileFlat(t_dm + d * 2 * delta) &&
(GetInclinedSlopeDirection(GetTileSlope(t_dm + d * 2 * delta)) == dir_rot ||
GetInclinedSlopeDirection(GetTileSlope(t_dm + d * 2 * delta)) == ReverseDiagDir(dir_rot)) &&
FlowsLock(t_dm + d * 2 * delta)) {
return false;
}
}
}
}
TileIndex t_2dm = t_dm + m * delta_mid;
if (IsValidTile(t_2dm)) {
if (!IsTileFlat(t_2dm)) {
return false;
}
for (int d = -1; d <= 1; d += 2) {
if (IsValidTile(t_2dm + d * delta)) {
if (IsTileFlat(t_dm + d * delta) && !IsTileFlat(t_2dm + d * delta)) {
return false;
}
if (!IsTileFlat(t_2dm + d * delta) &&
(GetInclinedSlopeDirection(GetTileSlope(t_2dm + d * delta)) == dir_rot ||
GetInclinedSlopeDirection(GetTileSlope(t_2dm + d * delta)) == ReverseDiagDir(dir_rot)) &&
FlowsLock(t_2dm + d * delta)) {
return false;
}
}
}
TileIndex t_3dm = t_2dm + m * delta_mid;
if (IsValidTile(t_3dm)) {
if ((GetInclinedSlopeDirection(GetTileSlope(t_3dm)) == dir ||
GetInclinedSlopeDirection(GetTileSlope(t_3dm)) == ReverseDiagDir(dir)) &&
FlowsLock(t_3dm)) {
return false;
}
}
}
}
}
return true;
}
/**
* 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. */
(slopeEnd == SLOPE_FLAT || (IsInclinedSlope(slopeEnd) && FlowsLock(end, true))) &&
/* Slope continues, then it must be lower... or either end must be flat. */
((slopeEnd == slopeBegin && heightEnd < heightBegin) || slopeEnd == SLOPE_FLAT || (slopeBegin == SLOPE_FLAT && GetTileMaxZ(end) == heightBegin));
}