From eb7482fd73ed111d84644e3abca2b51eb22566f9 Mon Sep 17 00:00:00 2001
From: paramat <mat.gregory@virginmedia.com>
Date: Wed, 4 Mar 2015 10:14:07 +0000
Subject: [PATCH] Cavegen, mgv5: Cleanup code

Conf.example: Update mgv5 mapgen params
Mgv7: Lava caves only below -256
---
 minetest.conf.example |  38 +---
 src/cavegen.cpp       | 412 +++++++++++++++++++-----------------------
 src/cavegen.h         |   3 +-
 src/mapgen_v5.cpp     |  34 ++--
 src/mapgen_v7.cpp     |   2 +-
 5 files changed, 205 insertions(+), 284 deletions(-)

diff --git a/minetest.conf.example b/minetest.conf.example
index e8e304073..6731c9ece 100644
--- a/minetest.conf.example
+++ b/minetest.conf.example
@@ -486,33 +486,14 @@
 #    flags       = "defaults"
 #}
 #    Only the group format supports noise flags which are needed for eased noise.
-#    Mgv5 uses eased noise for np_cave1, np_cave2, np_ground and np_crumble, so these are shown in
-#    group format, other noise parameters are shown in positional format to save space.
+#    Mgv5 uses eased noise for np_ground so this is shown in group format,
+#    other noise parameters are shown in positional format to save space.
 
-#mgv5_spflags = blobs
 #mgv5_np_filler_depth = 0, 1, (150, 150, 150), 261, 4, 0.7, 2.0
 #mgv5_np_factor = 0, 1, (250, 250, 250), 920381, 3, 0.45, 2.0
 #mgv5_np_height = 0, 10, (250, 250, 250), 84174, 4, 0.5, 2.0
-#mgv5_np_cave1 = {
-#    offset      = 0
-#    scale       = 6
-#    spread      = (50, 50, 50)
-#    seed        = 52534
-#    octaves     = 4
-#    persistence = 0.5
-#    lacunarity  = 2.0
-#    flags       = "eased"
-#}
-#mgv5_np_cave2 = {
-#    offset      = 0
-#    scale       = 6
-#    spread      = (50, 50, 50)
-#    seed        = 10325
-#    octaves     = 4
-#    persistence = 0.5
-#    lacunarity  = 2.0
-#    flags       = "eased"
-#}
+#mgv5_np_cave1 = 0, 12, (50, 50, 50), 52534, 4, 0.5, 2.0
+#mgv5_np_cave2 = 0, 12, (50, 50, 50), 10325, 4, 0.5, 2.0
 #mgv5_np_ground = {
 #    offset      = 0
 #    scale       = 40
@@ -523,17 +504,6 @@
 #    lacunarity  = 2.0
 #    flags       = "eased"
 #}
-#mgv5_np_crumble = {
-#    offset      = 0
-#    scale       = 1
-#    spread      = (20, 20, 20)
-#    seed        = 34413
-#    octaves     = 3
-#    persistence = 1.3
-#    lacunarity  = 2.0
-#    flags       = "eased"
-#}
-#mgv5_np_wetness = 0, 1, (40, 40, 40), 32474, 4, 1.1, 2.0
 
 #mgv6_spflags = biomeblend, jungles, mudflow
 #mgv6_np_terrain_base = -4, 20, (250, 250, 250), 82341, 5, 0.6, 2.0
diff --git a/src/cavegen.cpp b/src/cavegen.cpp
index bac656511..8fb1a7293 100644
--- a/src/cavegen.cpp
+++ b/src/cavegen.cpp
@@ -28,43 +28,35 @@ with this program; if not, write to the Free Software Foundation, Inc.,
 NoiseParams nparams_caveliquids(0, 1, v3f(150.0, 150.0, 150.0), 776, 3, 0.6, 2.0);
 
 
-///////////////////////////////////////////////////////////////////////////////
+///////////////////////////////////////// Caves V5
 
 
-CaveV6::CaveV6(MapgenV6 *mg, PseudoRandom *ps, PseudoRandom *ps2, bool is_large_cave) {
+CaveV5::CaveV5(MapgenV5 *mg, PseudoRandom *ps) {
 	this->mg   = mg;
 	this->vm   = mg->vm;
 	this->ndef = mg->ndef;
 	this->water_level = mg->water_level;
-	this->large_cave = is_large_cave;
-	this->ps  = ps;
-	this->ps2 = ps2;
+	this->ps = ps;
 	this->c_water_source = mg->c_water_source;
 	this->c_lava_source  = mg->c_lava_source;
+	this->c_ice          = mg->c_ice;
+	this->np_caveliquids = &nparams_caveliquids;
 
-	min_tunnel_diameter = 2;
-	max_tunnel_diameter = ps->range(2, 6);
 	dswitchint = ps->range(1, 14);
-	flooded = true;
+	flooded    = ps->range(1, 2) == 2;
 
-	if (large_cave) {
-		part_max_length_rs = ps->range(2,4);
-		tunnel_routepoints = ps->range(5, ps->range(15,30));
-		min_tunnel_diameter = 5;
-		max_tunnel_diameter = ps->range(7, ps->range(8,24));
-	} else {
-		part_max_length_rs = ps->range(2,9);
-		tunnel_routepoints = ps->range(10, ps->range(15,30));
-	}
+	part_max_length_rs = ps->range(2, 4);
+	tunnel_routepoints = ps->range(5, ps->range(15, 30));
+	min_tunnel_diameter = 5;
+	max_tunnel_diameter = ps->range(7, ps->range(8, 24));
 
-	large_cave_is_flat = (ps->range(0,1) == 0);
+	large_cave_is_flat = (ps->range(0, 1) == 0);
 }
 
 
-void CaveV6::makeCave(v3s16 nmin, v3s16 nmax, int max_stone_height) {
+void CaveV5::makeCave(v3s16 nmin, v3s16 nmax, int max_stone_height) {
 	node_min = nmin;
 	node_max = nmax;
-	max_stone_y = max_stone_height;
 	main_direction = v3f(0, 0, 0);
 
 	// Allowed route area size in nodes
@@ -74,9 +66,8 @@ void CaveV6::makeCave(v3s16 nmin, v3s16 nmax, int max_stone_height) {
 
 	// Allow a bit more
 	//(this should be more than the maximum radius of the tunnel)
-	const s16 max_spread_amount = MAP_BLOCKSIZE;
 	s16 insure = 10;
-	s16 more = MYMAX(max_spread_amount - max_tunnel_diameter / 2 - insure, 1);
+	s16 more = MYMAX(MAP_BLOCKSIZE - max_tunnel_diameter / 2 - insure, 1);
 	ar += v3s16(1,0,1) * more * 2;
 	of -= v3s16(1,0,1) * more;
 
@@ -87,21 +78,19 @@ void CaveV6::makeCave(v3s16 nmin, v3s16 nmax, int max_stone_height) {
 	// Limit maximum to area
 	route_y_max = rangelim(route_y_max, 0, ar.Y - 1);
 
-	if (large_cave) {
-		s16 min = 0;
+	s16 min = 0;
 		if (node_min.Y < water_level && node_max.Y > water_level) {
 			min = water_level - max_tunnel_diameter/3 - of.Y;
 			route_y_max = water_level + max_tunnel_diameter/3 - of.Y;
 		}
-		route_y_min = ps->range(min, min + max_tunnel_diameter);
-		route_y_min = rangelim(route_y_min, 0, route_y_max);
-	}
+	route_y_min = ps->range(min, min + max_tunnel_diameter);
+	route_y_min = rangelim(route_y_min, 0, route_y_max);
 
 	s16 route_start_y_min = route_y_min;
 	s16 route_start_y_max = route_y_max;
 
-	route_start_y_min = rangelim(route_start_y_min, 0, ar.Y-1);
-	route_start_y_max = rangelim(route_start_y_max, route_start_y_min, ar.Y-1);
+	route_start_y_min = rangelim(route_start_y_min, 0, ar.Y - 1);
+	route_start_y_max = rangelim(route_start_y_max, route_start_y_min, ar.Y - 1);
 
 	// Randomize starting position
 	orp = v3f(
@@ -112,8 +101,7 @@ void CaveV6::makeCave(v3s16 nmin, v3s16 nmax, int max_stone_height) {
 
 	// Add generation notify begin event
 	v3s16 abs_pos(of.X + orp.X, of.Y + orp.Y, of.Z + orp.Z);
-	GenNotifyType notifytype = large_cave ?
-		GENNOTIFY_LARGECAVE_BEGIN : GENNOTIFY_CAVE_BEGIN;
+	GenNotifyType notifytype = GENNOTIFY_LARGECAVE_BEGIN;
 	mg->gennotify.addEvent(notifytype, abs_pos);
 
 	// Generate some tunnel starting from orp
@@ -122,85 +110,60 @@ void CaveV6::makeCave(v3s16 nmin, v3s16 nmax, int max_stone_height) {
 
 	// Add generation notify end event
 	abs_pos = v3s16(of.X + orp.X, of.Y + orp.Y, of.Z + orp.Z);
-	notifytype = large_cave ?
-		GENNOTIFY_LARGECAVE_END : GENNOTIFY_CAVE_END;
+	notifytype = GENNOTIFY_LARGECAVE_END;
 	mg->gennotify.addEvent(notifytype, abs_pos);
 }
 
 
-void CaveV6::makeTunnel(bool dirswitch) {
-	if (dirswitch && !large_cave) {
-		main_direction = v3f(
-			((float)(ps->next() % 20) - (float)10) / 10,
-			((float)(ps->next() % 20) - (float)10) / 30,
-			((float)(ps->next() % 20) - (float)10) / 10
-		);
-		main_direction *= (float)ps->range(0, 10) / 10;
-	}
+void CaveV5::makeTunnel(bool dirswitch) {
 
 	// Randomize size
 	s16 min_d = min_tunnel_diameter;
 	s16 max_d = max_tunnel_diameter;
 	rs = ps->range(min_d, max_d);
+	s16 rs_part_max_length_rs = rs * part_max_length_rs;
 
 	v3s16 maxlen;
-	if (large_cave) {
-		maxlen = v3s16(
-			rs * part_max_length_rs,
-			rs * part_max_length_rs / 2,
-			rs * part_max_length_rs
-		);
-	} else {
-		maxlen = v3s16(
-			rs * part_max_length_rs,
-			ps->range(1, rs * part_max_length_rs),
-			rs * part_max_length_rs
-		);
-	}
-
-	v3f vec(
-		(float)(ps->next() % (maxlen.X * 1)) - (float)maxlen.X / 2,
-		(float)(ps->next() % (maxlen.Y * 1)) - (float)maxlen.Y / 2,
-		(float)(ps->next() % (maxlen.Z * 1)) - (float)maxlen.Z / 2
+	maxlen = v3s16(
+		rs_part_max_length_rs,
+		rs_part_max_length_rs / 2,
+		rs_part_max_length_rs
 	);
 
+	v3f vec;
 	// Jump downward sometimes
-	if (!large_cave && ps->range(0, 12) == 0) {
-		vec = v3f(
-			(float)(ps->next() % (maxlen.X * 1)) - (float)maxlen.X / 2,
-			(float)(ps->next() % (maxlen.Y * 2)) - (float)maxlen.Y,
-			(float)(ps->next() % (maxlen.Z * 1)) - (float)maxlen.Z / 2
-		);
-	}
+	vec = v3f(
+		(float)(ps->next() % maxlen.X) - (float)maxlen.X / 2,
+		(float)(ps->next() % maxlen.Y) - (float)maxlen.Y / 2,
+		(float)(ps->next() % maxlen.Z) - (float)maxlen.Z / 2
+	);
 
-	// Do not make large caves that are entirely above ground.
+	// Do not make large caves that are above ground.
 	// It is only necessary to check the startpoint and endpoint.
-	if (large_cave) {
-		v3s16 orpi(orp.X, orp.Y, orp.Z);
-		v3s16 veci(vec.X, vec.Y, vec.Z);
-		s16 h1;
-		s16 h2;
-
-		v3s16 p1 = orpi + veci + of + rs / 2;
-		if (p1.Z >= node_min.Z && p1.Z <= node_max.Z &&
-				p1.X >= node_min.X && p1.X <= node_max.X) {
-			u32 index1 = (p1.Z - node_min.Z) * mg->ystride + (p1.X - node_min.X);
-			h1 = mg->heightmap[index1];
-		} else {
-			h1 = water_level; // If not in heightmap
-		}
+	v3s16 orpi(orp.X, orp.Y, orp.Z);
+	v3s16 veci(vec.X, vec.Y, vec.Z);
+	v3s16 p;
 
-		v3s16 p2 = orpi + of + rs / 2;
-		if (p2.Z >= node_min.Z && p2.Z <= node_max.Z &&
-				p2.X >= node_min.X && p2.X <= node_max.X) {
-			u32 index2 = (p2.Z - node_min.Z) * mg->ystride + (p2.X - node_min.X);
-			h2 = mg->heightmap[index2];
-		} else {
-			h2 = water_level;
-		}
+	p = orpi + veci + of + rs / 2;
+	if (p.Z >= node_min.Z && p.Z <= node_max.Z &&
+			p.X >= node_min.X && p.X <= node_max.X) {
+		u32 index = (p.Z - node_min.Z) * mg->ystride + (p.X - node_min.X);
+		s16 h = mg->heightmap[index];
+		if (h < p.Y)
+			return;
+	} else if (p.Y > water_level) {
+		return; // If it's not in our heightmap, use a simple heuristic
+	}
 
-		if (p1.Y > h1 && p2.Y > h2) // If startpoint and endpoint are above ground
+	p = orpi + of + rs / 2;
+	if (p.Z >= node_min.Z && p.Z <= node_max.Z &&
+		p.X >= node_min.X && p.X <= node_max.X) {
+		u32 index = (p.Z - node_min.Z) * mg->ystride + (p.X - node_min.X);
+		s16 h = mg->heightmap[index];
+		if (h < p.Y)
 			return;
+	} else if (p.Y > water_level) {
+		return;
 	}
 
 	vec += main_direction;
@@ -224,22 +187,26 @@ void CaveV6::makeTunnel(bool dirswitch) {
 	vec = rp - orp;
 
 	float veclen = vec.getLength();
-	// As odd as it sounds, veclen is *exactly* 0.0 sometimes, causing a FPE
 	if (veclen < 0.05)
 		veclen = 1.0;
 
 	// Every second section is rough
-	bool randomize_xz = (ps2->range(1, 2) == 1);
+	bool randomize_xz = (ps->range(1, 2) == 1);
+
+	// Make a ravine every once in a while if it's long enough
+	//float xylen = vec.X * vec.X + vec.Z * vec.Z;
+	//disable ravines for now
+	bool is_ravine = false; //(xylen > 500.0) && !large_cave && (ps->range(1, 8) == 1);
 
 	// Carve routes
 	for (float f = 0; f < 1.0; f += 1.0 / veclen)
-		carveRoute(vec, f, randomize_xz);
+		carveRoute(vec, f, randomize_xz, is_ravine);
 
 	orp = rp;
 }
 
 
-void CaveV6::carveRoute(v3f vec, float f, bool randomize_xz) {
+void CaveV5::carveRoute(v3f vec, float f, bool randomize_xz, bool is_ravine) {
 	MapNode airnode(CONTENT_AIR);
 	MapNode waternode(c_water_source);
 	MapNode lavanode(c_lava_source);
@@ -247,6 +214,10 @@ void CaveV6::carveRoute(v3f vec, float f, bool randomize_xz) {
 	v3s16 startp(orp.X, orp.Y, orp.Z);
 	startp += of;
 
+	float nval = NoisePerlin3D(np_caveliquids, startp.X,
+							startp.Y, startp.Z, mg->seed);
+	MapNode liquidnode = nval < 0.40 ? lavanode : waternode;
+
 	v3f fp = orp + vec * f;
 	fp.X += 0.1 * ps->range(-10, 10);
 	fp.Z += 0.1 * ps->range(-10, 10);
@@ -259,11 +230,16 @@ void CaveV6::carveRoute(v3f vec, float f, bool randomize_xz) {
 		d1 += ps->range(-1, 1);
 	}
 
+	bool should_make_cave_hole = ps->range(1, 10) == 1;
+
 	for (s16 z0 = d0; z0 <= d1; z0++) {
 		s16 si = rs / 2 - MYMAX(0, abs(z0) - rs / 7 - 1);
 		for (s16 x0 = -si - ps->range(0,1); x0 <= si - 1 + ps->range(0,1); x0++) {
 			s16 maxabsxz = MYMAX(abs(x0), abs(z0));
-			s16 si2 = rs / 2 - MYMAX(0, maxabsxz - rs / 7 - 1);
+
+			s16 si2 = is_ravine ? MYMIN(ps->range(25, 26), ar.Y) :
+								 rs / 2 - MYMAX(0, maxabsxz - rs / 7 - 1);
+
 			for (s16 y0 = -si2; y0 <= si2; y0++) {
 				if (large_cave_is_flat) {
 					// Make large caves not so tall
@@ -274,75 +250,74 @@ void CaveV6::carveRoute(v3f vec, float f, bool randomize_xz) {
 				v3s16 p(cp.X + x0, cp.Y + y0, cp.Z + z0);
 				p += of;
 
+				if (!is_ravine && mg->heightmap && should_make_cave_hole &&
+					p.X <= node_max.X && p.Z <= node_max.Z) {
+					int maplen = node_max.X - node_min.X + 1;
+					int idx = (p.Z - node_min.Z) * maplen + (p.X - node_min.X);
+					if (p.Y >= mg->heightmap[idx] - 2)
+						continue;
+				}
+
 				if (vm->m_area.contains(p) == false)
 					continue;
 
 				u32 i = vm->m_area.index(p);
+
+				// Don't replace air, water, lava, or ice
 				content_t c = vm->m_data[i].getContent();
-				if (!ndef->get(c).is_ground_content)
+				if (!ndef->get(c).is_ground_content || c == CONTENT_AIR ||
+					c == c_water_source || c == c_lava_source || c == c_ice)
 					continue;
 
-				if (large_cave) {
-					int full_ymin = node_min.Y - MAP_BLOCKSIZE;
-					int full_ymax = node_max.Y + MAP_BLOCKSIZE;
-
-					if (flooded && full_ymin < water_level && full_ymax > water_level) {
-						vm->m_data[i] = (p.Y <= water_level) ? waternode : airnode;
-					} else if (flooded && full_ymax < water_level) {
-						vm->m_data[i] = (p.Y < startp.Y - 2) ? lavanode : airnode;
-					} else {
-						vm->m_data[i] = airnode;
-					}
-				} else {
-					// Don't replace air or water or lava or ignore
-					if (c == CONTENT_IGNORE || c == CONTENT_AIR ||
-						c == c_water_source || c == c_lava_source)
-						continue;
+				int full_ymin = node_min.Y - MAP_BLOCKSIZE;
+				int full_ymax = node_max.Y + MAP_BLOCKSIZE;
 
+				if (flooded && full_ymin < water_level && full_ymax > water_level)
+					vm->m_data[i] = (p.Y <= water_level) ? waternode : airnode;
+				else if (flooded && full_ymax < water_level)
+					vm->m_data[i] = (p.Y < startp.Y - 4) ? liquidnode : airnode;
+				else
 					vm->m_data[i] = airnode;
-					vm->m_flags[i] |= VMANIP_FLAG_CAVE;
-				}
 			}
 		}
 	}
 }
 
 
-///////////////////////////////////////// Caves V7
+///////////////////////////////////////// Caves V6
 
 
-CaveV7::CaveV7(MapgenV7 *mg, PseudoRandom *ps, bool is_large_cave) {
+CaveV6::CaveV6(MapgenV6 *mg, PseudoRandom *ps, PseudoRandom *ps2, bool is_large_cave) {
 	this->mg   = mg;
 	this->vm   = mg->vm;
 	this->ndef = mg->ndef;
 	this->water_level = mg->water_level;
-	this->large_cave  = is_large_cave;
-	this->ps = ps;
+	this->large_cave = is_large_cave;
+	this->ps  = ps;
+	this->ps2 = ps2;
 	this->c_water_source = mg->c_water_source;
 	this->c_lava_source  = mg->c_lava_source;
-	this->c_ice          = mg->c_ice;
-	this->np_caveliquids = &nparams_caveliquids;
 
+	min_tunnel_diameter = 2;
+	max_tunnel_diameter = ps->range(2, 6);
 	dswitchint = ps->range(1, 14);
-	flooded    = ps->range(1, 2) == 2;
+	flooded = true;
 
 	if (large_cave) {
-		part_max_length_rs = ps->range(2, 4);
-		tunnel_routepoints = ps->range(5, ps->range(15, 30));
+		part_max_length_rs = ps->range(2,4);
+		tunnel_routepoints = ps->range(5, ps->range(15,30));
 		min_tunnel_diameter = 5;
-		max_tunnel_diameter = ps->range(7, ps->range(8, 24));
+		max_tunnel_diameter = ps->range(7, ps->range(8,24));
 	} else {
-		part_max_length_rs = ps->range(2, 9);
-		tunnel_routepoints = ps->range(10, ps->range(15, 30));
-		min_tunnel_diameter = 2;
-		max_tunnel_diameter = ps->range(2, 6);
+		part_max_length_rs = ps->range(2,9);
+		tunnel_routepoints = ps->range(10, ps->range(15,30));
 	}
 
-	large_cave_is_flat = (ps->range(0, 1) == 0);
+	large_cave_is_flat = (ps->range(0,1) == 0);
 }
 
 
-void CaveV7::makeCave(v3s16 nmin, v3s16 nmax, int max_stone_height) {
+void CaveV6::makeCave(v3s16 nmin, v3s16 nmax, int max_stone_height) {
 	node_min = nmin;
 	node_max = nmax;
 	max_stone_y = max_stone_height;
@@ -355,8 +330,9 @@ void CaveV7::makeCave(v3s16 nmin, v3s16 nmax, int max_stone_height) {
 
 	// Allow a bit more
 	//(this should be more than the maximum radius of the tunnel)
+	const s16 max_spread_amount = MAP_BLOCKSIZE;
 	s16 insure = 10;
-	s16 more = MYMAX(MAP_BLOCKSIZE - max_tunnel_diameter / 2 - insure, 1);
+	s16 more = MYMAX(max_spread_amount - max_tunnel_diameter / 2 - insure, 1);
 	ar += v3s16(1,0,1) * more * 2;
 	of -= v3s16(1,0,1) * more;
 
@@ -380,8 +356,8 @@ void CaveV7::makeCave(v3s16 nmin, v3s16 nmax, int max_stone_height) {
 	s16 route_start_y_min = route_y_min;
 	s16 route_start_y_max = route_y_max;
 
-	route_start_y_min = rangelim(route_start_y_min, 0, ar.Y - 1);
-	route_start_y_max = rangelim(route_start_y_max, route_start_y_min, ar.Y - 1);
+	route_start_y_min = rangelim(route_start_y_min, 0, ar.Y-1);
+	route_start_y_max = rangelim(route_start_y_max, route_start_y_min, ar.Y-1);
 
 	// Randomize starting position
 	orp = v3f(
@@ -408,7 +384,7 @@ void CaveV7::makeCave(v3s16 nmin, v3s16 nmax, int max_stone_height) {
 }
 
 
-void CaveV7::makeTunnel(bool dirswitch) {
+void CaveV6::makeTunnel(bool dirswitch) {
 	if (dirswitch && !large_cave) {
 		main_direction = v3f(
 			((float)(ps->next() % 20) - (float)10) / 10,
@@ -422,66 +398,66 @@ void CaveV7::makeTunnel(bool dirswitch) {
 	s16 min_d = min_tunnel_diameter;
 	s16 max_d = max_tunnel_diameter;
 	rs = ps->range(min_d, max_d);
+	s16 rs_part_max_length_rs = rs * part_max_length_rs;
 
 	v3s16 maxlen;
 	if (large_cave) {
 		maxlen = v3s16(
-			rs * part_max_length_rs,
-			rs * part_max_length_rs / 2,
-			rs * part_max_length_rs
+			rs_part_max_length_rs,
+			rs_part_max_length_rs / 2,
+			rs_part_max_length_rs
 		);
 	} else {
 		maxlen = v3s16(
-			rs * part_max_length_rs,
-			ps->range(1, rs * part_max_length_rs),
-			rs * part_max_length_rs
+			rs_part_max_length_rs,
+			ps->range(1, rs_part_max_length_rs),
+			rs_part_max_length_rs
 		);
 	}
 
-	v3f vec;
+	v3f vec(
+		(float)(ps->next() % maxlen.X) - (float)maxlen.X / 2,
+		(float)(ps->next() % maxlen.Y) - (float)maxlen.Y / 2,
+		(float)(ps->next() % maxlen.Z) - (float)maxlen.Z / 2
+	);
+
 	// Jump downward sometimes
 	if (!large_cave && ps->range(0, 12) == 0) {
 		vec = v3f(
-			(float)(ps->next() % (maxlen.X * 1)) - (float)maxlen.X / 2,
+			(float)(ps->next() % maxlen.X) - (float)maxlen.X / 2,
 			(float)(ps->next() % (maxlen.Y * 2)) - (float)maxlen.Y,
-			(float)(ps->next() % (maxlen.Z * 1)) - (float)maxlen.Z / 2
-		);
-	} else {
-		vec = v3f(
-			(float)(ps->next() % (maxlen.X * 1)) - (float)maxlen.X / 2,
-			(float)(ps->next() % (maxlen.Y * 1)) - (float)maxlen.Y / 2,
-			(float)(ps->next() % (maxlen.Z * 1)) - (float)maxlen.Z / 2
+			(float)(ps->next() % maxlen.Z) - (float)maxlen.Z / 2
 		);
 	}
 
-	// Do not make large caves that are above ground.
+	// Do not make large caves that are entirely above ground.
 	// It is only necessary to check the startpoint and endpoint.
 	if (large_cave) {
 		v3s16 orpi(orp.X, orp.Y, orp.Z);
 		v3s16 veci(vec.X, vec.Y, vec.Z);
-		v3s16 p;
-
-		p = orpi + veci + of + rs / 2;
-		if (p.Z >= node_min.Z && p.Z <= node_max.Z &&
-				p.X >= node_min.X && p.X <= node_max.X) {
-			u32 index = (p.Z - node_min.Z) * mg->ystride + (p.X - node_min.X);
-			s16 h = mg->ridge_heightmap[index];
-			if (h < p.Y)
-				return;
-		} else if (p.Y > water_level) {
-			return; // If it's not in our heightmap, use a simple heuristic
+		s16 h1;
+		s16 h2;
+
+		v3s16 p1 = orpi + veci + of + rs / 2;
+		if (p1.Z >= node_min.Z && p1.Z <= node_max.Z &&
+				p1.X >= node_min.X && p1.X <= node_max.X) {
+			u32 index1 = (p1.Z - node_min.Z) * mg->ystride + (p1.X - node_min.X);
+			h1 = mg->heightmap[index1];
+		} else {
+			h1 = water_level; // If not in heightmap
 		}
 
-		p = orpi + of + rs / 2;
-		if (p.Z >= node_min.Z && p.Z <= node_max.Z &&
-				p.X >= node_min.X && p.X <= node_max.X) {
-			u32 index = (p.Z - node_min.Z) * mg->ystride + (p.X - node_min.X);
-			s16 h = mg->ridge_heightmap[index];
-			if (h < p.Y)
-				return;
-		} else if (p.Y > water_level) {
-			return;
+		v3s16 p2 = orpi + of + rs / 2;
+		if (p2.Z >= node_min.Z && p2.Z <= node_max.Z &&
+				p2.X >= node_min.X && p2.X <= node_max.X) {
+			u32 index2 = (p2.Z - node_min.Z) * mg->ystride + (p2.X - node_min.X);
+			h2 = mg->heightmap[index2];
+		} else {
+			h2 = water_level;
 		}
+
+		if (p1.Y > h1 && p2.Y > h2) // If startpoint and endpoint are above ground
+			return;
 	}
 
 	vec += main_direction;
@@ -505,26 +481,22 @@ void CaveV7::makeTunnel(bool dirswitch) {
 	vec = rp - orp;
 
 	float veclen = vec.getLength();
+	// As odd as it sounds, veclen is *exactly* 0.0 sometimes, causing a FPE
 	if (veclen < 0.05)
 		veclen = 1.0;
 
 	// Every second section is rough
-	bool randomize_xz = (ps->range(1, 2) == 1);
-
-	// Make a ravine every once in a while if it's long enough
-	//float xylen = vec.X * vec.X + vec.Z * vec.Z;
-	//disable ravines for now
-	bool is_ravine = false; //(xylen > 500.0) && !large_cave && (ps->range(1, 8) == 1);
+	bool randomize_xz = (ps2->range(1, 2) == 1);
 
 	// Carve routes
 	for (float f = 0; f < 1.0; f += 1.0 / veclen)
-		carveRoute(vec, f, randomize_xz, is_ravine);
+		carveRoute(vec, f, randomize_xz);
 
 	orp = rp;
 }
 
 
-void CaveV7::carveRoute(v3f vec, float f, bool randomize_xz, bool is_ravine) {
+void CaveV6::carveRoute(v3f vec, float f, bool randomize_xz) {
 	MapNode airnode(CONTENT_AIR);
 	MapNode waternode(c_water_source);
 	MapNode lavanode(c_lava_source);
@@ -532,10 +504,6 @@ void CaveV7::carveRoute(v3f vec, float f, bool randomize_xz, bool is_ravine) {
 	v3s16 startp(orp.X, orp.Y, orp.Z);
 	startp += of;
 
-	float nval = NoisePerlin3D(np_caveliquids, startp.X,
-							startp.Y, startp.Z, mg->seed);
-	MapNode liquidnode = nval < 0.40 ? lavanode : waternode;
-
 	v3f fp = orp + vec * f;
 	fp.X += 0.1 * ps->range(-10, 10);
 	fp.Z += 0.1 * ps->range(-10, 10);
@@ -548,22 +516,12 @@ void CaveV7::carveRoute(v3f vec, float f, bool randomize_xz, bool is_ravine) {
 		d1 += ps->range(-1, 1);
 	}
 
-	bool flat_cave_floor = !large_cave && ps->range(0, 2) == 2;
-	bool should_make_cave_hole = ps->range(1, 10) == 1;
-
 	for (s16 z0 = d0; z0 <= d1; z0++) {
 		s16 si = rs / 2 - MYMAX(0, abs(z0) - rs / 7 - 1);
 		for (s16 x0 = -si - ps->range(0,1); x0 <= si - 1 + ps->range(0,1); x0++) {
 			s16 maxabsxz = MYMAX(abs(x0), abs(z0));
-
-			s16 si2 = is_ravine ? MYMIN(ps->range(25, 26), ar.Y) :
-								 rs / 2 - MYMAX(0, maxabsxz - rs / 7 - 1);
-
+			s16 si2 = rs / 2 - MYMAX(0, maxabsxz - rs / 7 - 1);
 			for (s16 y0 = -si2; y0 <= si2; y0++) {
-				// Make better floors in small caves
-				if(flat_cave_floor && y0 <= -rs/2 && rs<=7)
-					continue;
-
 				if (large_cave_is_flat) {
 					// Make large caves not so tall
 					if (rs > 7 && abs(y0) >= rs / 3)
@@ -573,37 +531,29 @@ void CaveV7::carveRoute(v3f vec, float f, bool randomize_xz, bool is_ravine) {
 				v3s16 p(cp.X + x0, cp.Y + y0, cp.Z + z0);
 				p += of;
 
-				if (!is_ravine && mg->heightmap && should_make_cave_hole &&
-					p.X <= node_max.X && p.Z <= node_max.Z) {
-					int maplen = node_max.X - node_min.X + 1;
-					int idx = (p.Z - node_min.Z) * maplen + (p.X - node_min.X);
-					if (p.Y >= mg->heightmap[idx] - 2)
-						continue;
-				}
-
 				if (vm->m_area.contains(p) == false)
 					continue;
 
 				u32 i = vm->m_area.index(p);
-
-				// Don't replace air, water, lava, or ice
 				content_t c = vm->m_data[i].getContent();
-				if (!ndef->get(c).is_ground_content || c == CONTENT_AIR ||
-					c == c_water_source || c == c_lava_source || c == c_ice)
+				if (!ndef->get(c).is_ground_content)
 					continue;
 
 				if (large_cave) {
 					int full_ymin = node_min.Y - MAP_BLOCKSIZE;
 					int full_ymax = node_max.Y + MAP_BLOCKSIZE;
 
-					if (flooded && full_ymin < water_level && full_ymax > water_level)
+					if (flooded && full_ymin < water_level && full_ymax > water_level) {
 						vm->m_data[i] = (p.Y <= water_level) ? waternode : airnode;
-					else if (flooded && full_ymax < water_level)
-						vm->m_data[i] = (p.Y < startp.Y - 4) ? liquidnode : airnode;
-					else
+					} else if (flooded && full_ymax < water_level) {
+						vm->m_data[i] = (p.Y < startp.Y - 2) ? lavanode : airnode;
+					} else {
 						vm->m_data[i] = airnode;
+					}
 				} else {
-					if (c == CONTENT_IGNORE)
+					// Don't replace air or water or lava or ignore
+					if (c == CONTENT_IGNORE || c == CONTENT_AIR ||
+						c == c_water_source || c == c_lava_source)
 						continue;
 
 					vm->m_data[i] = airnode;
@@ -615,10 +565,10 @@ void CaveV7::carveRoute(v3f vec, float f, bool randomize_xz, bool is_ravine) {
 }
 
 
-///////////////////////////////////////// Caves V5
+///////////////////////////////////////// Caves V7
 
 
-CaveV5::CaveV5(MapgenV5 *mg, PseudoRandom *ps) {
+CaveV7::CaveV7(MapgenV7 *mg, PseudoRandom *ps) {
 	this->mg   = mg;
 	this->vm   = mg->vm;
 	this->ndef = mg->ndef;
@@ -641,9 +591,10 @@ CaveV5::CaveV5(MapgenV5 *mg, PseudoRandom *ps) {
 }
 
 
-void CaveV5::makeCave(v3s16 nmin, v3s16 nmax, int max_stone_height) {
+void CaveV7::makeCave(v3s16 nmin, v3s16 nmax, int max_stone_height) {
 	node_min = nmin;
 	node_max = nmax;
+	max_stone_y = max_stone_height;
 	main_direction = v3f(0, 0, 0);
 
 	// Allowed route area size in nodes
@@ -666,10 +617,10 @@ void CaveV5::makeCave(v3s16 nmin, v3s16 nmax, int max_stone_height) {
 	route_y_max = rangelim(route_y_max, 0, ar.Y - 1);
 
 	s16 min = 0;
-		if (node_min.Y < water_level && node_max.Y > water_level) {
-			min = water_level - max_tunnel_diameter/3 - of.Y;
-			route_y_max = water_level + max_tunnel_diameter/3 - of.Y;
-		}
+	if (node_min.Y < water_level && node_max.Y > water_level) {
+		min = water_level - max_tunnel_diameter/3 - of.Y;
+		route_y_max = water_level + max_tunnel_diameter/3 - of.Y;
+	}
 	route_y_min = ps->range(min, min + max_tunnel_diameter);
 	route_y_min = rangelim(route_y_min, 0, route_y_max);
 
@@ -702,26 +653,27 @@ void CaveV5::makeCave(v3s16 nmin, v3s16 nmax, int max_stone_height) {
 }
 
 
-void CaveV5::makeTunnel(bool dirswitch) {
+void CaveV7::makeTunnel(bool dirswitch) {
 
 	// Randomize size
 	s16 min_d = min_tunnel_diameter;
 	s16 max_d = max_tunnel_diameter;
 	rs = ps->range(min_d, max_d);
+	s16 rs_part_max_length_rs = rs * part_max_length_rs;
 
 	v3s16 maxlen;
 	maxlen = v3s16(
-		rs * part_max_length_rs,
-		rs * part_max_length_rs / 2,
-		rs * part_max_length_rs
+		rs_part_max_length_rs,
+		rs_part_max_length_rs / 2,
+		rs_part_max_length_rs
 	);
 
 	v3f vec;
 	// Jump downward sometimes
 	vec = v3f(
-		(float)(ps->next() % (maxlen.X * 1)) - (float)maxlen.X / 2,
-		(float)(ps->next() % (maxlen.Y * 1)) - (float)maxlen.Y / 2,
-		(float)(ps->next() % (maxlen.Z * 1)) - (float)maxlen.Z / 2
+		(float)(ps->next() % maxlen.X) - (float)maxlen.X / 2,
+		(float)(ps->next() % maxlen.Y) - (float)maxlen.Y / 2,
+		(float)(ps->next() % maxlen.Z) - (float)maxlen.Z / 2
 	);
 
 	// Do not make large caves that are above ground.
@@ -734,7 +686,7 @@ void CaveV5::makeTunnel(bool dirswitch) {
 	if (p.Z >= node_min.Z && p.Z <= node_max.Z &&
 			p.X >= node_min.X && p.X <= node_max.X) {
 		u32 index = (p.Z - node_min.Z) * mg->ystride + (p.X - node_min.X);
-		s16 h = mg->heightmap[index];
+		s16 h = mg->ridge_heightmap[index];
 		if (h < p.Y)
 			return;
 	} else if (p.Y > water_level) {
@@ -743,9 +695,9 @@ void CaveV5::makeTunnel(bool dirswitch) {
 
 	p = orpi + of + rs / 2;
 	if (p.Z >= node_min.Z && p.Z <= node_max.Z &&
-		p.X >= node_min.X && p.X <= node_max.X) {
+			p.X >= node_min.X && p.X <= node_max.X) {
 		u32 index = (p.Z - node_min.Z) * mg->ystride + (p.X - node_min.X);
-		s16 h = mg->heightmap[index];
+		s16 h = mg->ridge_heightmap[index];
 		if (h < p.Y)
 			return;
 	} else if (p.Y > water_level) {
@@ -792,7 +744,7 @@ void CaveV5::makeTunnel(bool dirswitch) {
 }
 
 
-void CaveV5::carveRoute(v3f vec, float f, bool randomize_xz, bool is_ravine) {
+void CaveV7::carveRoute(v3f vec, float f, bool randomize_xz, bool is_ravine) {
 	MapNode airnode(CONTENT_AIR);
 	MapNode waternode(c_water_source);
 	MapNode lavanode(c_lava_source);
@@ -802,7 +754,7 @@ void CaveV5::carveRoute(v3f vec, float f, bool randomize_xz, bool is_ravine) {
 
 	float nval = NoisePerlin3D(np_caveliquids, startp.X,
 							startp.Y, startp.Z, mg->seed);
-	MapNode liquidnode = nval < 0.40 ? lavanode : waternode;
+	MapNode liquidnode = (nval < 0.40 && node_max.Y < -256) ? lavanode : waternode;
 
 	v3f fp = orp + vec * f;
 	fp.X += 0.1 * ps->range(-10, 10);
diff --git a/src/cavegen.h b/src/cavegen.h
index 0b57bf4dc..27626753a 100644
--- a/src/cavegen.h
+++ b/src/cavegen.h
@@ -129,7 +129,6 @@ class CaveV7 {
 	int dswitchint;
 	int part_max_length_rs;
 
-	bool large_cave;
 	bool large_cave_is_flat;
 	bool flooded;
 
@@ -155,7 +154,7 @@ class CaveV7 {
 	int water_level;
 
 	CaveV7() {}
-	CaveV7(MapgenV7 *mg, PseudoRandom *ps, bool large_cave);
+	CaveV7(MapgenV7 *mg, PseudoRandom *ps);
 	void makeCave(v3s16 nmin, v3s16 nmax, int max_stone_height);
 	void makeTunnel(bool dirswitch);
 	void carveRoute(v3f vec, float f, bool randomize_xz, bool is_ravine);
diff --git a/src/mapgen_v5.cpp b/src/mapgen_v5.cpp
index e3624c2bd..9392c35b1 100644
--- a/src/mapgen_v5.cpp
+++ b/src/mapgen_v5.cpp
@@ -171,9 +171,9 @@ int MapgenV5::getGroundLevelAtPoint(v2s16 p)
 	//TimeTaker t("getGroundLevelAtPoint", NULL, PRECISION_MICRO);
 
 	float f = 0.55 + NoisePerlin2D(&noise_factor->np, p.X, p.Y, seed);
-	if(f < 0.01)
+	if (f < 0.01)
 		f = 0.01;
-	else if(f >= 1.0)
+	else if (f >= 1.0)
 		f *= 1.6;
 	float h = water_level + NoisePerlin2D(&noise_height->np, p.X, p.Y, seed);
 
@@ -183,8 +183,8 @@ int MapgenV5::getGroundLevelAtPoint(v2s16 p)
 	s16 level = -31000;
 	for (s16 y = search_top; y >= search_base; y--) {
 		float n_ground = NoisePerlin3D(&noise_ground->np, p.X, y, p.Y, seed);
-		if(n_ground * f > y - h) {
-			if(y >= search_top - 7)
+		if (n_ground * f > y - h) {
+			if (y >= search_top - 7)
 				break;
 			else
 				level = y;
@@ -322,22 +322,22 @@ int MapgenV5::generateBaseTerrain()
 	u32 index2d = 0;
 	int stone_surface_max_y = -MAP_GENERATION_LIMIT;
 
-	for(s16 z=node_min.Z; z<=node_max.Z; z++) {
-		for(s16 y=node_min.Y - 1; y<=node_max.Y + 1; y++) {
+	for (s16 z=node_min.Z; z<=node_max.Z; z++) {
+		for (s16 y=node_min.Y - 1; y<=node_max.Y + 1; 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)
+			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)
+				if (f < 0.01)
 					f = 0.01;
-				else if(f >= 1.0)
+				else if (f >= 1.0)
 					f *= 1.6;
 				float h = noise_height->result[index2d];
 
-				if(noise_ground->result[index] * f < y - h) {
-					if(y <= water_level)
+				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);
@@ -443,13 +443,13 @@ void MapgenV5::generateCaves(int max_stone_y)
 	u32 index = 0;
 	u32 index2d = 0;
 
-	for(s16 z=node_min.Z; z<=node_max.Z; z++) {
-		for(s16 y=node_min.Y - 1; y<=node_max.Y + 1; y++) {
+	for (s16 z=node_min.Z; z<=node_max.Z; z++) {
+		for (s16 y=node_min.Y - 1; y<=node_max.Y + 1; 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++) {
+			for (s16 x=node_min.X; x<=node_max.X; x++, i++, index++, index2d++) {
 				Biome *biome = (Biome *)bmgr->get(biomemap[index2d]);
 				content_t c = vm->m_data[i].getContent();
-				if(c == CONTENT_AIR
+				if (c == CONTENT_AIR
 						|| (y <= water_level
 						&& c != biome->c_stone
 						&& c != c_stone))
@@ -457,7 +457,7 @@ void MapgenV5::generateCaves(int max_stone_y)
 
 				float d1 = contour(noise_cave1->result[index]);
 				float d2 = contour(noise_cave2->result[index]);
-				if(d1*d2 > 0.125)
+				if (d1*d2 > 0.125)
 					vm->m_data[i] = MapNode(CONTENT_AIR);
 			}
 			index2d = index2d - ystride;
diff --git a/src/mapgen_v7.cpp b/src/mapgen_v7.cpp
index 29d311575..6bdb5a177 100644
--- a/src/mapgen_v7.cpp
+++ b/src/mapgen_v7.cpp
@@ -790,7 +790,7 @@ void MapgenV7::generateCaves(int max_stone_y)
 	PseudoRandom ps(blockseed + 21343);
 	u32 bruises_count = (ps.range(1, 5) == 1) ? ps.range(1, 2) : 0;
 	for (u32 i = 0; i < bruises_count; i++) {
-		CaveV7 cave(this, &ps, true);
+		CaveV7 cave(this, &ps);
 		cave.makeCave(node_min, node_max, max_stone_y);
 	}
 }
-- 
GitLab