aboutsummaryrefslogtreecommitdiff
path: root/games/minimal/mods/default/textures/default_mineral_iron.png
blob: 6c894ce1ce524a93dfb4a7ef48e1b4eb9b83f25e (plain)
ofshex dumpascii
0000 89 50 4e 47 0d 0a 1a 0a 00 00 00 0d 49 48 44 52 00 00 00 10 00 00 00 10 08 03 00 00 00 28 2d 0f .PNG........IHDR.............(-.
0020 53 00 00 01 ce 50 4c 54 45 24 24 24 2d 41 37 30 31 2c 31 3e 42 34 44 3b 37 34 31 3a 3b 36 3a 3e S....PLTE$$$-A701,1>B4D;741:;6:>
0040 39 3b 41 3b 3e 42 37 3e 4b 45 3f 4b 48 40 3e 37 42 49 47 42 51 4f 44 45 41 44 4f 4f 45 47 45 46 9;A;>B7>KE?KH@>7BIGBQODEADOOEGEF
0060 4d 49 47 4f 46 47 50 4d 48 4b 45 48 4e 48 48 52 48 49 50 4c 4c 4f 4f 4c 51 4e 4d 4d 47 4e 4e 4c MIGOFGPMHKEHNHHRHIPLLOOLQNMMGNNL
0080 4e 4e 4e 4f 48 42 4f 50 4c 4f 53 4e 4f 59 52 4f 59 53 51 52 4d 51 59 52 52 52 52 52 54 50 52 60 NNNOHBOPLOSNOYROYSQRMQYRRRRRTPR`
00a0 5b 53 5f 5c 55 59 53 55 5e 5e 55 60 60 56 4c 48 56 56 52 56 57 53 56 57 55 56 5b 58 56 5d 5c 57 [S_\UYSU^^U``VLHVVRVWSVWUV[XV]\W
00c0 60 5b 58 59 54 58 5b 5a 59 5b 5f 5a 5f 5c 5b 62 5e 5c 5c 56 5c 60 5f 5c 61 5e 5d 5c 59 5d 5f 5b `[XYTX[ZY[_Z_\[b^\\V\`_\a^]\Y]_[
00e0 5f 5f 5f 5f 63 60 60 5c 59 60 61 60 60 64 61 61 65 62 61 67 5f 61 6c 6c 62 63 5b 62 63 63 62 66 ____c``\Y`a``daaebag_allbc[bccbf
0100 65 63 63 61 63 63 65 63 67 64 64 61 5f 65 64 61 66 65 66 66 67 63 66 67 6a 66 70 6e 67 67 67 69 eccaccecgdda_edafeffgcfgjfpngggi
0120 69 67 69 6a 62 69 6c 6b 69 6e 69 6a 62 60 6a 64 62 6a 69 65 6a 69 67 6a 6b 66 6a 6f 6f 6b 6f 6a igijbilkinijb`jdbjiejigjkfjookoj
0140 6b 70 6a 6b 70 6d 6c 6b 67 6d 6d 6d 6d 6d 6e 6d 6d 6f 6e 6e 66 6e 6f 70 6e 73 73 6f 73 70 6f 77 kpjkpmlkgmmmmmnmmonnfnopnssospow
0160 7a 70 6d 6c 70 71 6f 70 72 70 71 74 6e 71 7a 77 72 6f 6d 73 74 70 73 77 74 74 75 6f 74 77 77 74 zpmlpqoprpqtnqzwromstpswttuotwwt
0180 7b 7a 75 7c 7b 77 74 70 77 77 73 77 7e 7a 77 7f 80 78 79 7c 78 7c 7e 78 7f 7d 7a 7b 79 7a 7c 7a {zu|{wtpwwsw~zw..xy|x|~x.}z{yz|z
01a0 7a 7c 81 7a 7e 7e 7a 7f 7a 7a 83 80 7b 74 73 7d 7e 7a 7e 7e 7e 81 83 7f 83 84 80 84 81 7c 84 85 z|.z~~z.zz..{ts}~z~~~........|..
01c0 87 84 86 84 84 88 84 85 83 7f 87 88 88 8b 8b 8a 8c 89 87 90 8d 8b 9a 97 96 9c 98 9b 9e 9a 98 53 ...............................S
01e0 55 54 59 5c 59 5e 62 5d 74 6e 6d 81 81 7e 92 49 24 93 92 8f b6 6d 49 f3 37 b9 7b 00 00 00 92 74 UTY\Y^b]tnm..~.I$....mI.7.{....t
0200 52 4e 53 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 RNS.............................
0220 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................................
0240 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................................
0260 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................................
0280 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 2a fe af 3e 00 00 00 e9 49 44 41 .....................*..>....IDA
02a0 54 18 19 2d c1 03 43 03 50 18 05 d0 2f db 2d 2d db be b5 6c 6b d9 76 cb b6 6d df de bf ed 85 73 T..-..C.P.../.--...lk.v..m.....s
02c0 64 15 3f fa 13 e3 5b 06 2b 02 01 88 df 41 e5 36 89 dc 3c 47 67 2b d8 45 a5 89 77 71 4f 7b 82 ff d.?...[.+....A.6..<Gg+.E..wqO{..
02e0 1a 40 62 26 d8 a9 4b 22 a2 3d 0a 8d 39 d3 54 80 22 47 5c 25 ff 8d e4 e7 56 07 10 90 da 7c 62 4a .@b&..K".=..9.T."G\%....V....|bJ
0300 92 38 00 8a 28 45 9d 6f 6d 86 43 6c af 6c 5e 9c 3e 87 da b8 43 23 5d ec dd 64 fc 9a 7f 94 46 8a .8..(E.om.Cl.l^.>...C#]..d....F.
0320 84 ef 4d 3d 2a ed 78 bf bc de 50 86 48 69 7b ff 08 b2 35 66 2d 1f de 57 cd 4d 1c 2d 9d c9 15 b5 ..M=*.x...P.Hi{...5f-..W.M.-....
0340 ee 9a 9b 5b 42 7b 0d 93 f3 cb 8d 94 97 02 92 4a 29 02 e9 b2 68 19 de 35 67 3f 0c 98 3d 4d 86 bb ...[B{.........J)...h..5g?..=M..
0360 22 24 4b 89 0f 49 fc eb fb 0a 91 f5 05 cb ec 28 7e 91 c4 98 c4 58 37 3c b5 7a ad 34 56 4f 66 ce "$K..I.........(~....X7<.z.4VOf.
0380 0f 35 75 ee 7c 03 8f b5 56 1a 05 be c6 55 00 00 00 00 49 45 4e 44 ae 42 60 82 .5u.|...V....U....IEND.B`.
ef='#n220'>220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 448 449 450 451 452 453 454 455 456 457 458 459 460 461 462 463 464 465 466 467 468 469 470 471 472 473 474 475 476 477 478 479 480 481 482 483 484 485 486 487 488 489 490 491 492 493 494 495 496 497 498 499 500 501 502 503 504 505 506 507 508 509 510 511 512 513 514 515 516 517 518 519 520 521 522 523 524 525 526 527 528 529 530 531 532 533 534 535 536 537 538 539 540 541 542 543 544 545 546 547 548 549 550 551 552 553 554 555 556 557 558 559 560 561 562 563 564 565 566 567 568 569 570 571 572 573 574 575 576 577 578 579 580 581 582 583 584 585 586 587 588 589 590 591 592 593 594 595 596 597 598 599 600 601 602 603 604 605 606 607 608 609 610 611 612 613 614 615 616 617 618 619 620 621 622 623 624 625 626 627 628 629 630 631 632 633 634 635 636 637 638 639 640 641 642 643 644 645 646 647 648 649 650 651 652 653 654 655 656 657 658 659 660 661 662 663 664 665 666 667 668 669 670 671 672 673 674 675 676 677 678 679 680 681 682 683 684 685 686 687 688 689 690 691 692 693 694 695 696 697 698 699 700 701 702 703 704 705 706 707 708 709 710 711 712 713 714 715 716 717 718 719 720 721 722 723 724 725 726 727 728 729 730 731 732 733 734 735 736 737 738 739 740 741 742 743 744 745 746 747 748 749 750 751 752 753 754 755 756 757 758 759 760 761 762 763 764 765 766 767 768 769 770 771 772 773 774 775 776 777 778 779 780 781 782 783 784 785 786 787 788 789 790 791 792 793 794 795 796 797 798 799 800 801 802 803 804 805 806 807 808 809 810 811 812 813 814 815 816 817 818 819 820 821 822 823 824 825 826 827 828 829 830 831 832 833 834 835 836 837 838 839 840 841 842 843 844 845 846 847 848 849 850 851 852 853 854 855 856 857 858 859 860 861 862 863 864 865 866 867 868 869 870 871 872 873 874 875 876 877 878 879 880 881 882 883 884
/*
Minetest
Copyright (C) 2010-2018 celeron55, Perttu Ahola <celeron55@gmail.com>
Copyright (C) 2010-2018 kwolekr, Ryan Kwolek <kwolekr@minetest.net>
Copyright (C) 2015-2018 paramat

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 "util/numeric.h"
#include "map.h"
#include "mapgen.h"
#include "mapgen_v5.h"
#include "mapgen_v6.h"
#include "mapgen_v7.h"
#include "mg_biome.h"
#include "cavegen.h"

static NoiseParams nparams_caveliquids(0, 1, v3f(150.0, 150.0, 150.0), 776, 3, 0.6, 2.0);


////
//// CavesNoiseIntersection
////

CavesNoiseIntersection::CavesNoiseIntersection(
	INodeDefManager *nodedef, BiomeManager *biomemgr, v3s16 chunksize,
	NoiseParams *np_cave1, NoiseParams *np_cave2, s32 seed, float cave_width)
{
	assert(nodedef);
	assert(biomemgr);

	m_ndef = nodedef;
	m_bmgr = biomemgr;

	m_csize = chunksize;
	m_cave_width = cave_width;

	m_ystride    = m_csize.X;
	m_zstride_1d = m_csize.X * (m_csize.Y + 1);

	// Noises are created using 1-down overgeneration
	// A Nx-by-1-by-Nz-sized plane is at the bottom of the desired for
	// re-carving the solid overtop placed for blocking sunlight
	noise_cave1 = new Noise(np_cave1, seed, m_csize.X, m_csize.Y + 1, m_csize.Z);
	noise_cave2 = new Noise(np_cave2, seed, m_csize.X, m_csize.Y + 1, m_csize.Z);
}


CavesNoiseIntersection::~CavesNoiseIntersection()
{
	delete noise_cave1;
	delete noise_cave2;
}


void CavesNoiseIntersection::generateCaves(MMVManip *vm,
	v3s16 nmin, v3s16 nmax, u8 *biomemap)
{
	assert(vm);
	assert(biomemap);

	noise_cave1->perlinMap3D(nmin.X, nmin.Y - 1, nmin.Z);
	noise_cave2->perlinMap3D(nmin.X, nmin.Y - 1, nmin.Z);

	const v3s16 &em = vm->m_area.getExtent();
	u32 index2d = 0;  // Biomemap index

	for (s16 z = nmin.Z; z <= nmax.Z; z++)
	for (s16 x = nmin.X; x <= nmax.X; x++, index2d++) {
		bool column_is_open = false;  // Is column open to overground
		bool is_under_river = false;  // Is column under river water
		bool is_under_tunnel = false;  // Is tunnel or is under tunnel
		bool is_top_filler_above = false;  // Is top or filler above node
		// Indexes at column top
		u32 vi = vm->m_area.index(x, nmax.Y, z);
		u32 index3d = (z - nmin.Z) * m_zstride_1d + m_csize.Y * m_ystride +
			(x - nmin.X);  // 3D noise index
		// Biome of column
		Biome *biome = (Biome *)m_bmgr->getRaw(biomemap[index2d]);
		u16 depth_top = biome->depth_top;
		u16 base_filler = depth_top + biome->depth_filler;
		u16 depth_riverbed = biome->depth_riverbed;
		u16 nplaced = 0;
		// Don't excavate the overgenerated stone at nmax.Y + 1,
		// this creates a 'roof' over the tunnel, preventing light in
		// tunnels at mapchunk borders when generating mapchunks upwards.
		// This 'roof' is removed when the mapchunk above is generated.
		for (s16 y = nmax.Y; y >= nmin.Y - 1; y--,
				index3d -= m_ystride,
				vm->m_area.add_y(em, vi, -1)) {
			content_t c = vm->m_data[vi].getContent();

			if (c == CONTENT_AIR || c == biome->c_water_top ||
					c == biome->c_water) {
				column_is_open = true;
				is_top_filler_above = false;
				continue;
			}

			if (c == biome->c_river_water) {
				column_is_open = true;
				is_under_river = true;
				is_top_filler_above = false;
				continue;
			}

			// Ground
			float d1 = contour(noise_cave1->result[index3d]);
			float d2 = contour(noise_cave2->result[index3d]);

			if (d1 * d2 > m_cave_width && m_ndef->get(c).is_ground_content) {
				// In tunnel and ground content, excavate
				vm->m_data[vi] = MapNode(CONTENT_AIR);
				is_under_tunnel = true;
				// If tunnel roof is top or filler, replace with stone
				if (is_top_filler_above)
					vm->m_data[vi + em.X] = MapNode(biome->c_stone);
				is_top_filler_above = false;
			} else if (column_is_open && is_under_tunnel &&
					(c == biome->c_stone || c == biome->c_filler)) {
				// Tunnel entrance floor, place biome surface nodes
				if (is_under_river) {
					if (nplaced < depth_riverbed) {
						vm->m_data[vi] = MapNode(biome->c_riverbed);
						is_top_filler_above = true;
						nplaced++;
					} else {
						// Disable top/filler placement
						column_is_open = false;
						is_under_river = false;
						is_under_tunnel = false;
					}
				} else if (nplaced < depth_top) {
					vm->m_data[vi] = MapNode(biome->c_top);
					is_top_filler_above = true;
					nplaced++;
				} else if (nplaced < base_filler) {
					vm->m_data[vi] = MapNode(biome->c_filler);
					is_top_filler_above = true;
					nplaced++;
				} else {
					// Disable top/filler placement
					column_is_open = false;
					is_under_tunnel = false;
				}
			} else {
				// Not tunnel or tunnel entrance floor
				// Check node for possible replacing with stone for tunnel roof
				if (c == biome->c_top || c == biome->c_filler)
					is_top_filler_above = true;

				column_is_open = false;
			}
		}
	}
}


////
//// CavernsNoise
////

CavernsNoise::CavernsNoise(
	INodeDefManager *nodedef, v3s16 chunksize, NoiseParams *np_cavern,
	s32 seed, float cavern_limit, float cavern_taper, float cavern_threshold)
{
	assert(nodedef);

	m_ndef  = nodedef;

	m_csize            = chunksize;
	m_cavern_limit     = cavern_limit;
	m_cavern_taper     = cavern_taper;
	m_cavern_threshold = cavern_threshold;

	m_ystride = m_csize.X;
	m_zstride_1d = m_csize.X * (m_csize.Y + 1);

	// Noise is created using 1-down overgeneration
	// A Nx-by-1-by-Nz-sized plane is at the bottom of the desired for
	// re-carving the solid overtop placed for blocking sunlight
	noise_cavern = new Noise(np_cavern, seed, m_csize.X, m_csize.Y + 1, m_csize.Z);

	c_water_source = m_ndef->getId("mapgen_water_source");
	if (c_water_source == CONTENT_IGNORE)
		c_water_source = CONTENT_AIR;

	c_lava_source = m_ndef->getId("mapgen_lava_source");
	if (c_lava_source == CONTENT_IGNORE)
		c_lava_source = CONTENT_AIR;
}


CavernsNoise::~CavernsNoise()
{
	delete noise_cavern;
}


bool CavernsNoise::generateCaverns(MMVManip *vm, v3s16 nmin, v3s16 nmax)
{
	assert(vm);

	// Calculate noise
	noise_cavern->perlinMap3D(nmin.X, nmin.Y - 1, nmin.Z);

	// Cache cavern_amp values
	float *cavern_amp = new float[m_csize.Y + 1];
	u8 cavern_amp_index = 0;  // Index zero at column top
	for (s16 y = nmax.Y; y >= nmin.Y - 1; y--, cavern_amp_index++) {
		cavern_amp[cavern_amp_index] =
			MYMIN((m_cavern_limit - y) / (float)m_cavern_taper, 1.0f);
	}

	//// Place nodes
	bool near_cavern = false;
	const v3s16 &em = vm->m_area.getExtent();
	u32 index2d = 0;

	for (s16 z = nmin.Z; z <= nmax.Z; z++)
	for (s16 x = nmin.X; x <= nmax.X; x++, index2d++) {
		// Reset cave_amp index to column top
		cavern_amp_index = 0;
		// Initial voxelmanip index at column top
		u32 vi = vm->m_area.index(x, nmax.Y, z);
		// Initial 3D noise index at column top
		u32 index3d = (z - nmin.Z) * m_zstride_1d + m_csize.Y * m_ystride +
			(x - nmin.X);
		// Don't excavate the overgenerated stone at node_max.Y + 1,
		// this creates a 'roof' over the cavern, preventing light in
		// caverns at mapchunk borders when generating mapchunks upwards.
		// This 'roof' is excavated when the mapchunk above is generated.
		for (s16 y = nmax.Y; y >= nmin.Y - 1; y--,
				index3d -= m_ystride,
				vm->m_area.add_y(em, vi, -1),
				cavern_amp_index++) {
			content_t c = vm->m_data[vi].getContent();
			float n_absamp_cavern = fabs(noise_cavern->result[index3d]) *
				cavern_amp[cavern_amp_index];
			// Disable CavesRandomWalk at a safe distance from caverns
			// to avoid excessively spreading liquids in caverns.
			if (n_absamp_cavern > m_cavern_threshold - 0.1f) {
				near_cavern = true;
				if (n_absamp_cavern > m_cavern_threshold &&
						m_ndef->get(c).is_ground_content)
					vm->m_data[vi] = MapNode(CONTENT_AIR);
			}
		}
	}

	delete[] cavern_amp;

	return near_cavern;
}


////
//// CavesRandomWalk
////

CavesRandomWalk::CavesRandomWalk(
	INodeDefManager *ndef,
	GenerateNotifier *gennotify,
	s32 seed,
	int water_level,
	content_t water_source,
	content_t lava_source,
	int lava_depth)
{
	assert(ndef);

	this->ndef           = ndef;
	this->gennotify      = gennotify;
	this->seed           = seed;
	this->water_level    = water_level;
	this->np_caveliquids = &nparams_caveliquids;
	this->lava_depth     = lava_depth;

	c_water_source = water_source;
	if (c_water_source == CONTENT_IGNORE)
		c_water_source = ndef->getId("mapgen_water_source");
	if (c_water_source == CONTENT_IGNORE)
		c_water_source = CONTENT_AIR;

	c_lava_source = lava_source;
	if (c_lava_source == CONTENT_IGNORE)
		c_lava_source = ndef->getId("mapgen_lava_source");
	if (c_lava_source == CONTENT_IGNORE)
		c_lava_source = CONTENT_AIR;
}


void CavesRandomWalk::makeCave(MMVManip *vm, v3s16 nmin, v3s16 nmax,
	PseudoRandom *ps, bool is_large_cave, int max_stone_height, s16 *heightmap)
{
	assert(vm);
	assert(ps);

	this->vm         = vm;
	this->ps         = ps;
	this->node_min   = nmin;
	this->node_max   = nmax;
	this->heightmap  = heightmap;
	this->large_cave = is_large_cave;

	this->ystride = nmax.X - nmin.X + 1;

	// Set initial parameters from randomness
	int dswitchint = ps->range(1, 14);
	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));
		min_tunnel_diameter = 2;
		max_tunnel_diameter = ps->range(2, 6);
	}

	large_cave_is_flat = (ps->range(0, 1) == 0);

	main_direction = v3f(0, 0, 0);

	// Allowed route area size in nodes
	ar = node_max - node_min + v3s16(1, 1, 1);
	// Area starting point in nodes
	of = node_min;

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

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

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

	if (large_cave) {
		s16 minpos = 0;
		if (node_min.Y < water_level && node_max.Y > water_level) {
			minpos = water_level - max_tunnel_diameter / 3 - of.Y;
			route_y_max = water_level + max_tunnel_diameter / 3 - of.Y;
		}
		route_y_min = ps->range(minpos, minpos + 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
	orp.Z = (float)(ps->next() % ar.Z) + 0.5f;
	orp.Y = (float)(ps->range(route_start_y_min, route_start_y_max)) + 0.5f;
	orp.X = (float)(ps->next() % ar.X) + 0.5f;

	// Add generation notify begin event
	if (gennotify) {
		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;
		gennotify->addEvent(notifytype, abs_pos);
	}

	// Generate some tunnel starting from orp
	for (u16 j = 0; j < tunnel_routepoints; j++)
		makeTunnel(j % dswitchint == 0);

	// Add generation notify end event
	if (gennotify) {
		v3s16 abs_pos(of.X + orp.X, of.Y + orp.Y, of.Z + orp.Z);
		GenNotifyType notifytype = large_cave ?
			GENNOTIFY_LARGECAVE_END : GENNOTIFY_CAVE_END;
		gennotify->addEvent(notifytype, abs_pos);
	}
}


void CavesRandomWalk::makeTunnel(bool dirswitch)
{
	if (dirswitch && !large_cave) {
		main_direction.Z = ((float)(ps->next() % 20) - (float)10) / 10;
		main_direction.Y = ((float)(ps->next() % 20) - (float)10) / 30;
		main_direction.X = ((float)(ps->next() % 20) - (float)10) / 10;

		main_direction *= (float)ps->range(0, 10) / 10;
	}

	// 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;
	// Jump downward sometimes
	if (!large_cave && ps->range(0, 12) == 0) {
		vec.Z = (float)(ps->next() % (maxlen.Z * 1)) - (float)maxlen.Z / 2;
		vec.Y = (float)(ps->next() % (maxlen.Y * 2)) - (float)maxlen.Y;
		vec.X = (float)(ps->next() % (maxlen.X * 1)) - (float)maxlen.X / 2;
	} else {