diff --git a/builtin/mainmenu/dlg_create_world.lua b/builtin/mainmenu/dlg_create_world.lua
index 6d433bde4952958c01100e791cf237e419dc88d6..9fcd9104b26c461f3338f987bd893f3712dd3242 100644
--- a/builtin/mainmenu/dlg_create_world.lua
+++ b/builtin/mainmenu/dlg_create_world.lua
@@ -16,7 +16,7 @@
 --51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
 
 local function create_world_formspec(dialogdata)
-	local mapgens = {"v6", "v7", "singlenode"}
+	local mapgens = {"v5", "v6", "v7", "singlenode"}
 
 	local current_seed = core.setting_get("fixed_map_seed") or ""
 	local current_mg   = core.setting_get("mg_name")
diff --git a/minetest.conf.example b/minetest.conf.example
index c593e0ec10ed42444a30419a6a48fdc8d8c83aaa..992b7ded96cbf39c0e12743d2bb79087935935d9 100644
--- a/minetest.conf.example
+++ b/minetest.conf.example
@@ -407,7 +407,7 @@
 # Mapgen stuff
 #
 
-# Name of map generator to be used.  Currently supported: v6, v7, singlenode
+# Name of map generator to be used.  Currently supported: v5, v6, v7, singlenode
 #mg_name = v6
 # Water level of map.
 #water_level = 1
@@ -424,6 +424,16 @@
 #mgv6_freq_beach = 0.15
 # Perlin noise attributes for different map generation parameters
 # Offset, scale, spread factor, seed offset, number of octaves, persistence
+
+#mgv5_np_filler_depth = 0, 1, (150, 150, 150), 261, 4, 0.7
+#mgv5_np_factor = 0, 1, (250, 250, 250), 920381, 3, 0.45
+#mgv5_np_height = 0, 10, (250, 250, 250), 84174, 4, 0.5
+#mgv5_np_cave1 = 0, 7.5, (50, 50, 50), 52534, 4, 0.5
+#mgv5_np_cave2 = 0, 7.5, (50, 50, 50), 10325, 4, 0.5
+#mgv5_np_ground = 0, 40, (80, 80, 80), 983240, 4, 0.55
+#mgv5_np_crumble = 0, 1, (20, 20, 20), 34413, 3, 1.3
+#mgv5_np_wetness = 0, 1, (40, 40, 40), 32474, 4, 1.1
+
 #mgv6_np_terrain_base = -4, 20, (250, 250, 250), 82341, 5, 0.6
 #mgv6_np_terrain_higher = 20, 16, (500, 500, 500), 85039, 5, 0.6
 #mgv6_np_steepness = 0.85, 0.5, (125, 125, 125), -932, 5, 0.7
diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt
index 5de5834d38f518a0d7820dd2780a34bd0de0372f..eeceb6358feba219e19abf44a53dc079cfbbcb48 100644
--- a/src/CMakeLists.txt
+++ b/src/CMakeLists.txt
@@ -368,6 +368,7 @@ set(common_SRCS
 	mapblock.cpp
 	mapgen.cpp
 	mapgen_singlenode.cpp
+	mapgen_v5.cpp
 	mapgen_v6.cpp
 	mapgen_v7.cpp
 	mapnode.cpp
diff --git a/src/emerge.cpp b/src/emerge.cpp
index 9cbcd25741d814da7ba74e7f87005a6a4d057667..7427f6f4ba6a230f1855c65e9a7086571712dfdc 100644
--- a/src/emerge.cpp
+++ b/src/emerge.cpp
@@ -42,6 +42,7 @@ with this program; if not, write to the Free Software Foundation, Inc.,
 #include "mg_biome.h"
 #include "mg_decoration.h"
 #include "mg_ore.h"
+#include "mapgen_v5.h"
 #include "mapgen_v6.h"
 #include "mapgen_v7.h"
 #include "mapgen_singlenode.h"
@@ -82,6 +83,7 @@ class EmergeThread : public JThread
 
 EmergeManager::EmergeManager(IGameDef *gamedef) {
 	//register built-in mapgens
+	registerMapgen("v5",         new MapgenFactoryV5());
 	registerMapgen("v6",         new MapgenFactoryV6());
 	registerMapgen("v7",         new MapgenFactoryV7());
 	registerMapgen("singlenode", new MapgenFactorySinglenode());
diff --git a/src/mapgen_v5.cpp b/src/mapgen_v5.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..152537eed394cf6d713d6cf5e2372849d0f18419
--- /dev/null
+++ b/src/mapgen_v5.cpp
@@ -0,0 +1,496 @@
+/*
+Minetest
+Copyright (C) 2010-2013 kwolekr, Ryan Kwolek <kwolekr@minetest.net>
+
+This program is free software; you can redistribute it and/or modify
+it under the terms of the GNU Lesser General Public License as published by
+the Free Software Foundation; either version 2.1 of the License, or
+(at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+GNU Lesser General Public License for more details.
+
+You should have received a copy of the GNU Lesser General Public License along
+with this program; if not, write to the Free Software Foundation, Inc.,
+51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+*/
+
+
+#include "mapgen.h"
+#include "voxel.h"
+#include "noise.h"
+#include "mapblock.h"
+#include "mapnode.h"
+#include "map.h"
+#include "content_sao.h"
+#include "nodedef.h"
+#include "voxelalgorithms.h"
+#include "profiler.h"
+#include "settings.h" // For g_settings
+#include "main.h" // For g_profiler
+#include "emerge.h"
+#include "dungeongen.h"
+#include "cavegen.h"
+#include "treegen.h"
+#include "mg_biome.h"
+#include "mg_ore.h"
+#include "mg_decoration.h"
+#include "mapgen_v5.h"
+#include "util/directiontables.h"
+
+
+FlagDesc flagdesc_mapgen_v5[] = {
+	//{"blobs", MGV5_BLOBS},
+	{NULL,         0}
+};
+
+
+MapgenV5::MapgenV5(int mapgenid, MapgenParams *params, EmergeManager *emerge_) {
+	this->generating  = false;
+	this->id     = mapgenid;
+	this->emerge = emerge_;
+	this->bmgr   = emerge->biomedef;
+
+	this->seed        = (int)params->seed;
+	this->water_level = params->water_level;
+	this->flags       = params->flags;
+	this->gennotify   = emerge->gennotify;
+
+	this->csize   = v3s16(1, 1, 1) * params->chunksize * MAP_BLOCKSIZE;
+
+	// amount of elements to skip for the next index
+	// for noise/height/biome maps (not vmanip)
+	this->ystride = csize.X;
+	this->zstride = csize.X * csize.Y;
+
+	this->biomemap  = new u8[csize.X * csize.Z];
+	this->heightmap = new s16[csize.X * csize.Z];
+
+	MapgenV5Params *sp = (MapgenV5Params *)params->sparams;
+
+	// Terrain noise
+	noise_filler_depth = new Noise(&sp->np_filler_depth, seed, csize.X, csize.Z);
+	noise_factor       = new Noise(&sp->np_factor,       seed, csize.X, csize.Z);
+	noise_height       = new Noise(&sp->np_height,       seed, csize.X, csize.Z);
+
+	// 3D terrain noise
+	noise_cave1        = new Noise(&sp->np_cave1,   seed, csize.X, csize.Y, csize.Z);
+	noise_cave2        = new Noise(&sp->np_cave2,   seed, csize.X, csize.Y, csize.Z);
+	noise_ground       = new Noise(&sp->np_ground,  seed, csize.X, csize.Y, csize.Z);
+	noise_crumble      = new Noise(&sp->np_crumble, seed, csize.X, csize.Y, csize.Z);
+	noise_wetness      = new Noise(&sp->np_wetness, seed, csize.X, csize.Y, csize.Z);
+
+	// Biome noise
+	noise_heat         = new Noise(bmgr->np_heat,     seed, csize.X, csize.Z);
+	noise_humidity     = new Noise(bmgr->np_humidity, seed, csize.X, csize.Z);
+
+	//// Resolve nodes to be used
+	INodeDefManager *ndef = emerge->ndef;
+
+	c_stone           = ndef->getId("mapgen_stone");
+	c_dirt            = ndef->getId("mapgen_dirt");
+	c_dirt_with_grass = ndef->getId("mapgen_dirt_with_grass");
+	c_sand            = ndef->getId("mapgen_sand");
+	c_water_source    = ndef->getId("mapgen_water_source");
+	c_lava_source     = ndef->getId("mapgen_lava_source");
+	c_gravel          = ndef->getId("mapgen_gravel");
+	c_cobble          = ndef->getId("mapgen_cobble");
+	c_ice             = ndef->getId("default:ice");
+	c_mossycobble     = ndef->getId("mapgen_mossycobble");
+	c_sandbrick       = ndef->getId("mapgen_sandstonebrick");
+	c_stair_cobble    = ndef->getId("mapgen_stair_cobble");
+	c_stair_sandstone = ndef->getId("mapgen_stair_sandstone");
+	if (c_ice == CONTENT_IGNORE)
+		c_ice = CONTENT_AIR;
+	if (c_mossycobble == CONTENT_IGNORE)
+		c_mossycobble = c_cobble;
+	if (c_sandbrick == CONTENT_IGNORE)
+		c_sandbrick = c_desert_stone;
+	if (c_stair_cobble == CONTENT_IGNORE)
+		c_stair_cobble = c_cobble;
+	if (c_stair_sandstone == CONTENT_IGNORE)
+		c_stair_sandstone = c_sandbrick;
+}
+
+
+MapgenV5::~MapgenV5() {
+	delete noise_filler_depth;
+	delete noise_factor;
+	delete noise_height;
+	delete noise_cave1;
+	delete noise_cave2;
+	delete noise_ground;
+	delete noise_crumble;
+	delete noise_wetness;
+
+	delete noise_heat;
+	delete noise_humidity;
+	
+	delete[] heightmap;
+	delete[] biomemap;
+}
+
+
+MapgenV5Params::MapgenV5Params() {
+	//spflags = MGV5_BLOBS;
+	spflags = 0;
+
+	np_filler_depth = NoiseParams(0, 1,   v3f(150, 150, 150), 261,    4, 0.7);
+	np_factor       = NoiseParams(0, 1,   v3f(250, 250, 250), 920381, 3, 0.45);
+	np_height       = NoiseParams(0, 10,  v3f(250, 250, 250), 84174,  4, 0.5);
+	np_cave1        = NoiseParams(0, 7.5, v3f(50,  50,  50),  52534,  4, 0.5);
+	np_cave2        = NoiseParams(0, 7.5, v3f(50,  50,  50),  10325,  4, 0.5);
+	np_ground       = NoiseParams(0, 40,  v3f(80,  80,  80),  983240, 4, 0.55);
+	np_crumble      = NoiseParams(0, 1,   v3f(20,  20,  20),  34413,  3, 1.3);
+	np_wetness      = NoiseParams(0, 1,   v3f(40,  40,  40),  32474,  4, 1.1);
+}
+
+
+// Scaling the output of the noise function affects the overdrive of the
+// contour function, which affects the shape of the output considerably.
+
+//#define CAVE_NOISE_SCALE 12.0 < original default
+//#define CAVE_NOISE_SCALE 10.0
+//#define CAVE_NOISE_SCALE 7.5 < current default to compensate for new eased 3d noise
+//#define CAVE_NOISE_SCALE 5.0
+//#define CAVE_NOISE_SCALE 1.0
+
+//#define CAVE_NOISE_THRESHOLD (2.5/CAVE_NOISE_SCALE)
+//#define CAVE_NOISE_THRESHOLD (1.5/CAVE_NOISE_SCALE) < original and current default
+
+
+void MapgenV5Params::readParams(Settings *settings) {
+	settings->getFlagStrNoEx("mgv5_spflags", spflags, flagdesc_mapgen_v5);
+
+	settings->getNoiseParams("mgv5_np_filler_depth", np_filler_depth);
+	settings->getNoiseParams("mgv5_np_factor",       np_factor);
+	settings->getNoiseParams("mgv5_np_height",       np_height);
+	settings->getNoiseParams("mgv5_np_cave1",        np_cave1);
+	settings->getNoiseParams("mgv5_np_cave2",        np_cave2);
+	settings->getNoiseParams("mgv5_np_ground",       np_ground);
+	settings->getNoiseParams("mgv5_np_crumble",      np_crumble);
+	settings->getNoiseParams("mgv5_np_wetness",      np_wetness);
+}
+
+
+void MapgenV5Params::writeParams(Settings *settings) {
+	settings->setFlagStr("mgv5_spflags", spflags, flagdesc_mapgen_v5, (u32)-1);
+
+	settings->setNoiseParams("mgv5_np_filler_depth", np_filler_depth);
+	settings->setNoiseParams("mgv5_np_factor",       np_factor);
+	settings->setNoiseParams("mgv5_np_height",       np_height);
+	settings->setNoiseParams("mgv5_np_cave1",        np_cave1);
+	settings->setNoiseParams("mgv5_np_cave2",        np_cave2);
+	settings->setNoiseParams("mgv5_np_ground",       np_ground);
+	settings->setNoiseParams("mgv5_np_crumble",      np_crumble);
+	settings->setNoiseParams("mgv5_np_wetness",      np_wetness);
+}
+
+
+void MapgenV5::makeChunk(BlockMakeData *data) {
+	assert(data->vmanip);
+	assert(data->nodedef);
+	assert(data->blockpos_requested.X >= data->blockpos_min.X &&
+		   data->blockpos_requested.Y >= data->blockpos_min.Y &&
+		   data->blockpos_requested.Z >= data->blockpos_min.Z);
+	assert(data->blockpos_requested.X <= data->blockpos_max.X &&
+		   data->blockpos_requested.Y <= data->blockpos_max.Y &&
+		   data->blockpos_requested.Z <= data->blockpos_max.Z);
+			
+	generating = true;
+	vm   = data->vmanip;	
+	ndef = data->nodedef;
+	//TimeTaker t("makeChunk");
+	
+	v3s16 blockpos_min = data->blockpos_min;
+	v3s16 blockpos_max = data->blockpos_max;
+	node_min = blockpos_min * MAP_BLOCKSIZE;
+	node_max = (blockpos_max + v3s16(1, 1, 1)) * MAP_BLOCKSIZE - v3s16(1, 1, 1);
+	full_node_min = (blockpos_min - 1) * MAP_BLOCKSIZE;
+	full_node_max = (blockpos_max + 2) * MAP_BLOCKSIZE - v3s16(1, 1, 1);
+
+	// Create a block-specific seed
+	blockseed = emerge->getBlockSeed(full_node_min);  //////use getBlockSeed2()!
+	
+	// Make some noise
+	calculateNoise();
+
+	// Generate base terrain
+	generateBaseTerrain();
+	updateHeightmap(node_min, node_max);
+
+	// Generate underground dirt, sand, gravel and lava blobs
+	//if (spflags & MGV5_BLOBS) {
+		generateBlobs();
+	//}
+
+	// Calculate biomes
+	BiomeNoiseInput binput;
+	binput.mapsize      = v2s16(csize.X, csize.Z);
+	binput.heat_map     = noise_heat->result;
+	binput.humidity_map = noise_humidity->result;
+	binput.height_map   = heightmap;
+	bmgr->calcBiomes(&binput, biomemap);
+	
+	// Actually place the biome-specific nodes
+	generateBiomes();
+
+	// Generate dungeons and desert temples
+	if (flags & MG_DUNGEONS) {
+		DungeonGen dgen(this, NULL);
+		dgen.generate(blockseed, full_node_min, full_node_max);
+	}
+
+	// Generate the registered decorations
+	for (size_t i = 0; i != emerge->decorations.size(); i++) {
+		Decoration *deco = emerge->decorations[i];
+		deco->placeDeco(this, blockseed + i, node_min, node_max);
+	}
+
+	// Generate the registered ores
+	for (unsigned int i = 0; i != emerge->ores.size(); i++) {
+		Ore *ore = emerge->ores[i];
+		ore->placeOre(this, blockseed + i, node_min, node_max);
+	}
+
+	// Sprinkle some dust on top after everything else was generated
+	dustTopNodes();
+
+	//printf("makeChunk: %dms\n", t.stop());
+
+	// Add top and bottom side of water to transforming_liquid queue
+	updateLiquid(&data->transforming_liquid, full_node_min, full_node_max);
+	
+	// Calculate lighting
+	if (flags & MG_LIGHT)
+		calcLighting(node_min - v3s16(1, 0, 1) * MAP_BLOCKSIZE,
+					 node_max + v3s16(1, 0, 1) * MAP_BLOCKSIZE);
+	
+	this->generating = false;
+}
+
+
+void MapgenV5::calculateNoise() {
+	//TimeTaker t("calculateNoise", NULL, PRECISION_MICRO);
+	int x = node_min.X;
+	int y = node_min.Y;
+	int z = node_min.Z;
+	
+	noise_filler_depth->perlinMap2D(x, z);
+	noise_factor->perlinMap2D(x, z);
+	noise_height->perlinMap2D(x, z);
+	noise_height->transformNoiseMap();
+
+	noise_cave1->perlinMap3D(x, y, z, true);
+	noise_cave1->transformNoiseMap();
+	noise_cave2->perlinMap3D(x, y, z, true);
+	noise_cave2->transformNoiseMap();
+	noise_ground->perlinMap3D(x, y, z, true);
+	noise_ground->transformNoiseMap();
+
+	//if (spflags & MGV5_BLOBS) {
+		noise_crumble->perlinMap3D(x, y, z, true);
+		noise_wetness->perlinMap3D(x, y, z, false);
+	//}
+
+	noise_heat->perlinMap2D(x, z);
+	noise_humidity->perlinMap2D(x, z);
+
+	//printf("calculateNoise: %dus\n", t.stop());
+}
+
+
+//bool is_cave(u32 index) {
+//	double d1 = contour(noise_cave1->result[index]);
+//	double d2 = contour(noise_cave2->result[index]);
+//	return d1*d2 > CAVE_NOISE_THRESHOLD;
+//}
+
+
+//bool val_is_ground(v3s16 p, u32 index, u32 index2d) {
+//	double f = 0.55 + noise_factor->result[index2d];
+//	if(f < 0.01)
+//		f = 0.01;
+//	else if(f >= 1.0)
+//		f *= 1.6;
+//	double h = WATER_LEVEL + 10 * noise_height->result[index2d];
+//	return (noise_ground->result[index] * f > (double)p.Y - h);
+//}
+
+
+// Make base ground level
+void MapgenV5::generateBaseTerrain() {
+	u32 index = 0;
+	u32 index2d = 0;
+
+	for(s16 z=node_min.Z; z<=node_max.Z; z++) {
+		for(s16 y=node_min.Y; y<=node_max.Y; y++) {
+			u32 i = vm->m_area.index(node_min.X, y, z);
+			for(s16 x=node_min.X; x<=node_max.X; x++, i++, index++, index2d++) {
+				if(vm->m_data[i].getContent() != CONTENT_IGNORE)
+					continue;
+
+				float f = 0.55 + noise_factor->result[index2d];
+				if(f < 0.01)
+					f = 0.01;
+				else if(f >= 1.0)
+					f *= 1.6;
+				float h = water_level + noise_height->result[index2d];
+				float d1 = contour(noise_cave1->result[index]);
+				float d2 = contour(noise_cave2->result[index]);
+				if(noise_ground->result[index] * f < y - h) {
+					if(y <= water_level)
+						vm->m_data[i] = MapNode(c_water_source);
+					else
+						vm->m_data[i] = MapNode(CONTENT_AIR);
+				} else if(d1*d2 > 0.2) {
+					vm->m_data[i] = MapNode(CONTENT_AIR);
+				} else {
+					vm->m_data[i] = MapNode(c_stone);
+				}
+			}
+			index2d = index2d - ystride;
+		}
+		index2d = index2d + ystride;
+	}
+}
+
+
+// Add mud and sand and others underground (in place of stone)
+void MapgenV5::generateBlobs() {
+	u32 index = 0;
+
+	for(s16 z=node_min.Z; z<=node_max.Z; z++) {
+		for(s16 y=node_min.Y; y<=node_max.Y; y++) {
+			u32 i = vm->m_area.index(node_min.X, y, z);
+			for(s16 x=node_min.X; x<=node_max.X; x++, i++, index++) {
+				content_t c = vm->m_data[i].getContent();
+				if(c != c_stone)
+					continue;
+
+				if(noise_crumble->result[index] > 1.3) {
+					if(noise_wetness->result[index] > 0.0)
+						vm->m_data[i] = MapNode(c_dirt);
+					else
+						vm->m_data[i] = MapNode(c_sand);
+				} else if(noise_crumble->result[index] > 0.7) {
+					if(noise_wetness->result[index] < -0.6)
+						vm->m_data[i] = MapNode(c_gravel);
+				} else if(noise_crumble->result[index] < -3.5 +
+						MYMIN(0.1 *
+						sqrt((float)MYMAX(0, -y)), 1.5)) {
+					vm->m_data[i] = MapNode(c_lava_source);
+				}
+			}
+		}
+	}
+}
+
+
+void MapgenV5::generateBiomes() {
+	if (node_max.Y < water_level)
+		return;
+
+	MapNode n_air(CONTENT_AIR);
+	MapNode n_stone(c_stone);
+	MapNode n_water(c_water_source);
+
+	v3s16 em = vm->m_area.getExtent();
+	u32 index = 0;
+	
+	for (s16 z = node_min.Z; z <= node_max.Z; z++)
+	for (s16 x = node_min.X; x <= node_max.X; x++, index++) {
+		Biome *biome  = bmgr->biomes[biomemap[index]];
+		s16 dfiller   = biome->depth_filler + noise_filler_depth->result[index];
+		s16 y0_top    = biome->depth_top;
+		s16 y0_filler = biome->depth_filler + biome->depth_top + dfiller;
+		
+		s16 nplaced = 0;
+		u32 i = vm->m_area.index(x, node_max.Y, z);	
+
+		content_t c_above = vm->m_data[i + em.X].getContent();
+		bool have_air = c_above == CONTENT_AIR;
+		
+		for (s16 y = node_max.Y; y >= node_min.Y; y--) {
+			content_t c = vm->m_data[i].getContent();
+			if ((c == c_stone || c == c_dirt_with_grass
+					|| c == c_dirt
+					|| c == c_sand
+					|| c == c_lava_source
+					|| c == c_gravel) && have_air) {
+				content_t c_below = vm->m_data[i - em.X].getContent();
+				
+				if (c_below != CONTENT_AIR) {
+					if (nplaced < y0_top) {
+						// A hack to prevent dirt_with_grass from being
+						// placed below water.  TODO: fix later
+						content_t c_place = ((y < water_level) &&
+								(biome->c_top ==
+								c_dirt_with_grass)) ?
+								 c_dirt : biome->c_top;
+						
+						vm->m_data[i] = MapNode(c_place);
+						nplaced++;
+					} else if (nplaced < y0_filler && nplaced >= y0_top) {
+						vm->m_data[i] = MapNode(biome->c_filler);
+						nplaced++;
+					} else {
+						have_air = false;
+						nplaced  = 0;
+					}
+				}
+			} else if (c == c_water_source) {
+				have_air = true;
+				nplaced = 0;
+				vm->m_data[i] = MapNode(biome->c_water);
+			} else if (c == CONTENT_AIR) {
+				have_air = true;
+				nplaced = 0;
+			}
+			
+			vm->m_area.add_y(em, i, -1);
+		}
+	}
+}
+
+void MapgenV5::dustTopNodes() {
+	v3s16 em = vm->m_area.getExtent();
+	u32 index = 0;
+	
+	if (water_level > node_max.Y)
+		return;
+
+	for (s16 z = node_min.Z; z <= node_max.Z; z++)
+	for (s16 x = node_min.X; x <= node_max.X; x++, index++) {
+		Biome *biome = bmgr->biomes[biomemap[index]];
+	
+		if (biome->c_dust == CONTENT_IGNORE)
+			continue;
+
+		s16 y = node_max.Y;
+		u32 vi = vm->m_area.index(x, y, z);
+		for (; y >= node_min.Y; y--) {
+			if (vm->m_data[vi].getContent() != CONTENT_AIR)
+				break;
+
+			vm->m_area.add_y(em, vi, -1);
+		}
+			
+		content_t c = vm->m_data[vi].getContent();
+		if (c == biome->c_water && biome->c_dust_water != CONTENT_IGNORE) {
+			if (y < node_min.Y)
+				continue;
+				
+			vm->m_data[vi] = MapNode(biome->c_dust_water);
+		} else if (!ndef->get(c).buildable_to && c != CONTENT_IGNORE) {
+			if (y == node_max.Y)
+				continue;
+				
+			vm->m_area.add_y(em, vi, 1);
+			vm->m_data[vi] = MapNode(biome->c_dust);
+		}
+	}
+}
+
diff --git a/src/mapgen_v5.h b/src/mapgen_v5.h
new file mode 100644
index 0000000000000000000000000000000000000000..c38113fecfbfcf74cfb32c52103d01cafd179f22
--- /dev/null
+++ b/src/mapgen_v5.h
@@ -0,0 +1,115 @@
+/*
+Minetest
+Copyright (C) 2010-2013 kwolekr, Ryan Kwolek <kwolekr@minetest.net>
+
+This program is free software; you can redistribute it and/or modify
+it under the terms of the GNU Lesser General Public License as published by
+the Free Software Foundation; either version 2.1 of the License, or
+(at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+GNU Lesser General Public License for more details.
+
+You should have received a copy of the GNU Lesser General Public License along
+with this program; if not, write to the Free Software Foundation, Inc.,
+51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+*/
+
+#ifndef MAPGEN_V5_HEADER
+#define MAPGEN_V5_HEADER
+
+#include "mapgen.h"
+
+/////////////////// Mapgen V5 flags
+//#define MGV5_BLOBS 0x01
+
+extern FlagDesc flagdesc_mapgen_v5[];
+
+
+struct MapgenV5Params : public MapgenSpecificParams {
+	u32 spflags;
+	NoiseParams np_filler_depth;
+	NoiseParams np_factor;
+	NoiseParams np_height;
+	NoiseParams np_cave1;
+	NoiseParams np_cave2;
+	NoiseParams np_ground;
+	NoiseParams np_crumble;
+	NoiseParams np_wetness;
+
+	MapgenV5Params();
+	~MapgenV5Params() {}
+	
+	void readParams(Settings *settings);
+	void writeParams(Settings *settings);
+};
+
+
+class MapgenV5 : public Mapgen {
+public:
+	EmergeManager *emerge;
+	BiomeDefManager *bmgr;
+
+	int ystride;
+	int zstride;
+	u32 flags;
+	u32 spflags;
+
+	u32 blockseed;
+	v3s16 node_min;
+	v3s16 node_max;
+	v3s16 full_node_min;
+	v3s16 full_node_max;
+	
+	Noise *noise_filler_depth;
+	Noise *noise_factor;
+	Noise *noise_height;
+	Noise *noise_cave1;
+	Noise *noise_cave2;
+	Noise *noise_ground;
+	Noise *noise_crumble;
+	Noise *noise_wetness;
+	Noise *noise_heat;
+	Noise *noise_humidity;
+
+	content_t c_stone;
+	content_t c_dirt;
+	content_t c_dirt_with_grass;
+	content_t c_sand;
+	content_t c_water_source;
+	content_t c_lava_source;
+	content_t c_ice;
+	content_t c_gravel;
+	content_t c_cobble;
+	content_t c_desert_sand;
+	content_t c_desert_stone;
+	content_t c_mossycobble;
+	content_t c_sandbrick;
+	content_t c_stair_cobble;
+	content_t c_stair_sandstone;
+
+	MapgenV5(int mapgenid, MapgenParams *params, EmergeManager *emerge_);
+	~MapgenV5();
+	
+	virtual void makeChunk(BlockMakeData *data);
+	void calculateNoise();
+	void generateBaseTerrain();
+	void generateBlobs();
+	void generateBiomes();
+	void dustTopNodes();
+};
+
+
+struct MapgenFactoryV5 : public MapgenFactory {
+	Mapgen *createMapgen(int mgid, MapgenParams *params, EmergeManager *emerge) {
+		return new MapgenV5(mgid, params, emerge);
+	};
+	
+	MapgenSpecificParams *createMapgenParams() {
+		return new MapgenV5Params();
+	};
+};
+
+#endif
diff --git a/src/noise.cpp b/src/noise.cpp
index ba2fe54210a28dd5688afeaf93bf1c40d37ba630..c30e1570d2f38580f247afd71ded4d7afacde533 100644
--- a/src/noise.cpp
+++ b/src/noise.cpp
@@ -306,7 +306,6 @@ float noise3d_perlin_abs(float x, float y, float z, int seed,
 }
 
 
-// -1->0, 0->1, 1->0
 float contour(float v)
 {
 	v = fabs(v);
@@ -653,3 +652,4 @@ void Noise::transformNoiseMap()
 		i++;
 	}
 }
+
diff --git a/src/noise.h b/src/noise.h
index 34dcb7374ebda7dd887a123edb0442517cdd5b9a..aa489b2c0c747e745d49cbf102b0a412d77cefa2 100644
--- a/src/noise.h
+++ b/src/noise.h
@@ -152,6 +152,8 @@ inline float easeCurve(float t) {
 	return t * t * t * (t * (6.f * t - 15.f) + 10.f);
 }
 
+float contour(float v);
+
 #define NoisePerlin2D(np, x, y, s) \
 		((np)->offset + (np)->scale * noise2d_perlin( \
 		(float)(x) / (np)->spread.X, \