3 Copyright (C) 2010-2013 celeron55, Perttu Ahola <celeron55@gmail.com>
5 This program is free software; you can redistribute it and/or modify
6 it under the terms of the GNU Lesser General Public License as published by
7 the Free Software Foundation; either version 2.1 of the License, or
8 (at your option) any later version.
10 This program is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 GNU Lesser General Public License for more details.
15 You should have received a copy of the GNU Lesser General Public License along
16 with this program; if not, write to the Free Software Foundation, Inc.,
17 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
20 #include "util/numeric.h"
23 #include "mapgen_v5.h"
24 #include "mapgen_v6.h"
25 #include "mapgen_v7.h"
28 NoiseParams nparams_caveliquids(0, 1, v3f(150.0, 150.0, 150.0), 776, 3, 0.6, 2.0);
31 ///////////////////////////////////////// Caves V5
34 CaveV5::CaveV5(MapgenV5 *mg, PseudoRandom *ps)
38 this->ndef = mg->ndef;
39 this->water_level = mg->water_level;
41 this->c_water_source = mg->c_water_source;
42 this->c_lava_source = mg->c_lava_source;
43 this->c_ice = mg->c_ice;
44 this->np_caveliquids = &nparams_caveliquids;
46 dswitchint = ps->range(1, 14);
47 flooded = ps->range(1, 2) == 2;
49 part_max_length_rs = ps->range(2, 4);
50 tunnel_routepoints = ps->range(5, ps->range(15, 30));
51 min_tunnel_diameter = 5;
52 max_tunnel_diameter = ps->range(7, ps->range(8, 24));
54 large_cave_is_flat = (ps->range(0, 1) == 0);
58 void CaveV5::makeCave(v3s16 nmin, v3s16 nmax, int max_stone_height)
62 main_direction = v3f(0, 0, 0);
64 // Allowed route area size in nodes
65 ar = node_max - node_min + v3s16(1, 1, 1);
66 // Area starting point in nodes
70 //(this should be more than the maximum radius of the tunnel)
72 s16 more = MYMAX(MAP_BLOCKSIZE - max_tunnel_diameter / 2 - insure, 1);
73 ar += v3s16(1,0,1) * more * 2;
74 of -= v3s16(1,0,1) * more;
77 // Allow half a diameter + 7 over stone surface
78 route_y_max = -of.Y + max_stone_y + max_tunnel_diameter / 2 + 7;
80 // Limit maximum to area
81 route_y_max = rangelim(route_y_max, 0, ar.Y - 1);
84 if (node_min.Y < water_level && node_max.Y > water_level) {
85 min = water_level - max_tunnel_diameter/3 - of.Y;
86 route_y_max = water_level + max_tunnel_diameter/3 - of.Y;
88 route_y_min = ps->range(min, min + max_tunnel_diameter);
89 route_y_min = rangelim(route_y_min, 0, route_y_max);
91 s16 route_start_y_min = route_y_min;
92 s16 route_start_y_max = route_y_max;
94 route_start_y_min = rangelim(route_start_y_min, 0, ar.Y - 1);
95 route_start_y_max = rangelim(route_start_y_max, route_start_y_min, ar.Y - 1);
97 // Randomize starting position
99 (float)(ps->next() % ar.X) + 0.5,
100 (float)(ps->range(route_start_y_min, route_start_y_max)) + 0.5,
101 (float)(ps->next() % ar.Z) + 0.5
104 // Add generation notify begin event
105 v3s16 abs_pos(of.X + orp.X, of.Y + orp.Y, of.Z + orp.Z);
106 GenNotifyType notifytype = GENNOTIFY_LARGECAVE_BEGIN;
107 mg->gennotify.addEvent(notifytype, abs_pos);
109 // Generate some tunnel starting from orp
110 for (u16 j = 0; j < tunnel_routepoints; j++)
111 makeTunnel(j % dswitchint == 0);
113 // Add generation notify end event
114 abs_pos = v3s16(of.X + orp.X, of.Y + orp.Y, of.Z + orp.Z);
115 notifytype = GENNOTIFY_LARGECAVE_END;
116 mg->gennotify.addEvent(notifytype, abs_pos);
120 void CaveV5::makeTunnel(bool dirswitch)
123 s16 min_d = min_tunnel_diameter;
124 s16 max_d = max_tunnel_diameter;
125 rs = ps->range(min_d, max_d);
126 s16 rs_part_max_length_rs = rs * part_max_length_rs;
130 rs_part_max_length_rs,
131 rs_part_max_length_rs / 2,
132 rs_part_max_length_rs
136 // Jump downward sometimes
138 (float)(ps->next() % maxlen.X) - (float)maxlen.X / 2,
139 (float)(ps->next() % maxlen.Y) - (float)maxlen.Y / 2,
140 (float)(ps->next() % maxlen.Z) - (float)maxlen.Z / 2
143 // Do not make caves that are above ground.
144 // It is only necessary to check the startpoint and endpoint.
145 v3s16 orpi(orp.X, orp.Y, orp.Z);
146 v3s16 veci(vec.X, vec.Y, vec.Z);
149 p = orpi + veci + of + rs / 2;
150 if (p.Z >= node_min.Z && p.Z <= node_max.Z &&
151 p.X >= node_min.X && p.X <= node_max.X) {
152 u32 index = (p.Z - node_min.Z) * mg->ystride + (p.X - node_min.X);
153 s16 h = mg->heightmap[index];
156 } else if (p.Y > water_level) {
157 return; // If it's not in our heightmap, use a simple heuristic
160 p = orpi + of + rs / 2;
161 if (p.Z >= node_min.Z && p.Z <= node_max.Z &&
162 p.X >= node_min.X && p.X <= node_max.X) {
163 u32 index = (p.Z - node_min.Z) * mg->ystride + (p.X - node_min.X);
164 s16 h = mg->heightmap[index];
167 } else if (p.Y > water_level) {
171 vec += main_direction;
176 else if (rp.X >= ar.X)
179 if (rp.Y < route_y_min)
181 else if (rp.Y >= route_y_max)
182 rp.Y = route_y_max - 1;
186 else if (rp.Z >= ar.Z)
191 float veclen = vec.getLength();
195 // Every second section is rough
196 bool randomize_xz = (ps->range(1, 2) == 1);
199 for (float f = 0; f < 1.0; f += 1.0 / veclen)
200 carveRoute(vec, f, randomize_xz);
206 void CaveV5::carveRoute(v3f vec, float f, bool randomize_xz)
208 MapNode airnode(CONTENT_AIR);
209 MapNode waternode(c_water_source);
210 MapNode lavanode(c_lava_source);
212 v3s16 startp(orp.X, orp.Y, orp.Z);
215 float nval = NoisePerlin3D(np_caveliquids, startp.X,
216 startp.Y, startp.Z, mg->seed);
217 MapNode liquidnode = nval < 0.40 ? lavanode : waternode;
219 v3f fp = orp + vec * f;
220 fp.X += 0.1 * ps->range(-10, 10);
221 fp.Z += 0.1 * ps->range(-10, 10);
222 v3s16 cp(fp.X, fp.Y, fp.Z);
227 d0 += ps->range(-1, 1);
228 d1 += ps->range(-1, 1);
231 for (s16 z0 = d0; z0 <= d1; z0++) {
232 s16 si = rs / 2 - MYMAX(0, abs(z0) - rs / 7 - 1);
233 for (s16 x0 = -si - ps->range(0,1); x0 <= si - 1 + ps->range(0,1); x0++) {
234 s16 maxabsxz = MYMAX(abs(x0), abs(z0));
236 s16 si2 = rs / 2 - MYMAX(0, maxabsxz - rs / 7 - 1);
238 for (s16 y0 = -si2; y0 <= si2; y0++) {
239 if (large_cave_is_flat) {
240 // Make large caves not so tall
241 if (rs > 7 && abs(y0) >= rs / 3)
245 v3s16 p(cp.X + x0, cp.Y + y0, cp.Z + z0);
248 if (vm->m_area.contains(p) == false)
251 u32 i = vm->m_area.index(p);
252 content_t c = vm->m_data[i].getContent();
253 if (!ndef->get(c).is_ground_content)
256 int full_ymin = node_min.Y - MAP_BLOCKSIZE;
257 int full_ymax = node_max.Y + MAP_BLOCKSIZE;
259 if (flooded && full_ymin < water_level &&
260 full_ymax > water_level)
261 vm->m_data[i] = (p.Y <= water_level) ?
263 else if (flooded && full_ymax < water_level)
264 vm->m_data[i] = (p.Y < startp.Y - 4) ?
265 liquidnode : airnode;
267 vm->m_data[i] = airnode;
274 ///////////////////////////////////////// Caves V6
277 CaveV6::CaveV6(MapgenV6 *mg, PseudoRandom *ps, PseudoRandom *ps2, bool is_large_cave)
281 this->ndef = mg->ndef;
282 this->water_level = mg->water_level;
283 this->large_cave = is_large_cave;
286 this->c_water_source = mg->c_water_source;
287 this->c_lava_source = mg->c_lava_source;
289 min_tunnel_diameter = 2;
290 max_tunnel_diameter = ps->range(2, 6);
291 dswitchint = ps->range(1, 14);
295 part_max_length_rs = ps->range(2,4);
296 tunnel_routepoints = ps->range(5, ps->range(15,30));
297 min_tunnel_diameter = 5;
298 max_tunnel_diameter = ps->range(7, ps->range(8,24));
300 part_max_length_rs = ps->range(2,9);
301 tunnel_routepoints = ps->range(10, ps->range(15,30));
304 large_cave_is_flat = (ps->range(0,1) == 0);
308 void CaveV6::makeCave(v3s16 nmin, v3s16 nmax, int max_stone_height)
312 max_stone_y = max_stone_height;
313 main_direction = v3f(0, 0, 0);
315 // Allowed route area size in nodes
316 ar = node_max - node_min + v3s16(1, 1, 1);
317 // Area starting point in nodes
321 //(this should be more than the maximum radius of the tunnel)
322 const s16 max_spread_amount = MAP_BLOCKSIZE;
324 s16 more = MYMAX(max_spread_amount - max_tunnel_diameter / 2 - insure, 1);
325 ar += v3s16(1,0,1) * more * 2;
326 of -= v3s16(1,0,1) * more;
329 // Allow half a diameter + 7 over stone surface
330 route_y_max = -of.Y + max_stone_y + max_tunnel_diameter / 2 + 7;
332 // Limit maximum to area
333 route_y_max = rangelim(route_y_max, 0, ar.Y - 1);
337 if (node_min.Y < water_level && node_max.Y > water_level) {
338 min = water_level - max_tunnel_diameter/3 - of.Y;
339 route_y_max = water_level + max_tunnel_diameter/3 - of.Y;
341 route_y_min = ps->range(min, min + max_tunnel_diameter);
342 route_y_min = rangelim(route_y_min, 0, route_y_max);
345 s16 route_start_y_min = route_y_min;
346 s16 route_start_y_max = route_y_max;
348 route_start_y_min = rangelim(route_start_y_min, 0, ar.Y-1);
349 route_start_y_max = rangelim(route_start_y_max, route_start_y_min, ar.Y-1);
351 // Randomize starting position
353 (float)(ps->next() % ar.X) + 0.5,
354 (float)(ps->range(route_start_y_min, route_start_y_max)) + 0.5,
355 (float)(ps->next() % ar.Z) + 0.5
358 // Add generation notify begin event
359 v3s16 abs_pos(of.X + orp.X, of.Y + orp.Y, of.Z + orp.Z);
360 GenNotifyType notifytype = large_cave ?
361 GENNOTIFY_LARGECAVE_BEGIN : GENNOTIFY_CAVE_BEGIN;
362 mg->gennotify.addEvent(notifytype, abs_pos);
364 // Generate some tunnel starting from orp
365 for (u16 j = 0; j < tunnel_routepoints; j++)
366 makeTunnel(j % dswitchint == 0);
368 // Add generation notify end event
369 abs_pos = v3s16(of.X + orp.X, of.Y + orp.Y, of.Z + orp.Z);
370 notifytype = large_cave ?
371 GENNOTIFY_LARGECAVE_END : GENNOTIFY_CAVE_END;
372 mg->gennotify.addEvent(notifytype, abs_pos);
376 void CaveV6::makeTunnel(bool dirswitch)
378 if (dirswitch && !large_cave) {
379 main_direction = v3f(
380 ((float)(ps->next() % 20) - (float)10) / 10,
381 ((float)(ps->next() % 20) - (float)10) / 30,
382 ((float)(ps->next() % 20) - (float)10) / 10
384 main_direction *= (float)ps->range(0, 10) / 10;
388 s16 min_d = min_tunnel_diameter;
389 s16 max_d = max_tunnel_diameter;
390 rs = ps->range(min_d, max_d);
391 s16 rs_part_max_length_rs = rs * part_max_length_rs;
396 rs_part_max_length_rs,
397 rs_part_max_length_rs / 2,
398 rs_part_max_length_rs
402 rs_part_max_length_rs,
403 ps->range(1, rs_part_max_length_rs),
404 rs_part_max_length_rs
409 (float)(ps->next() % maxlen.X) - (float)maxlen.X / 2,
410 (float)(ps->next() % maxlen.Y) - (float)maxlen.Y / 2,
411 (float)(ps->next() % maxlen.Z) - (float)maxlen.Z / 2
414 // Jump downward sometimes
415 if (!large_cave && ps->range(0, 12) == 0) {
417 (float)(ps->next() % maxlen.X) - (float)maxlen.X / 2,
418 (float)(ps->next() % (maxlen.Y * 2)) - (float)maxlen.Y,
419 (float)(ps->next() % maxlen.Z) - (float)maxlen.Z / 2
423 // Do not make caves that are entirely above ground, to fix
424 // shadow bugs caused by overgenerated large caves.
425 // It is only necessary to check the startpoint and endpoint.
426 v3s16 orpi(orp.X, orp.Y, orp.Z);
427 v3s16 veci(vec.X, vec.Y, vec.Z);
431 v3s16 p1 = orpi + veci + of + rs / 2;
432 if (p1.Z >= node_min.Z && p1.Z <= node_max.Z &&
433 p1.X >= node_min.X && p1.X <= node_max.X) {
434 u32 index1 = (p1.Z - node_min.Z) * mg->ystride +
436 h1 = mg->heightmap[index1];
438 h1 = water_level; // If not in heightmap
441 v3s16 p2 = orpi + of + rs / 2;
442 if (p2.Z >= node_min.Z && p2.Z <= node_max.Z &&
443 p2.X >= node_min.X && p2.X <= node_max.X) {
444 u32 index2 = (p2.Z - node_min.Z) * mg->ystride +
446 h2 = mg->heightmap[index2];
451 // If startpoint and endpoint are above ground,
452 // disable placing of nodes in carveRoute while
453 // still running all pseudorandom calls to ensure
454 // caves consistent with existing worlds.
455 bool tunnel_above_ground = p1.Y > h1 && p2.Y > h2;
457 vec += main_direction;
462 else if (rp.X >= ar.X)
465 if (rp.Y < route_y_min)
467 else if (rp.Y >= route_y_max)
468 rp.Y = route_y_max - 1;
472 else if (rp.Z >= ar.Z)
477 float veclen = vec.getLength();
478 // As odd as it sounds, veclen is *exactly* 0.0 sometimes, causing a FPE
482 // Every second section is rough
483 bool randomize_xz = (ps2->range(1, 2) == 1);
486 for (float f = 0; f < 1.0; f += 1.0 / veclen)
487 carveRoute(vec, f, randomize_xz, tunnel_above_ground);
493 void CaveV6::carveRoute(v3f vec, float f, bool randomize_xz, bool tunnel_above_ground)
495 MapNode airnode(CONTENT_AIR);
496 MapNode waternode(c_water_source);
497 MapNode lavanode(c_lava_source);
499 v3s16 startp(orp.X, orp.Y, orp.Z);
502 v3f fp = orp + vec * f;
503 fp.X += 0.1 * ps->range(-10, 10);
504 fp.Z += 0.1 * ps->range(-10, 10);
505 v3s16 cp(fp.X, fp.Y, fp.Z);
510 d0 += ps->range(-1, 1);
511 d1 += ps->range(-1, 1);
514 for (s16 z0 = d0; z0 <= d1; z0++) {
515 s16 si = rs / 2 - MYMAX(0, abs(z0) - rs / 7 - 1);
516 for (s16 x0 = -si - ps->range(0,1); x0 <= si - 1 + ps->range(0,1); x0++) {
517 if (tunnel_above_ground)
520 s16 maxabsxz = MYMAX(abs(x0), abs(z0));
521 s16 si2 = rs / 2 - MYMAX(0, maxabsxz - rs / 7 - 1);
522 for (s16 y0 = -si2; y0 <= si2; y0++) {
523 if (large_cave_is_flat) {
524 // Make large caves not so tall
525 if (rs > 7 && abs(y0) >= rs / 3)
529 v3s16 p(cp.X + x0, cp.Y + y0, cp.Z + z0);
532 if (vm->m_area.contains(p) == false)
535 u32 i = vm->m_area.index(p);
536 content_t c = vm->m_data[i].getContent();
537 if (!ndef->get(c).is_ground_content)
541 int full_ymin = node_min.Y - MAP_BLOCKSIZE;
542 int full_ymax = node_max.Y + MAP_BLOCKSIZE;
544 if (flooded && full_ymin < water_level &&
545 full_ymax > water_level) {
546 vm->m_data[i] = (p.Y <= water_level) ?
548 } else if (flooded && full_ymax < water_level) {
549 vm->m_data[i] = (p.Y < startp.Y - 2) ?
552 vm->m_data[i] = airnode;
555 if (c == CONTENT_IGNORE || c == CONTENT_AIR)
558 vm->m_data[i] = airnode;
559 vm->m_flags[i] |= VMANIP_FLAG_CAVE;
567 ///////////////////////////////////////// Caves V7
570 CaveV7::CaveV7(MapgenV7 *mg, PseudoRandom *ps)
574 this->ndef = mg->ndef;
575 this->water_level = mg->water_level;
577 this->c_water_source = mg->c_water_source;
578 this->c_lava_source = mg->c_lava_source;
579 this->c_ice = mg->c_ice;
580 this->np_caveliquids = &nparams_caveliquids;
582 dswitchint = ps->range(1, 14);
583 flooded = ps->range(1, 2) == 2;
585 part_max_length_rs = ps->range(2, 4);
586 tunnel_routepoints = ps->range(5, ps->range(15, 30));
587 min_tunnel_diameter = 5;
588 max_tunnel_diameter = ps->range(7, ps->range(8, 24));
590 large_cave_is_flat = (ps->range(0, 1) == 0);
594 void CaveV7::makeCave(v3s16 nmin, v3s16 nmax, int max_stone_height)
598 max_stone_y = max_stone_height;
599 main_direction = v3f(0, 0, 0);
601 // Allowed route area size in nodes
602 ar = node_max - node_min + v3s16(1, 1, 1);
603 // Area starting point in nodes
607 //(this should be more than the maximum radius of the tunnel)
609 s16 more = MYMAX(MAP_BLOCKSIZE - max_tunnel_diameter / 2 - insure, 1);
610 ar += v3s16(1,0,1) * more * 2;
611 of -= v3s16(1,0,1) * more;
614 // Allow half a diameter + 7 over stone surface
615 route_y_max = -of.Y + max_stone_y + max_tunnel_diameter / 2 + 7;
617 // Limit maximum to area
618 route_y_max = rangelim(route_y_max, 0, ar.Y - 1);
621 if (node_min.Y < water_level && node_max.Y > water_level) {
622 min = water_level - max_tunnel_diameter/3 - of.Y;
623 route_y_max = water_level + max_tunnel_diameter/3 - of.Y;
625 route_y_min = ps->range(min, min + max_tunnel_diameter);
626 route_y_min = rangelim(route_y_min, 0, route_y_max);
628 s16 route_start_y_min = route_y_min;
629 s16 route_start_y_max = route_y_max;
631 route_start_y_min = rangelim(route_start_y_min, 0, ar.Y - 1);
632 route_start_y_max = rangelim(route_start_y_max, route_start_y_min, ar.Y - 1);
634 // Randomize starting position
636 (float)(ps->next() % ar.X) + 0.5,
637 (float)(ps->range(route_start_y_min, route_start_y_max)) + 0.5,
638 (float)(ps->next() % ar.Z) + 0.5
641 // Add generation notify begin event
642 v3s16 abs_pos(of.X + orp.X, of.Y + orp.Y, of.Z + orp.Z);
643 GenNotifyType notifytype = GENNOTIFY_LARGECAVE_BEGIN;
644 mg->gennotify.addEvent(notifytype, abs_pos);
646 // Generate some tunnel starting from orp
647 for (u16 j = 0; j < tunnel_routepoints; j++)
648 makeTunnel(j % dswitchint == 0);
650 // Add generation notify end event
651 abs_pos = v3s16(of.X + orp.X, of.Y + orp.Y, of.Z + orp.Z);
652 notifytype = GENNOTIFY_LARGECAVE_END;
653 mg->gennotify.addEvent(notifytype, abs_pos);
657 void CaveV7::makeTunnel(bool dirswitch)
660 s16 min_d = min_tunnel_diameter;
661 s16 max_d = max_tunnel_diameter;
662 rs = ps->range(min_d, max_d);
663 s16 rs_part_max_length_rs = rs * part_max_length_rs;
667 rs_part_max_length_rs,
668 rs_part_max_length_rs / 2,
669 rs_part_max_length_rs
673 // Jump downward sometimes
675 (float)(ps->next() % maxlen.X) - (float)maxlen.X / 2,
676 (float)(ps->next() % maxlen.Y) - (float)maxlen.Y / 2,
677 (float)(ps->next() % maxlen.Z) - (float)maxlen.Z / 2
680 // Do not make caves that are above ground.
681 // It is only necessary to check the startpoint and endpoint.
682 v3s16 orpi(orp.X, orp.Y, orp.Z);
683 v3s16 veci(vec.X, vec.Y, vec.Z);
686 p = orpi + veci + of + rs / 2;
687 if (p.Z >= node_min.Z && p.Z <= node_max.Z &&
688 p.X >= node_min.X && p.X <= node_max.X) {
689 u32 index = (p.Z - node_min.Z) * mg->ystride + (p.X - node_min.X);
690 s16 h = mg->ridge_heightmap[index];
693 } else if (p.Y > water_level) {
694 return; // If it's not in our heightmap, use a simple heuristic
697 p = orpi + of + rs / 2;
698 if (p.Z >= node_min.Z && p.Z <= node_max.Z &&
699 p.X >= node_min.X && p.X <= node_max.X) {
700 u32 index = (p.Z - node_min.Z) * mg->ystride + (p.X - node_min.X);
701 s16 h = mg->ridge_heightmap[index];
704 } else if (p.Y > water_level) {
708 vec += main_direction;
713 else if (rp.X >= ar.X)
716 if (rp.Y < route_y_min)
718 else if (rp.Y >= route_y_max)
719 rp.Y = route_y_max - 1;
723 else if (rp.Z >= ar.Z)
728 float veclen = vec.getLength();
732 // Every second section is rough
733 bool randomize_xz = (ps->range(1, 2) == 1);
736 for (float f = 0; f < 1.0; f += 1.0 / veclen)
737 carveRoute(vec, f, randomize_xz);
743 void CaveV7::carveRoute(v3f vec, float f, bool randomize_xz)
745 MapNode airnode(CONTENT_AIR);
746 MapNode waternode(c_water_source);
747 MapNode lavanode(c_lava_source);
749 v3s16 startp(orp.X, orp.Y, orp.Z);
752 float nval = NoisePerlin3D(np_caveliquids, startp.X,
753 startp.Y, startp.Z, mg->seed);
754 MapNode liquidnode = (nval < 0.40 && node_max.Y < MGV7_LAVA_DEPTH) ?
755 lavanode : waternode;
757 v3f fp = orp + vec * f;
758 fp.X += 0.1 * ps->range(-10, 10);
759 fp.Z += 0.1 * ps->range(-10, 10);
760 v3s16 cp(fp.X, fp.Y, fp.Z);
765 d0 += ps->range(-1, 1);
766 d1 += ps->range(-1, 1);
769 for (s16 z0 = d0; z0 <= d1; z0++) {
770 s16 si = rs / 2 - MYMAX(0, abs(z0) - rs / 7 - 1);
771 for (s16 x0 = -si - ps->range(0,1); x0 <= si - 1 + ps->range(0,1); x0++) {
772 s16 maxabsxz = MYMAX(abs(x0), abs(z0));
774 s16 si2 = rs / 2 - MYMAX(0, maxabsxz - rs / 7 - 1);
776 for (s16 y0 = -si2; y0 <= si2; y0++) {
777 if (large_cave_is_flat) {
778 // Make large caves not so tall
779 if (rs > 7 && abs(y0) >= rs / 3)
783 v3s16 p(cp.X + x0, cp.Y + y0, cp.Z + z0);
786 if (vm->m_area.contains(p) == false)
789 u32 i = vm->m_area.index(p);
790 content_t c = vm->m_data[i].getContent();
791 if (!ndef->get(c).is_ground_content)
794 int full_ymin = node_min.Y - MAP_BLOCKSIZE;
795 int full_ymax = node_max.Y + MAP_BLOCKSIZE;
797 if (flooded && full_ymin < water_level &&
798 full_ymax > water_level)
799 vm->m_data[i] = (p.Y <= water_level) ?
801 else if (flooded && full_ymax < water_level)
802 vm->m_data[i] = (p.Y < startp.Y - 4) ?
803 liquidnode : airnode;
805 vm->m_data[i] = airnode;