/**
* 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) {
if (IsValidTile(tile + m * delta_mid)) {
if (DistanceFromEdgeDir(tile + m * delta_mid, dir) == 0 || DistanceFromEdgeDir(tile + m * delta_mid, ReverseDiagDir(dir)) == 0) {
return false;
}
if (IsValidTile(tile + m * 2 * delta_mid)) {
if (!IsTileFlat(tile + m * 2 * delta_mid)) {
return false;
}
if (IsValidTile(tile + m * 3 * delta_mid)) {
if ((GetInclinedSlopeDirection(GetTileSlope(tile + m * 3 * delta_mid)) == dir ||
GetInclinedSlopeDirection(GetTileSlope(tile + m * 3 * delta_mid)) == ReverseDiagDir(dir)) &&
FlowsLock(tile + m * 3 * delta_mid)) {
return false;
}
}
}
}
for (int d = -1; d <= 1; d += 2) {
if (IsValidTile(tile + m * delta_mid + d * delta)) {
if (!IsTileFlat(tile + m * delta_mid + d * delta) &&
(GetInclinedSlopeDirection(GetTileSlope(tile + m * delta_mid + d * delta)) == dir_rot ||
GetInclinedSlopeDirection(GetTileSlope(tile + m * delta_mid + d * delta)) == ReverseDiagDir(dir_rot)) &&
FlowsLock(tile + m * delta_mid + d * delta)) {
return false;
}
if (IsValidTile(tile + m * delta_mid + d * 2 * delta)) {
if (!IsTileFlat(tile + m * delta_mid + d * 2 * delta) &&
(GetInclinedSlopeDirection(GetTileSlope(tile + m * delta_mid + d * 2 * delta)) == dir_rot ||
GetInclinedSlopeDirection(GetTileSlope(tile + m * delta_mid + d * 2 * delta)) == ReverseDiagDir(dir_rot)) &&
FlowsLock(tile + m * delta_mid + d * 2 * delta)) {
return false;
}
}
if (IsValidTile(tile + m * 2 * delta_mid + d * delta)) {
if (IsTileFlat(tile + m * delta_mid + d * delta) && !IsTileFlat(tile + m * 2 * delta_mid + d * delta)) {
return false;
}
if (!IsTileFlat(tile + m * 2 * delta_mid + d * delta) &&
(GetInclinedSlopeDirection(GetTileSlope(tile + m * 2 * delta_mid + d * delta)) == dir_rot ||
GetInclinedSlopeDirection(GetTileSlope(tile + m * 2 * delta_mid + d * delta)) == ReverseDiagDir(dir_rot)) &&
FlowsLock(tile + m * 2 * delta_mid + d * delta)) {
return false;
}
if (IsValidTile(tile + m * 3 * delta_mid + d * delta)) {
if ((GetInclinedSlopeDirection(GetTileSlope(tile + m * 3 * delta_mid + d * delta)) == dir ||
GetInclinedSlopeDirection(GetTileSlope(tile + m * 3 * delta_mid + d * delta)) == ReverseDiagDir(dir)) &&
FlowsLock(tile + m * 3 * delta_mid + d * delta)) {
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));
}