Mgv6: Add heightmap. Do not make large caves that are entirely above ground
[oweals/minetest.git] / src / cavegen.cpp
1 /*
2 Minetest
3 Copyright (C) 2010-2013 celeron55, Perttu Ahola <celeron55@gmail.com>
4
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.
9
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.
14
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.
18 */
19
20 #include "util/numeric.h"
21 #include "map.h"
22 #include "mapgen.h"
23 #include "mapgen_v5.h"
24 #include "mapgen_v6.h"
25 #include "mapgen_v7.h"
26 #include "cavegen.h"
27
28 NoiseParams nparams_caveliquids(0, 1, v3f(150.0, 150.0, 150.0), 776, 3, 0.6, 2.0);
29
30
31 ///////////////////////////////////////////////////////////////////////////////
32
33
34 CaveV6::CaveV6(MapgenV6 *mg, PseudoRandom *ps, PseudoRandom *ps2, bool is_large_cave) {
35         this->mg   = mg;
36         this->vm   = mg->vm;
37         this->ndef = mg->ndef;
38         this->water_level = mg->water_level;
39         this->large_cave = is_large_cave;
40         this->ps  = ps;
41         this->ps2 = ps2;
42         this->c_water_source = mg->c_water_source;
43         this->c_lava_source  = mg->c_lava_source;
44
45         min_tunnel_diameter = 2;
46         max_tunnel_diameter = ps->range(2, 6);
47         dswitchint = ps->range(1, 14);
48         flooded = true;
49
50         if (large_cave) {
51                 part_max_length_rs = ps->range(2,4);
52                 tunnel_routepoints = ps->range(5, ps->range(15,30));
53                 min_tunnel_diameter = 5;
54                 max_tunnel_diameter = ps->range(7, ps->range(8,24));
55         } else {
56                 part_max_length_rs = ps->range(2,9);
57                 tunnel_routepoints = ps->range(10, ps->range(15,30));
58         }
59
60         large_cave_is_flat = (ps->range(0,1) == 0);
61 }
62
63
64 void CaveV6::makeCave(v3s16 nmin, v3s16 nmax, int max_stone_height) {
65         node_min = nmin;
66         node_max = nmax;
67         max_stone_y = max_stone_height;
68         main_direction = v3f(0, 0, 0);
69
70         // Allowed route area size in nodes
71         ar = node_max - node_min + v3s16(1, 1, 1);
72         // Area starting point in nodes
73         of = node_min;
74
75         // Allow a bit more
76         //(this should be more than the maximum radius of the tunnel)
77         const s16 max_spread_amount = MAP_BLOCKSIZE;
78         s16 insure = 10;
79         s16 more = MYMAX(max_spread_amount - max_tunnel_diameter / 2 - insure, 1);
80         ar += v3s16(1,0,1) * more * 2;
81         of -= v3s16(1,0,1) * more;
82
83         route_y_min = 0;
84         // Allow half a diameter + 7 over stone surface
85         route_y_max = -of.Y + max_stone_y + max_tunnel_diameter / 2 + 7;
86
87         // Limit maximum to area
88         route_y_max = rangelim(route_y_max, 0, ar.Y - 1);
89
90         if (large_cave) {
91                 s16 min = 0;
92                 if (node_min.Y < water_level && node_max.Y > water_level) {
93                         min = water_level - max_tunnel_diameter/3 - of.Y;
94                         route_y_max = water_level + max_tunnel_diameter/3 - of.Y;
95                 }
96                 route_y_min = ps->range(min, min + max_tunnel_diameter);
97                 route_y_min = rangelim(route_y_min, 0, route_y_max);
98         }
99
100         s16 route_start_y_min = route_y_min;
101         s16 route_start_y_max = route_y_max;
102
103         route_start_y_min = rangelim(route_start_y_min, 0, ar.Y-1);
104         route_start_y_max = rangelim(route_start_y_max, route_start_y_min, ar.Y-1);
105
106         // Randomize starting position
107         orp = v3f(
108                 (float)(ps->next() % ar.X) + 0.5,
109                 (float)(ps->range(route_start_y_min, route_start_y_max)) + 0.5,
110                 (float)(ps->next() % ar.Z) + 0.5
111         );
112
113         // Add generation notify begin event
114         v3s16 abs_pos(of.X + orp.X, of.Y + orp.Y, of.Z + orp.Z);
115         GenNotifyType notifytype = large_cave ?
116                 GENNOTIFY_LARGECAVE_BEGIN : GENNOTIFY_CAVE_BEGIN;
117         mg->gennotify.addEvent(notifytype, abs_pos);
118
119         // Generate some tunnel starting from orp
120         for (u16 j = 0; j < tunnel_routepoints; j++)
121                 makeTunnel(j % dswitchint == 0);
122
123         // Add generation notify end event
124         abs_pos = v3s16(of.X + orp.X, of.Y + orp.Y, of.Z + orp.Z);
125         notifytype = large_cave ?
126                 GENNOTIFY_LARGECAVE_END : GENNOTIFY_CAVE_END;
127         mg->gennotify.addEvent(notifytype, abs_pos);
128 }
129
130
131 void CaveV6::makeTunnel(bool dirswitch) {
132         if (dirswitch && !large_cave) {
133                 main_direction = v3f(
134                         ((float)(ps->next() % 20) - (float)10) / 10,
135                         ((float)(ps->next() % 20) - (float)10) / 30,
136                         ((float)(ps->next() % 20) - (float)10) / 10
137                 );
138                 main_direction *= (float)ps->range(0, 10) / 10;
139         }
140
141         // Randomize size
142         s16 min_d = min_tunnel_diameter;
143         s16 max_d = max_tunnel_diameter;
144         rs = ps->range(min_d, max_d);
145
146         v3s16 maxlen;
147         if (large_cave) {
148                 maxlen = v3s16(
149                         rs * part_max_length_rs,
150                         rs * part_max_length_rs / 2,
151                         rs * part_max_length_rs
152                 );
153         } else {
154                 maxlen = v3s16(
155                         rs * part_max_length_rs,
156                         ps->range(1, rs * part_max_length_rs),
157                         rs * part_max_length_rs
158                 );
159         }
160
161         v3f vec(
162                 (float)(ps->next() % (maxlen.X * 1)) - (float)maxlen.X / 2,
163                 (float)(ps->next() % (maxlen.Y * 1)) - (float)maxlen.Y / 2,
164                 (float)(ps->next() % (maxlen.Z * 1)) - (float)maxlen.Z / 2
165         );
166
167         // Jump downward sometimes
168         if (!large_cave && ps->range(0, 12) == 0) {
169                 vec = v3f(
170                         (float)(ps->next() % (maxlen.X * 1)) - (float)maxlen.X / 2,
171                         (float)(ps->next() % (maxlen.Y * 2)) - (float)maxlen.Y,
172                         (float)(ps->next() % (maxlen.Z * 1)) - (float)maxlen.Z / 2
173                 );
174         }
175
176         // Do not make large caves that are entirely above ground.
177         // It is only necessary to check the startpoint and endpoint.
178         if (large_cave) {
179                 v3s16 orpi(orp.X, orp.Y, orp.Z);
180                 v3s16 veci(vec.X, vec.Y, vec.Z);
181                 s16 h1;
182                 s16 h2;
183
184                 v3s16 p1 = orpi + veci + of + rs / 2;
185                 if (p1.Z >= node_min.Z && p1.Z <= node_max.Z &&
186                                 p1.X >= node_min.X && p1.X <= node_max.X) {
187                         u32 index1 = (p1.Z - node_min.Z) * mg->ystride + (p1.X - node_min.X);
188                         h1 = mg->heightmap[index1];
189                 } else {
190                         h1 = water_level; // If not in heightmap
191                 }
192
193                 v3s16 p2 = orpi + of + rs / 2;
194                 if (p2.Z >= node_min.Z && p2.Z <= node_max.Z &&
195                                 p2.X >= node_min.X && p2.X <= node_max.X) {
196                         u32 index2 = (p2.Z - node_min.Z) * mg->ystride + (p2.X - node_min.X);
197                         h2 = mg->heightmap[index2];
198                 } else {
199                         h2 = water_level;
200                 }
201
202                 if (p1.Y > h1 && p2.Y > h2) // If startpoint and endpoint are above ground
203                         return;
204         }
205
206         vec += main_direction;
207
208         v3f rp = orp + vec;
209         if (rp.X < 0)
210                 rp.X = 0;
211         else if (rp.X >= ar.X)
212                 rp.X = ar.X - 1;
213
214         if (rp.Y < route_y_min)
215                 rp.Y = route_y_min;
216         else if (rp.Y >= route_y_max)
217                 rp.Y = route_y_max - 1;
218
219         if (rp.Z < 0)
220                 rp.Z = 0;
221         else if (rp.Z >= ar.Z)
222                 rp.Z = ar.Z - 1;
223
224         vec = rp - orp;
225
226         float veclen = vec.getLength();
227         // As odd as it sounds, veclen is *exactly* 0.0 sometimes, causing a FPE
228         if (veclen < 0.05)
229                 veclen = 1.0;
230
231         // Every second section is rough
232         bool randomize_xz = (ps2->range(1, 2) == 1);
233
234         // Carve routes
235         for (float f = 0; f < 1.0; f += 1.0 / veclen)
236                 carveRoute(vec, f, randomize_xz);
237
238         orp = rp;
239 }
240
241
242 void CaveV6::carveRoute(v3f vec, float f, bool randomize_xz) {
243         MapNode airnode(CONTENT_AIR);
244         MapNode waternode(c_water_source);
245         MapNode lavanode(c_lava_source);
246
247         v3s16 startp(orp.X, orp.Y, orp.Z);
248         startp += of;
249
250         v3f fp = orp + vec * f;
251         fp.X += 0.1 * ps->range(-10, 10);
252         fp.Z += 0.1 * ps->range(-10, 10);
253         v3s16 cp(fp.X, fp.Y, fp.Z);
254
255         s16 d0 = -rs/2;
256         s16 d1 = d0 + rs;
257         if (randomize_xz) {
258                 d0 += ps->range(-1, 1);
259                 d1 += ps->range(-1, 1);
260         }
261
262         for (s16 z0 = d0; z0 <= d1; z0++) {
263                 s16 si = rs / 2 - MYMAX(0, abs(z0) - rs / 7 - 1);
264                 for (s16 x0 = -si - ps->range(0,1); x0 <= si - 1 + ps->range(0,1); x0++) {
265                         s16 maxabsxz = MYMAX(abs(x0), abs(z0));
266                         s16 si2 = rs / 2 - MYMAX(0, maxabsxz - rs / 7 - 1);
267                         for (s16 y0 = -si2; y0 <= si2; y0++) {
268                                 if (large_cave_is_flat) {
269                                         // Make large caves not so tall
270                                         if (rs > 7 && abs(y0) >= rs / 3)
271                                                 continue;
272                                 }
273
274                                 v3s16 p(cp.X + x0, cp.Y + y0, cp.Z + z0);
275                                 p += of;
276
277                                 if (vm->m_area.contains(p) == false)
278                                         continue;
279
280                                 u32 i = vm->m_area.index(p);
281                                 content_t c = vm->m_data[i].getContent();
282                                 if (!ndef->get(c).is_ground_content)
283                                         continue;
284
285                                 if (large_cave) {
286                                         int full_ymin = node_min.Y - MAP_BLOCKSIZE;
287                                         int full_ymax = node_max.Y + MAP_BLOCKSIZE;
288
289                                         if (flooded && full_ymin < water_level && full_ymax > water_level) {
290                                                 vm->m_data[i] = (p.Y <= water_level) ? waternode : airnode;
291                                         } else if (flooded && full_ymax < water_level) {
292                                                 vm->m_data[i] = (p.Y < startp.Y - 2) ? lavanode : airnode;
293                                         } else {
294                                                 vm->m_data[i] = airnode;
295                                         }
296                                 } else {
297                                         // Don't replace air or water or lava or ignore
298                                         if (c == CONTENT_IGNORE || c == CONTENT_AIR ||
299                                                 c == c_water_source || c == c_lava_source)
300                                                 continue;
301
302                                         vm->m_data[i] = airnode;
303                                         vm->m_flags[i] |= VMANIP_FLAG_CAVE;
304                                 }
305                         }
306                 }
307         }
308 }
309
310
311 ///////////////////////////////////////// Caves V7
312
313
314 CaveV7::CaveV7(MapgenV7 *mg, PseudoRandom *ps, bool is_large_cave) {
315         this->mg   = mg;
316         this->vm   = mg->vm;
317         this->ndef = mg->ndef;
318         this->water_level = mg->water_level;
319         this->large_cave  = is_large_cave;
320         this->ps = ps;
321         this->c_water_source = mg->c_water_source;
322         this->c_lava_source  = mg->c_lava_source;
323         this->c_ice          = mg->c_ice;
324         this->np_caveliquids = &nparams_caveliquids;
325
326         dswitchint = ps->range(1, 14);
327         flooded    = ps->range(1, 2) == 2;
328
329         if (large_cave) {
330                 part_max_length_rs = ps->range(2, 4);
331                 tunnel_routepoints = ps->range(5, ps->range(15, 30));
332                 min_tunnel_diameter = 5;
333                 max_tunnel_diameter = ps->range(7, ps->range(8, 24));
334         } else {
335                 part_max_length_rs = ps->range(2, 9);
336                 tunnel_routepoints = ps->range(10, ps->range(15, 30));
337                 min_tunnel_diameter = 2;
338                 max_tunnel_diameter = ps->range(2, 6);
339         }
340
341         large_cave_is_flat = (ps->range(0, 1) == 0);
342 }
343
344
345 void CaveV7::makeCave(v3s16 nmin, v3s16 nmax, int max_stone_height) {
346         node_min = nmin;
347         node_max = nmax;
348         max_stone_y = max_stone_height;
349         main_direction = v3f(0, 0, 0);
350
351         // Allowed route area size in nodes
352         ar = node_max - node_min + v3s16(1, 1, 1);
353         // Area starting point in nodes
354         of = node_min;
355
356         // Allow a bit more
357         //(this should be more than the maximum radius of the tunnel)
358         s16 insure = 10;
359         s16 more = MYMAX(MAP_BLOCKSIZE - max_tunnel_diameter / 2 - insure, 1);
360         ar += v3s16(1,0,1) * more * 2;
361         of -= v3s16(1,0,1) * more;
362
363         route_y_min = 0;
364         // Allow half a diameter + 7 over stone surface
365         route_y_max = -of.Y + max_stone_y + max_tunnel_diameter / 2 + 7;
366
367         // Limit maximum to area
368         route_y_max = rangelim(route_y_max, 0, ar.Y - 1);
369
370         if (large_cave) {
371                 s16 min = 0;
372                 if (node_min.Y < water_level && node_max.Y > water_level) {
373                         min = water_level - max_tunnel_diameter/3 - of.Y;
374                         route_y_max = water_level + max_tunnel_diameter/3 - of.Y;
375                 }
376                 route_y_min = ps->range(min, min + max_tunnel_diameter);
377                 route_y_min = rangelim(route_y_min, 0, route_y_max);
378         }
379
380         s16 route_start_y_min = route_y_min;
381         s16 route_start_y_max = route_y_max;
382
383         route_start_y_min = rangelim(route_start_y_min, 0, ar.Y - 1);
384         route_start_y_max = rangelim(route_start_y_max, route_start_y_min, ar.Y - 1);
385
386         // Randomize starting position
387         orp = v3f(
388                 (float)(ps->next() % ar.X) + 0.5,
389                 (float)(ps->range(route_start_y_min, route_start_y_max)) + 0.5,
390                 (float)(ps->next() % ar.Z) + 0.5
391         );
392
393         // Add generation notify begin event
394         v3s16 abs_pos(of.X + orp.X, of.Y + orp.Y, of.Z + orp.Z);
395         GenNotifyType notifytype = large_cave ?
396                 GENNOTIFY_LARGECAVE_BEGIN : GENNOTIFY_CAVE_BEGIN;
397         mg->gennotify.addEvent(notifytype, abs_pos);
398
399         // Generate some tunnel starting from orp
400         for (u16 j = 0; j < tunnel_routepoints; j++)
401                 makeTunnel(j % dswitchint == 0);
402
403         // Add generation notify end event
404         abs_pos = v3s16(of.X + orp.X, of.Y + orp.Y, of.Z + orp.Z);
405         notifytype = large_cave ?
406                 GENNOTIFY_LARGECAVE_END : GENNOTIFY_CAVE_END;
407         mg->gennotify.addEvent(notifytype, abs_pos);
408 }
409
410
411 void CaveV7::makeTunnel(bool dirswitch) {
412         if (dirswitch && !large_cave) {
413                 main_direction = v3f(
414                         ((float)(ps->next() % 20) - (float)10) / 10,
415                         ((float)(ps->next() % 20) - (float)10) / 30,
416                         ((float)(ps->next() % 20) - (float)10) / 10
417                 );
418                 main_direction *= (float)ps->range(0, 10) / 10;
419         }
420
421         // Randomize size
422         s16 min_d = min_tunnel_diameter;
423         s16 max_d = max_tunnel_diameter;
424         rs = ps->range(min_d, max_d);
425
426         v3s16 maxlen;
427         if (large_cave) {
428                 maxlen = v3s16(
429                         rs * part_max_length_rs,
430                         rs * part_max_length_rs / 2,
431                         rs * part_max_length_rs
432                 );
433         } else {
434                 maxlen = v3s16(
435                         rs * part_max_length_rs,
436                         ps->range(1, rs * part_max_length_rs),
437                         rs * part_max_length_rs
438                 );
439         }
440
441         v3f vec;
442         // Jump downward sometimes
443         if (!large_cave && ps->range(0, 12) == 0) {
444                 vec = v3f(
445                         (float)(ps->next() % (maxlen.X * 1)) - (float)maxlen.X / 2,
446                         (float)(ps->next() % (maxlen.Y * 2)) - (float)maxlen.Y,
447                         (float)(ps->next() % (maxlen.Z * 1)) - (float)maxlen.Z / 2
448                 );
449         } else {
450                 vec = v3f(
451                         (float)(ps->next() % (maxlen.X * 1)) - (float)maxlen.X / 2,
452                         (float)(ps->next() % (maxlen.Y * 1)) - (float)maxlen.Y / 2,
453                         (float)(ps->next() % (maxlen.Z * 1)) - (float)maxlen.Z / 2
454                 );
455         }
456
457         // Do not make large caves that are above ground.
458         // It is only necessary to check the startpoint and endpoint.
459         if (large_cave) {
460                 v3s16 orpi(orp.X, orp.Y, orp.Z);
461                 v3s16 veci(vec.X, vec.Y, vec.Z);
462                 v3s16 p;
463
464                 p = orpi + veci + of + rs / 2;
465                 if (p.Z >= node_min.Z && p.Z <= node_max.Z &&
466                                 p.X >= node_min.X && p.X <= node_max.X) {
467                         u32 index = (p.Z - node_min.Z) * mg->ystride + (p.X - node_min.X);
468                         s16 h = mg->ridge_heightmap[index];
469                         if (h < p.Y)
470                                 return;
471                 } else if (p.Y > water_level) {
472                         return; // If it's not in our heightmap, use a simple heuristic
473                 }
474
475                 p = orpi + of + rs / 2;
476                 if (p.Z >= node_min.Z && p.Z <= node_max.Z &&
477                                 p.X >= node_min.X && p.X <= node_max.X) {
478                         u32 index = (p.Z - node_min.Z) * mg->ystride + (p.X - node_min.X);
479                         s16 h = mg->ridge_heightmap[index];
480                         if (h < p.Y)
481                                 return;
482                 } else if (p.Y > water_level) {
483                         return;
484                 }
485         }
486
487         vec += main_direction;
488
489         v3f rp = orp + vec;
490         if (rp.X < 0)
491                 rp.X = 0;
492         else if (rp.X >= ar.X)
493                 rp.X = ar.X - 1;
494
495         if (rp.Y < route_y_min)
496                 rp.Y = route_y_min;
497         else if (rp.Y >= route_y_max)
498                 rp.Y = route_y_max - 1;
499
500         if (rp.Z < 0)
501                 rp.Z = 0;
502         else if (rp.Z >= ar.Z)
503                 rp.Z = ar.Z - 1;
504
505         vec = rp - orp;
506
507         float veclen = vec.getLength();
508         if (veclen < 0.05)
509                 veclen = 1.0;
510
511         // Every second section is rough
512         bool randomize_xz = (ps->range(1, 2) == 1);
513
514         // Make a ravine every once in a while if it's long enough
515         //float xylen = vec.X * vec.X + vec.Z * vec.Z;
516         //disable ravines for now
517         bool is_ravine = false; //(xylen > 500.0) && !large_cave && (ps->range(1, 8) == 1);
518
519         // Carve routes
520         for (float f = 0; f < 1.0; f += 1.0 / veclen)
521                 carveRoute(vec, f, randomize_xz, is_ravine);
522
523         orp = rp;
524 }
525
526
527 void CaveV7::carveRoute(v3f vec, float f, bool randomize_xz, bool is_ravine) {
528         MapNode airnode(CONTENT_AIR);
529         MapNode waternode(c_water_source);
530         MapNode lavanode(c_lava_source);
531
532         v3s16 startp(orp.X, orp.Y, orp.Z);
533         startp += of;
534
535         float nval = NoisePerlin3D(np_caveliquids, startp.X,
536                                                         startp.Y, startp.Z, mg->seed);
537         MapNode liquidnode = nval < 0.40 ? lavanode : waternode;
538
539         v3f fp = orp + vec * f;
540         fp.X += 0.1 * ps->range(-10, 10);
541         fp.Z += 0.1 * ps->range(-10, 10);
542         v3s16 cp(fp.X, fp.Y, fp.Z);
543
544         s16 d0 = -rs/2;
545         s16 d1 = d0 + rs;
546         if (randomize_xz) {
547                 d0 += ps->range(-1, 1);
548                 d1 += ps->range(-1, 1);
549         }
550
551         bool flat_cave_floor = !large_cave && ps->range(0, 2) == 2;
552         bool should_make_cave_hole = ps->range(1, 10) == 1;
553
554         for (s16 z0 = d0; z0 <= d1; z0++) {
555                 s16 si = rs / 2 - MYMAX(0, abs(z0) - rs / 7 - 1);
556                 for (s16 x0 = -si - ps->range(0,1); x0 <= si - 1 + ps->range(0,1); x0++) {
557                         s16 maxabsxz = MYMAX(abs(x0), abs(z0));
558
559                         s16 si2 = is_ravine ? MYMIN(ps->range(25, 26), ar.Y) :
560                                                                  rs / 2 - MYMAX(0, maxabsxz - rs / 7 - 1);
561
562                         for (s16 y0 = -si2; y0 <= si2; y0++) {
563                                 // Make better floors in small caves
564                                 if(flat_cave_floor && y0 <= -rs/2 && rs<=7)
565                                         continue;
566
567                                 if (large_cave_is_flat) {
568                                         // Make large caves not so tall
569                                         if (rs > 7 && abs(y0) >= rs / 3)
570                                                 continue;
571                                 }
572
573                                 v3s16 p(cp.X + x0, cp.Y + y0, cp.Z + z0);
574                                 p += of;
575
576                                 if (!is_ravine && mg->heightmap && should_make_cave_hole &&
577                                         p.X <= node_max.X && p.Z <= node_max.Z) {
578                                         int maplen = node_max.X - node_min.X + 1;
579                                         int idx = (p.Z - node_min.Z) * maplen + (p.X - node_min.X);
580                                         if (p.Y >= mg->heightmap[idx] - 2)
581                                                 continue;
582                                 }
583
584                                 if (vm->m_area.contains(p) == false)
585                                         continue;
586
587                                 u32 i = vm->m_area.index(p);
588
589                                 // Don't replace air, water, lava, or ice
590                                 content_t c = vm->m_data[i].getContent();
591                                 if (!ndef->get(c).is_ground_content || c == CONTENT_AIR ||
592                                         c == c_water_source || c == c_lava_source || c == c_ice)
593                                         continue;
594
595                                 if (large_cave) {
596                                         int full_ymin = node_min.Y - MAP_BLOCKSIZE;
597                                         int full_ymax = node_max.Y + MAP_BLOCKSIZE;
598
599                                         if (flooded && full_ymin < water_level && full_ymax > water_level)
600                                                 vm->m_data[i] = (p.Y <= water_level) ? waternode : airnode;
601                                         else if (flooded && full_ymax < water_level)
602                                                 vm->m_data[i] = (p.Y < startp.Y - 4) ? liquidnode : airnode;
603                                         else
604                                                 vm->m_data[i] = airnode;
605                                 } else {
606                                         if (c == CONTENT_IGNORE)
607                                                 continue;
608
609                                         vm->m_data[i] = airnode;
610                                         vm->m_flags[i] |= VMANIP_FLAG_CAVE;
611                                 }
612                         }
613                 }
614         }
615 }
616
617
618 ///////////////////////////////////////// Caves V5
619
620
621 CaveV5::CaveV5(MapgenV5 *mg, PseudoRandom *ps) {
622         this->mg   = mg;
623         this->vm   = mg->vm;
624         this->ndef = mg->ndef;
625         this->water_level = mg->water_level;
626         this->ps = ps;
627         this->c_water_source = mg->c_water_source;
628         this->c_lava_source  = mg->c_lava_source;
629         this->c_ice          = mg->c_ice;
630         this->np_caveliquids = &nparams_caveliquids;
631
632         dswitchint = ps->range(1, 14);
633         flooded    = ps->range(1, 2) == 2;
634
635         part_max_length_rs = ps->range(2, 4);
636         tunnel_routepoints = ps->range(5, ps->range(15, 30));
637         min_tunnel_diameter = 5;
638         max_tunnel_diameter = ps->range(7, ps->range(8, 24));
639
640         large_cave_is_flat = (ps->range(0, 1) == 0);
641 }
642
643
644 void CaveV5::makeCave(v3s16 nmin, v3s16 nmax, int max_stone_height) {
645         node_min = nmin;
646         node_max = nmax;
647         main_direction = v3f(0, 0, 0);
648
649         // Allowed route area size in nodes
650         ar = node_max - node_min + v3s16(1, 1, 1);
651         // Area starting point in nodes
652         of = node_min;
653
654         // Allow a bit more
655         //(this should be more than the maximum radius of the tunnel)
656         s16 insure = 10;
657         s16 more = MYMAX(MAP_BLOCKSIZE - max_tunnel_diameter / 2 - insure, 1);
658         ar += v3s16(1,0,1) * more * 2;
659         of -= v3s16(1,0,1) * more;
660
661         route_y_min = 0;
662         // Allow half a diameter + 7 over stone surface
663         route_y_max = -of.Y + max_stone_y + max_tunnel_diameter / 2 + 7;
664
665         // Limit maximum to area
666         route_y_max = rangelim(route_y_max, 0, ar.Y - 1);
667
668         s16 min = 0;
669                 if (node_min.Y < water_level && node_max.Y > water_level) {
670                         min = water_level - max_tunnel_diameter/3 - of.Y;
671                         route_y_max = water_level + max_tunnel_diameter/3 - of.Y;
672                 }
673         route_y_min = ps->range(min, min + max_tunnel_diameter);
674         route_y_min = rangelim(route_y_min, 0, route_y_max);
675
676         s16 route_start_y_min = route_y_min;
677         s16 route_start_y_max = route_y_max;
678
679         route_start_y_min = rangelim(route_start_y_min, 0, ar.Y - 1);
680         route_start_y_max = rangelim(route_start_y_max, route_start_y_min, ar.Y - 1);
681
682         // Randomize starting position
683         orp = v3f(
684                 (float)(ps->next() % ar.X) + 0.5,
685                 (float)(ps->range(route_start_y_min, route_start_y_max)) + 0.5,
686                 (float)(ps->next() % ar.Z) + 0.5
687         );
688
689         // Add generation notify begin event
690         v3s16 abs_pos(of.X + orp.X, of.Y + orp.Y, of.Z + orp.Z);
691         GenNotifyType notifytype = GENNOTIFY_LARGECAVE_BEGIN;
692         mg->gennotify.addEvent(notifytype, abs_pos);
693
694         // Generate some tunnel starting from orp
695         for (u16 j = 0; j < tunnel_routepoints; j++)
696                 makeTunnel(j % dswitchint == 0);
697
698         // Add generation notify end event
699         abs_pos = v3s16(of.X + orp.X, of.Y + orp.Y, of.Z + orp.Z);
700         notifytype = GENNOTIFY_LARGECAVE_END;
701         mg->gennotify.addEvent(notifytype, abs_pos);
702 }
703
704
705 void CaveV5::makeTunnel(bool dirswitch) {
706
707         // Randomize size
708         s16 min_d = min_tunnel_diameter;
709         s16 max_d = max_tunnel_diameter;
710         rs = ps->range(min_d, max_d);
711
712         v3s16 maxlen;
713         maxlen = v3s16(
714                 rs * part_max_length_rs,
715                 rs * part_max_length_rs / 2,
716                 rs * part_max_length_rs
717         );
718
719         v3f vec;
720         // Jump downward sometimes
721         vec = v3f(
722                 (float)(ps->next() % (maxlen.X * 1)) - (float)maxlen.X / 2,
723                 (float)(ps->next() % (maxlen.Y * 1)) - (float)maxlen.Y / 2,
724                 (float)(ps->next() % (maxlen.Z * 1)) - (float)maxlen.Z / 2
725         );
726
727         // Do not make large caves that are above ground.
728         // It is only necessary to check the startpoint and endpoint.
729         v3s16 orpi(orp.X, orp.Y, orp.Z);
730         v3s16 veci(vec.X, vec.Y, vec.Z);
731         v3s16 p;
732
733         p = orpi + veci + of + rs / 2;
734         if (p.Z >= node_min.Z && p.Z <= node_max.Z &&
735                         p.X >= node_min.X && p.X <= node_max.X) {
736                 u32 index = (p.Z - node_min.Z) * mg->ystride + (p.X - node_min.X);
737                 s16 h = mg->heightmap[index];
738                 if (h < p.Y)
739                         return;
740         } else if (p.Y > water_level) {
741                 return; // If it's not in our heightmap, use a simple heuristic
742         }
743
744         p = orpi + of + rs / 2;
745         if (p.Z >= node_min.Z && p.Z <= node_max.Z &&
746                 p.X >= node_min.X && p.X <= node_max.X) {
747                 u32 index = (p.Z - node_min.Z) * mg->ystride + (p.X - node_min.X);
748                 s16 h = mg->heightmap[index];
749                 if (h < p.Y)
750                         return;
751         } else if (p.Y > water_level) {
752                 return;
753         }
754
755         vec += main_direction;
756
757         v3f rp = orp + vec;
758         if (rp.X < 0)
759                 rp.X = 0;
760         else if (rp.X >= ar.X)
761                 rp.X = ar.X - 1;
762
763         if (rp.Y < route_y_min)
764                 rp.Y = route_y_min;
765         else if (rp.Y >= route_y_max)
766                 rp.Y = route_y_max - 1;
767
768         if (rp.Z < 0)
769                 rp.Z = 0;
770         else if (rp.Z >= ar.Z)
771                 rp.Z = ar.Z - 1;
772
773         vec = rp - orp;
774
775         float veclen = vec.getLength();
776         if (veclen < 0.05)
777                 veclen = 1.0;
778
779         // Every second section is rough
780         bool randomize_xz = (ps->range(1, 2) == 1);
781
782         // Make a ravine every once in a while if it's long enough
783         //float xylen = vec.X * vec.X + vec.Z * vec.Z;
784         //disable ravines for now
785         bool is_ravine = false; //(xylen > 500.0) && !large_cave && (ps->range(1, 8) == 1);
786
787         // Carve routes
788         for (float f = 0; f < 1.0; f += 1.0 / veclen)
789                 carveRoute(vec, f, randomize_xz, is_ravine);
790
791         orp = rp;
792 }
793
794
795 void CaveV5::carveRoute(v3f vec, float f, bool randomize_xz, bool is_ravine) {
796         MapNode airnode(CONTENT_AIR);
797         MapNode waternode(c_water_source);
798         MapNode lavanode(c_lava_source);
799
800         v3s16 startp(orp.X, orp.Y, orp.Z);
801         startp += of;
802
803         float nval = NoisePerlin3D(np_caveliquids, startp.X,
804                                                         startp.Y, startp.Z, mg->seed);
805         MapNode liquidnode = nval < 0.40 ? lavanode : waternode;
806
807         v3f fp = orp + vec * f;
808         fp.X += 0.1 * ps->range(-10, 10);
809         fp.Z += 0.1 * ps->range(-10, 10);
810         v3s16 cp(fp.X, fp.Y, fp.Z);
811
812         s16 d0 = -rs/2;
813         s16 d1 = d0 + rs;
814         if (randomize_xz) {
815                 d0 += ps->range(-1, 1);
816                 d1 += ps->range(-1, 1);
817         }
818
819         bool should_make_cave_hole = ps->range(1, 10) == 1;
820
821         for (s16 z0 = d0; z0 <= d1; z0++) {
822                 s16 si = rs / 2 - MYMAX(0, abs(z0) - rs / 7 - 1);
823                 for (s16 x0 = -si - ps->range(0,1); x0 <= si - 1 + ps->range(0,1); x0++) {
824                         s16 maxabsxz = MYMAX(abs(x0), abs(z0));
825
826                         s16 si2 = is_ravine ? MYMIN(ps->range(25, 26), ar.Y) :
827                                                                  rs / 2 - MYMAX(0, maxabsxz - rs / 7 - 1);
828
829                         for (s16 y0 = -si2; y0 <= si2; y0++) {
830                                 if (large_cave_is_flat) {
831                                         // Make large caves not so tall
832                                         if (rs > 7 && abs(y0) >= rs / 3)
833                                                 continue;
834                                 }
835
836                                 v3s16 p(cp.X + x0, cp.Y + y0, cp.Z + z0);
837                                 p += of;
838
839                                 if (!is_ravine && mg->heightmap && should_make_cave_hole &&
840                                         p.X <= node_max.X && p.Z <= node_max.Z) {
841                                         int maplen = node_max.X - node_min.X + 1;
842                                         int idx = (p.Z - node_min.Z) * maplen + (p.X - node_min.X);
843                                         if (p.Y >= mg->heightmap[idx] - 2)
844                                                 continue;
845                                 }
846
847                                 if (vm->m_area.contains(p) == false)
848                                         continue;
849
850                                 u32 i = vm->m_area.index(p);
851
852                                 // Don't replace air, water, lava, or ice
853                                 content_t c = vm->m_data[i].getContent();
854                                 if (!ndef->get(c).is_ground_content || c == CONTENT_AIR ||
855                                         c == c_water_source || c == c_lava_source || c == c_ice)
856                                         continue;
857
858                                 int full_ymin = node_min.Y - MAP_BLOCKSIZE;
859                                 int full_ymax = node_max.Y + MAP_BLOCKSIZE;
860
861                                 if (flooded && full_ymin < water_level && full_ymax > water_level)
862                                         vm->m_data[i] = (p.Y <= water_level) ? waternode : airnode;
863                                 else if (flooded && full_ymax < water_level)
864                                         vm->m_data[i] = (p.Y < startp.Y - 4) ? liquidnode : airnode;
865                                 else
866                                         vm->m_data[i] = airnode;
867                         }
868                 }
869         }
870 }
871