Beispiel #1
0
void CaveV6::carveRoute(v3f vec, float f, bool randomize_xz, bool tunnel_above_ground)
{
	MapNode airnode(CONTENT_AIR);
	MapNode waternode(c_water_source);
	MapNode lavanode(c_lava_source);

	v3s16 startp(orp.X, orp.Y, orp.Z);
	startp += of;

	v3f fp = orp + vec * f;
	fp.X += 0.1 * ps->range(-10, 10);
	fp.Z += 0.1 * ps->range(-10, 10);
	v3s16 cp(fp.X, fp.Y, fp.Z);

	s16 d0 = -rs/2;
	s16 d1 = d0 + rs;
	if (randomize_xz) {
		d0 += ps->range(-1, 1);
		d1 += ps->range(-1, 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++) {
			if (tunnel_above_ground)
				continue;

			s16 maxabsxz = MYMAX(abs(x0), abs(z0));
			s16 si2 = 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
					if (rs > 7 && abs(y0) >= rs / 3)
						continue;
				}

				v3s16 p(cp.X + x0, cp.Y + y0, cp.Z + z0);
				p += of;

				if (vm->m_area.contains(p) == false)
					continue;

				u32 i = vm->m_area.index(p);
				content_t c = vm->m_data[i].getContent();
				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) {
						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 {
					if (c == CONTENT_IGNORE || c == CONTENT_AIR)
						continue;

					vm->m_data[i] = airnode;
					vm->m_flags[i] |= VMANIP_FLAG_CAVE;
				}
			}
		}
	}
}
Beispiel #2
0
void CaveFractal::carveRoute(v3f vec, float f, bool randomize_xz) 
{
	MapNode airnode(CONTENT_AIR);
	MapNode waternode(c_water_source);
	MapNode lavanode(c_lava_source);

	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 && node_max.Y < MGFRACTAL_LAVA_DEPTH) ?
		lavanode : waternode;

	v3f fp = orp + vec * f;
	fp.X += 0.1 * ps->range(-10, 10);
	fp.Z += 0.1 * ps->range(-10, 10);
	v3s16 cp(fp.X, fp.Y, fp.Z);

	s16 d0 = -rs/2;
	s16 d1 = d0 + rs;
	if (randomize_xz) {
		d0 += ps->range(-1, 1);
		d1 += ps->range(-1, 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);

			for (s16 y0 = -si2; y0 <= si2; y0++) {
				if (large_cave_is_flat) {
					// Make large caves not so tall
					if (rs > 7 && abs(y0) >= rs / 3)
						continue;
				}

				v3s16 p(cp.X + x0, cp.Y + y0, cp.Z + z0);
				p += of;

				if (vm->m_area.contains(p) == false)
					continue;

				u32 i = vm->m_area.index(p);
				content_t c = vm->m_data[i].getContent();
				if (!ndef->get(c).is_ground_content)
					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;
			}
		}
	}
}
Beispiel #3
0
void CaveV5::carveRoute(v3f vec, float f, bool randomize_xz) 
{
	MapNode airnode(CONTENT_AIR);
	MapNode waternode(c_water_source);
	MapNode lavanode(c_lava_source);
	MapNode n_ice(c_ice);

	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);
	v3s16 cp(fp.X, fp.Y, fp.Z);

	s16 d0 = -rs/2;
	s16 d1 = d0 + rs;
	if (randomize_xz) {
		d0 += ps->range(-1, 1);
		d1 += ps->range(-1, 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);

			for (s16 y0 = -si2; y0 <= si2; y0++) {
				if (large_cave_is_flat) {
					// Make large caves not so tall
					if (rs > 7 && abs(y0) >= rs / 3)
						continue;
				}

				v3s16 p(cp.X + x0, cp.Y + y0, cp.Z + z0);
				p += of;

				if (vm->m_area.contains(p) == false)
					continue;

				u32 i = vm->m_area.index(p);
				content_t c = vm->m_data[i].getContent();
				if (!ndef->get(c).is_ground_content)
					continue;

				s16 heat = mg->m_emerge->env->m_use_weather ? mg->m_emerge->env->getServerMap().updateBlockHeat(mg->m_emerge->env, p, nullptr, &mg->heat_cache) : 0;
				MapNode n_water_or_ice = (heat < 0 && (p.Y > water_level + heat/4 || p.Y > startp.Y - 2 + heat/4)) ? n_ice : waternode;
				MapNode liquidnode = nval < 0.40 ? lavanode : n_water_or_ice;

				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) ?
						n_water_or_ice : 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;
			}
		}
	}
}
Beispiel #4
0
void CavesV6::carveRoute(v3f vec, float f, bool randomize_xz,
	bool tunnel_above_ground)
{
	MapNode airnode(CONTENT_AIR);
	MapNode waternode(c_water_source);
	MapNode lavanode(c_lava_source);
	MapNode n_ice(c_ice);
	bool flooded = ps->range(1, 2) == 2;

	v3s16 startp(orp.X, orp.Y, orp.Z);
	startp += of;

	v3f fp = orp + vec * f;
	fp.X += 0.1f * ps->range(-10, 10);
	fp.Z += 0.1f * ps->range(-10, 10);
	v3s16 cp(fp.X, fp.Y, fp.Z);

	s16 d0 = -rs / 2;
	s16 d1 = d0 + rs;
	if (randomize_xz) {
		d0 += ps->range(-1, 1);
		d1 += ps->range(-1, 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++) {
			if (tunnel_above_ground)
				continue;

			s16 maxabsxz = MYMAX(abs(x0), abs(z0));
			s16 si2 = rs / 2 - MYMAX(0, maxabsxz - rs / 7 - 1);

			//fmtodomerge: s16 heat = mg->m_emerge->env->m_use_weather ? mg->m_emerge->env->getServerMap().updateBlockHeat(mg->m_emerge->env, v3POS(cp.X + x0, cp.Y + -si2, cp.Z + z0), nullptr, &mg->heat_cache) : 0;
			s16 heat = 10;

			for (s16 y0 = -si2; y0 <= si2; y0++) {
				if (large_cave_is_flat) {
					// Make large caves not so tall
					if (rs > 7 && abs(y0) >= rs / 3)
						continue;
				}

				v3s16 p(cp.X + x0, cp.Y + y0, cp.Z + z0);
				p += of;

				if (vm->m_area.contains(p) == false)
					continue;

				u32 i = vm->m_area.index(p);
				content_t c = vm->m_data[i].getContent();
				if (!c || c == CONTENT_AIR || !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;

					bool protect_huge = vm->m_flags[i] & VOXELFLAG_CHECKED2;

					if (flooded && full_ymin < water_level && full_ymax > water_level) {
						if (!protect_huge) {
							MapNode n_water_or_ice = (heat < 0 && (p.Y > water_level + heat/4 || p.Y > startp.Y - 2 + heat/4)) ? n_ice : waternode;
							vm->m_data[i] = (p.Y <= water_level) ? n_water_or_ice : airnode;
						}
					} else if (flooded && full_ymax < water_level) {
						if (!protect_huge)
						vm->m_data[i] = (p.Y < startp.Y - 2) ? lavanode : airnode;
					} else {
						vm->m_data[i] = airnode;
					}
				} else {
/*
					if (c == CONTENT_IGNORE || c == CONTENT_AIR)
						continue;
*/

					vm->m_data[i] = airnode;
					vm->m_flags[i] |= VMANIP_FLAG_CAVE;
				}
			}
		}
	}
}
Beispiel #5
0
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);
	MapNode liquidnode = ps->range(0, 4) ? lavanode : waternode;
	
	v3s16 startp(orp.X, orp.Y, orp.Z);
	startp += of;
	
	v3f fp = orp + vec * f;
	fp.X += 0.1 * ps->range(-10, 10);
	fp.Z += 0.1 * ps->range(-10, 10);
	v3s16 cp(fp.X, fp.Y, fp.Z);

	s16 d0 = -rs/2;
	s16 d1 = d0 + rs;
	if (randomize_xz) {
		d0 += ps->range(-1, 1);
		d1 += ps->range(-1, 1);
	}
	
	bool flat_cave_floor = !large_cave && ps->range(0, 2) == 2;
	
	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);
			
			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)
						continue;
				}

				v3s16 p(cp.X + x0, cp.Y + y0, cp.Z + z0);
				p += of;

				if (vm->m_area.contains(p) == false)
					continue;

				u32 i = vm->m_area.index(p);
				
				// Don't replace air or water or lava
				content_t c = vm->m_data[i].getContent();
				if (c == CONTENT_AIR || c == c_water_source || c == c_lava_source)
					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 - 4) ? liquidnode : airnode;
					else
						vm->m_data[i] = airnode;
				} else {
					vm->m_data[i] = airnode;
					vm->m_flags[i] |= VMANIP_FLAG_CAVE;
				}
			}
		}
	}
}
Beispiel #6
0
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);

	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 && node_max.Y < -256) ? lavanode : waternode;

	v3f fp = orp + vec * f;
	fp.X += 0.1 * ps->range(-10, 10);
	fp.Z += 0.1 * ps->range(-10, 10);
	v3s16 cp(fp.X, fp.Y, fp.Z);

	s16 d0 = -rs/2;
	s16 d1 = d0 + rs;
	if (randomize_xz) {
		d0 += ps->range(-1, 1);
		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 = 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
					if (rs > 7 && abs(y0) >= rs / 3)
						continue;
				}

				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);
				content_t c = vm->m_data[i].getContent();
				if (!ndef->get(c).is_ground_content)
					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;
			}
		}
	}
}
Beispiel #7
0
void MapgenV6::generateCaves(int max_stone_y) {
	// 24ms @cs=8
	//TimeTaker timer1("caves");
	
	/*double cave_amount = 6.0 + 6.0 * noise2d_perlin(
		0.5+(double)node_min.X/250, 0.5+(double)node_min.Y/250,
		data->seed+34329, 3, 0.50);*/
	const s16 max_spread_amount = MAP_BLOCKSIZE;
	float cave_amount = NoisePerlin2D(np_cave, node_min.X, node_min.Y, seed);

	cave_amount = MYMAX(0.0, cave_amount);
	u32 caves_count = cave_amount * volume_nodes / 50000;
	u32 bruises_count = 1;
	PseudoRandom ps(blockseed + 21343);
	PseudoRandom ps2(blockseed + 1032);
	
	if (ps.range(1, 6) == 1)
		bruises_count = ps.range(0, ps.range(0, 2));
	
	if (getBiome(v2s16(node_min.X, node_min.Z)) == BT_DESERT) {
		caves_count   /= 3;
		bruises_count /= 3;
	}
	
	for(u32 jj = 0; jj < caves_count + bruises_count; jj++) {
		/*int avg_height = (int)
			  ((base_rock_level_2d(data->seed, v2s16(node_min.X, node_min.Z)) +
				base_rock_level_2d(data->seed, v2s16(node_max.X, node_max.Z))) / 2);
		if ((node_max.Y + node_min.Y) / 2 > avg_height)
			break;*/

		bool large_cave = (jj >= caves_count);

		Cave cave;
		defineCave(cave, ps, node_min, large_cave);

		v3f main_direction(0,0,0);

		// Allowed route area size in nodes
		v3s16 ar = central_area_size;

		// Area starting point in nodes
		v3s16 of = node_min;

		// Allow a bit more
		//(this should be more than the maximum radius of the tunnel)
		s16 insure = 10;
		s16 more = max_spread_amount - cave.max_tunnel_diameter / 2 - insure;
		ar += v3s16(1,0,1) * more * 2;
		of -= v3s16(1,0,1) * more;

		s16 route_y_min = 0;
		// Allow half a diameter + 7 over stone surface
		s16 route_y_max = -of.Y + max_stone_y + cave.max_tunnel_diameter/2 + 7;

		// Limit maximum to area
		route_y_max = rangelim(route_y_max, 0, ar.Y-1);

		if(large_cave)
		{
			s16 min = 0;
			if(node_min.Y < water_level && node_max.Y > water_level)
			{
				min = water_level - cave.max_tunnel_diameter/3 - of.Y;
				route_y_max = water_level + cave.max_tunnel_diameter/3 - of.Y;
			}
			route_y_min = ps.range(min, min + cave.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);

		// Randomize starting position
		v3f orp(
			(float)(ps.next()%ar.X)+0.5,
			(float)(ps.range(route_start_y_min, route_start_y_max))+0.5,
			(float)(ps.next()%ar.Z)+0.5
		);

		v3s16 startp(orp.X, orp.Y, orp.Z);
		startp += of;

		MapNode airnode(CONTENT_AIR);
		MapNode waternode(c_water_source);
		MapNode lavanode(c_lava_source);

		/*
			Generate some tunnel starting from orp
		*/

		for(u16 j=0; j<cave.tunnel_routepoints; j++)
		{
			if(j%cave.dswitchint==0 && large_cave == false)
			{
				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;
			}

			// Randomize size
			s16 min_d = cave.min_tunnel_diameter;
			s16 max_d = cave.max_tunnel_diameter;
			s16 rs = ps.range(min_d, max_d);

			// Every second section is rough
			bool randomize_xz = (ps2.range(1,2) == 1);

			v3s16 maxlen;
			if(large_cave)
			{
				maxlen = v3s16(
					rs*cave.part_max_length_rs,
					rs*cave.part_max_length_rs/2,
					rs*cave.part_max_length_rs
				);
			}
			else
			{
				maxlen = v3s16(
					rs*cave.part_max_length_rs,
					ps.range(1, rs*cave.part_max_length_rs),
					rs*cave.part_max_length_rs
				);
			}

			v3f vec;

			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
			);

			// 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*2/2,
					(float)(ps.next()%(maxlen.Z*1))-(float)maxlen.Z/2
				);
			}

			/*if(large_cave){
				v3f p = orp + vec;
				s16 h = find_ground_level_clever(vmanip,
						v2s16(p.X, p.Z), ndef);
				route_y_min = h - rs/3;
				route_y_max = h + rs;
			}*/

			vec += main_direction;

			v3f rp = orp + vec;
			if(rp.X < 0)
				rp.X = 0;
			else if(rp.X >= ar.X)
				rp.X = ar.X-1;
			if(rp.Y < route_y_min)
				rp.Y = route_y_min;
			else if(rp.Y >= route_y_max)
				rp.Y = route_y_max-1;
			if(rp.Z < 0)
				rp.Z = 0;
			else if(rp.Z >= ar.Z)
				rp.Z = ar.Z-1;
			vec = rp - orp;

			for(float f=0; f<1.0; f+=1.0/vec.getLength())
			{
				v3f fp = orp + vec * f;
				fp.X += 0.1*ps.range(-10,10);
				fp.Z += 0.1*ps.range(-10,10);
				v3s16 cp(fp.X, fp.Y, fp.Z);

				s16 d0 = -rs/2;
				s16 d1 = d0 + rs;
				if(randomize_xz){
					d0 += ps.range(-1,1);
					d1 += ps.range(-1,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);
						for(s16 y0=-si2; y0<=si2; y0++)
						{
							/*// Make better floors in small caves
							if(y0 <= -rs/2 && rs<=7)
								continue;*/
							if (cave.large_cave_is_flat) {
								// Make large caves not so tall
								if (rs > 7 && abs(y0) >= rs/3)
									continue;
							}

							s16 z = cp.Z + z0;
							s16 y = cp.Y + y0;
							s16 x = cp.X + x0;
							v3s16 p(x,y,z);
							p += of;

							if(vm->m_area.contains(p) == false)
								continue;

							u32 i = vm->m_area.index(p);

							if(large_cave) {
								if (cave.flooded && full_node_min.Y < water_level &&
									full_node_max.Y > water_level) {
									if (p.Y <= water_level)
										vm->m_data[i] = waternode;
									else
										vm->m_data[i] = airnode;
								} else if (cave.flooded && full_node_max.Y < water_level) {
									if (p.Y < startp.Y - 2)
										vm->m_data[i] = lavanode;
									else
										vm->m_data[i] = airnode;
								} else {
									vm->m_data[i] = airnode;
								}
							} else {
								// Don't replace air or water or lava or ignore
								if (vm->m_data[i].getContent() == CONTENT_IGNORE ||
									vm->m_data[i].getContent() == CONTENT_AIR ||
									vm->m_data[i].getContent() == c_water_source ||
									vm->m_data[i].getContent() == c_lava_source)
									continue;

								vm->m_data[i] = airnode;

								// Set tunnel flag
								vm->m_flags[i] |= VMANIP_FLAG_CAVE;
							}
						}
					}
				}
			}
			orp = rp;
		}
	}
}