]> git.lizzy.rs Git - dragonfireclient.git/blob - src/mapgen.cpp
Slightly improved version of mystrtok_r
[dragonfireclient.git] / src / mapgen.cpp
1 /*
2 Minetest-c55
3 Copyright (C) 2010-2011 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 "mapgen.h"
21 #include "voxel.h"
22 #include "noise.h"
23 #include "biome.h"
24 #include "mapblock.h"
25 #include "mapnode.h"
26 #include "map.h"
27 //#include "serverobject.h"
28 #include "content_sao.h"
29 #include "nodedef.h"
30 #include "content_mapnode.h" // For content_mapnode_get_new_name
31 #include "voxelalgorithms.h"
32 #include "profiler.h"
33 #include "settings.h" // For g_settings
34 #include "main.h" // For g_profiler
35 #include "treegen.h"
36
37 /////////////////// Mapgen V6 perlin noise default values
38 NoiseParams nparams_v6_def_terrain_base =
39         {-AVERAGE_MUD_AMOUNT, 20.0, v3f(250.0, 250.0, 250.0), 82341, 5, 0.6};
40 NoiseParams nparams_v6_def_terrain_higher =
41         {20.0, 16.0, v3f(500.0, 500.0, 500.0), 85039, 5, 0.6};
42 NoiseParams nparams_v6_def_steepness =
43         {0.85, 0.5, v3f(125.0, 125.0, 125.0), -932, 5, 0.7};
44 NoiseParams nparams_v6_def_height_select =
45         {0.5, 1.0, v3f(250.0, 250.0, 250.0), 4213, 5, 0.69};
46 NoiseParams nparams_v6_def_trees =
47         {0.0, 1.0, v3f(125.0, 125.0, 125.0), 2, 4, 0.66};
48 NoiseParams nparams_v6_def_mud =
49         {AVERAGE_MUD_AMOUNT, 2.0, v3f(200.0, 200.0, 200.0), 91013, 3, 0.55};
50 NoiseParams nparams_v6_def_beach =
51         {0.0, 1.0, v3f(250.0, 250.0, 250.0), 59420, 3, 0.50};
52 NoiseParams nparams_v6_def_biome =
53         {0.0, 1.0, v3f(250.0, 250.0, 250.0), 9130, 3, 0.50};
54 NoiseParams nparams_v6_def_cave =
55         {6.0, 6.0, v3f(250.0, 250.0, 250.0), 34329, 3, 0.50};
56
57
58 ///////////////////////////////////////////////////////////////////////////////
59 /////////////////////////////// Emerge Manager ////////////////////////////////
60
61
62
63 EmergeManager::EmergeManager(IGameDef *gamedef, BiomeDefManager *bdef,
64                                                          MapgenParams *mgparams) {
65         //the order of these assignments is pretty important
66         this->biomedef = bdef ? bdef : new BiomeDefManager(gamedef);
67         this->params   = mgparams;
68         this->mapgen   = NULL;
69         this->mapgen   = getMapgen();
70 }
71
72
73 EmergeManager::~EmergeManager() {
74         delete biomedef;
75         delete params;
76 }
77
78
79 Mapgen *EmergeManager::getMapgen() {
80         if (!mapgen) {
81                 /*switch (params->mg_version) {
82                         case 6:*/
83                                 mapgen = new MapgenV6(0, (MapgenV6Params *)params);
84                 /*              break;
85                         default:
86                                 errorstream << "EmergeManager: Unsupported mapgen version "
87                                         << params->mg_version << ", falling back to V6" << std::endl;
88                                 params->mg_version = 6;
89                                 mapgen = new MapgenV6(0, (MapgenV6Params *)params);
90                 }*/
91         }
92         return mapgen;
93 }
94
95
96 void EmergeManager::addBlockToQueue() {
97         //STUB
98 }
99
100
101 int EmergeManager::getGroundLevelAtPoint(v2s16 p) {
102         if (!mapgen)
103                 return 0;
104         return mapgen->getGroundLevelAtPoint(p);
105 }
106
107
108 bool EmergeManager::isBlockUnderground(v3s16 blockpos) {
109         /*
110         v2s16 p = v2s16((blockpos.X * MAP_BLOCKSIZE) + MAP_BLOCKSIZE / 2,
111                                         (blockpos.Y * MAP_BLOCKSIZE) + MAP_BLOCKSIZE / 2);
112         int ground_level = getGroundLevelAtPoint(p);
113         return blockpos.Y * (MAP_BLOCKSIZE + 1) <= min(water_level, ground_level);
114         */
115
116         //yuck, but then again, should i bother being accurate?
117         //the height of the nodes in a single block is quite variable
118         return blockpos.Y * (MAP_BLOCKSIZE + 1) <= params->water_level;
119 }
120
121
122 u32 EmergeManager::getBlockSeed(v3s16 p) {
123         return (u32)(params->seed & 0xFFFFFFFF) +
124                 p.Z * 38134234 +
125                 p.Y * 42123 +
126                 p.Y * 23;
127 }
128
129
130 MapgenParams *MapgenParams::createMapgenParams(std::string &mgstr) {
131         return new MapgenV6Params(); // this will be fixed later
132         /*switch (mgver) {
133                 case 6:
134                         return new MapgenV6Params();
135                 default: //instead of complaining, default to 6
136                         return new MapgenV6Params();
137         }*/
138 }
139
140
141 MapgenParams *MapgenParams::getParamsFromSettings(Settings *settings) {
142         std::string mg_name = settings->get("mg_name");
143         MapgenParams *mgparams = MapgenParams::createMapgenParams(mg_name);
144         mgparams->mg_name     = mg_name;
145         mgparams->seed        = settings->getU64(settings == g_settings ? "fixed_map_seed" : "seed");
146         mgparams->water_level = settings->getS16("water_level");
147         mgparams->chunksize   = settings->getS16("chunksize");
148         mgparams->flags       = settings->getS32("mg_flags");
149
150 /*      switch (mg_version) {
151                 case 6:
152                 {*/
153                         MapgenV6Params *v6params = (MapgenV6Params *)mgparams;
154
155                         v6params->freq_desert = settings->getFloat("mgv6_freq_desert");
156                         v6params->freq_beach  = settings->getFloat("mgv6_freq_beach");
157                         v6params->np_terrain_base   = settings->getNoiseParams("mgv6_np_terrain_base");
158                         v6params->np_terrain_higher = settings->getNoiseParams("mgv6_np_terrain_higher");
159                         v6params->np_steepness      = settings->getNoiseParams("mgv6_np_steepness");
160                         v6params->np_height_select  = settings->getNoiseParams("mgv6_np_height_select");
161                         v6params->np_trees          = settings->getNoiseParams("mgv6_np_trees");
162                         v6params->np_mud            = settings->getNoiseParams("mgv6_np_mud");
163                         v6params->np_beach          = settings->getNoiseParams("mgv6_np_beach");
164                         v6params->np_biome          = settings->getNoiseParams("mgv6_np_biome");
165                         v6params->np_cave           = settings->getNoiseParams("mgv6_np_cave");
166
167                         if (!v6params->np_terrain_base || !v6params->np_terrain_higher ||
168                                 !v6params->np_steepness    || !v6params->np_height_select  ||
169                                 !v6params->np_trees        || !v6params->np_mud            ||
170                                 !v6params->np_beach || !v6params->np_biome || !v6params->np_cave) {
171                                 delete mgparams;
172                                 return NULL;
173                         }
174 /*
175                         break;
176                 }
177                 default:
178                         delete mgparams;
179                         return NULL;
180         }*/
181
182         return mgparams;
183
184 }
185
186
187 /////////////////////////////////// legacy static functions for farmesh
188
189
190 s16 Mapgen::find_ground_level_from_noise(u64 seed, v2s16 p2d, s16 precision) {
191         //just need to return something
192         s16 level = 5;
193         return level;
194 }
195
196
197 bool Mapgen::get_have_beach(u64 seed, v2s16 p2d) {
198         double sandnoise = noise2d_perlin(
199                         0.2+(float)p2d.X/250, 0.7+(float)p2d.Y/250,
200                         seed+59420, 3, 0.50);
201
202         return (sandnoise > 0.15);
203 }
204
205
206 double Mapgen::tree_amount_2d(u64 seed, v2s16 p) {
207         double noise = noise2d_perlin(
208                         0.5+(float)p.X/125, 0.5+(float)p.Y/125,
209                         seed+2, 4, 0.66);
210         double zeroval = -0.39;
211         if(noise < zeroval)
212                 return 0;
213         else
214                 return 0.04 * (noise-zeroval) / (1.0-zeroval);
215 }
216
217
218 #if 0 /// BIG COMMENT
219 namespace mapgen
220 {
221
222 /*
223         Some helper functions for the map generator
224 */
225
226 #if 1
227 // Returns Y one under area minimum if not found
228 static s16 find_ground_level(VoxelManipulator &vmanip, v2s16 p2d,
229                 INodeDefManager *ndef)
230 {
231         v3s16 em = vmanip.m_area.getExtent();
232         s16 y_nodes_max = vmanip.m_area.MaxEdge.Y;
233         s16 y_nodes_min = vmanip.m_area.MinEdge.Y;
234         u32 i = vmanip.m_area.index(v3s16(p2d.X, y_nodes_max, p2d.Y));
235         s16 y;
236         for(y=y_nodes_max; y>=y_nodes_min; y--)
237         {
238                 MapNode &n = vmanip.m_data[i];
239                 if(ndef->get(n).walkable)
240                         break;
241
242                 vmanip.m_area.add_y(em, i, -1);
243         }
244         if(y >= y_nodes_min)
245                 return y;
246         else
247                 return y_nodes_min - 1;
248 }
249
250 #if 0
251 // Returns Y one under area minimum if not found
252 static s16 find_ground_level_clever(VoxelManipulator &vmanip, v2s16 p2d,
253                 INodeDefManager *ndef)
254 {
255         if(!vmanip.m_area.contains(v3s16(p2d.X, vmanip.m_area.MaxEdge.Y, p2d.Y)))
256                 return vmanip.m_area.MinEdge.Y-1;
257         v3s16 em = vmanip.m_area.getExtent();
258         s16 y_nodes_max = vmanip.m_area.MaxEdge.Y;
259         s16 y_nodes_min = vmanip.m_area.MinEdge.Y;
260         u32 i = vmanip.m_area.index(v3s16(p2d.X, y_nodes_max, p2d.Y));
261         s16 y;
262         content_t c_tree = ndef->getId("mapgen_tree");
263         content_t c_leaves = ndef->getId("mapgen_leaves");
264         for(y=y_nodes_max; y>=y_nodes_min; y--)
265         {
266                 MapNode &n = vmanip.m_data[i];
267                 if(ndef->get(n).walkable
268                                 && n.getContent() != c_tree
269                                 && n.getContent() != c_leaves)
270                         break;
271
272                 vmanip.m_area.add_y(em, i, -1);
273         }
274         if(y >= y_nodes_min)
275                 return y;
276         else
277                 return y_nodes_min - 1;
278 }
279 #endif
280
281 // Returns Y one under area minimum if not found
282 static s16 find_stone_level(VoxelManipulator &vmanip, v2s16 p2d,
283                 INodeDefManager *ndef)
284 {
285         v3s16 em = vmanip.m_area.getExtent();
286         s16 y_nodes_max = vmanip.m_area.MaxEdge.Y;
287         s16 y_nodes_min = vmanip.m_area.MinEdge.Y;
288         u32 i = vmanip.m_area.index(v3s16(p2d.X, y_nodes_max, p2d.Y));
289         s16 y;
290         content_t c_stone = ndef->getId("mapgen_stone");
291         content_t c_desert_stone = ndef->getId("mapgen_desert_stone");
292         for(y=y_nodes_max; y>=y_nodes_min; y--)
293         {
294                 MapNode &n = vmanip.m_data[i];
295                 content_t c = n.getContent();
296                 if(c != CONTENT_IGNORE && (
297                                 c == c_stone || c == c_desert_stone))
298                         break;
299
300                 vmanip.m_area.add_y(em, i, -1);
301         }
302         if(y >= y_nodes_min)
303                 return y;
304         else
305                 return y_nodes_min - 1;
306 }
307 #endif
308
309
310 #if 0
311
312 static void make_papyrus(VoxelManipulator &vmanip, v3s16 p0,
313                 INodeDefManager *ndef)
314 {
315         MapNode papyrusnode(ndef->getId("mapgen_papyrus"));
316
317         s16 trunk_h = myrand_range(2, 3);
318         v3s16 p1 = p0;
319         for(s16 ii=0; ii<trunk_h; ii++)
320         {
321                 if(vmanip.m_area.contains(p1))
322                         vmanip.m_data[vmanip.m_area.index(p1)] = papyrusnode;
323                 p1.Y++;
324         }
325 }
326
327 static void make_cactus(VoxelManipulator &vmanip, v3s16 p0,
328                 INodeDefManager *ndef)
329 {
330         MapNode cactusnode(ndef->getId("mapgen_cactus"));
331
332         s16 trunk_h = 3;
333         v3s16 p1 = p0;
334         for(s16 ii=0; ii<trunk_h; ii++)
335         {
336                 if(vmanip.m_area.contains(p1))
337                         vmanip.m_data[vmanip.m_area.index(p1)] = cactusnode;
338                 p1.Y++;
339         }
340 }
341 #endif
342
343 #if 0
344 /*
345         Dungeon making routines
346 */
347
348 #define VMANIP_FLAG_DUNGEON_INSIDE VOXELFLAG_CHECKED1
349 #define VMANIP_FLAG_DUNGEON_PRESERVE VOXELFLAG_CHECKED2
350 #define VMANIP_FLAG_DUNGEON_UNTOUCHABLE (\
351                 VMANIP_FLAG_DUNGEON_INSIDE|VMANIP_FLAG_DUNGEON_PRESERVE)
352
353 static void make_room1(VoxelManipulator &vmanip, v3s16 roomsize, v3s16 roomplace,
354                 INodeDefManager *ndef)
355 {
356         // Make +-X walls
357         for(s16 z=0; z<roomsize.Z; z++)
358         for(s16 y=0; y<roomsize.Y; y++)
359         {
360                 {
361                         v3s16 p = roomplace + v3s16(0,y,z);
362                         if(vmanip.m_area.contains(p) == false)
363                                 continue;
364                         u32 vi = vmanip.m_area.index(p);
365                         if(vmanip.m_flags[vi] & VMANIP_FLAG_DUNGEON_UNTOUCHABLE)
366                                 continue;
367                         vmanip.m_data[vi] = MapNode(ndef->getId("mapgen_cobble"));
368                 }
369                 {
370                         v3s16 p = roomplace + v3s16(roomsize.X-1,y,z);
371                         if(vmanip.m_area.contains(p) == false)
372                                 continue;
373                         u32 vi = vmanip.m_area.index(p);
374                         if(vmanip.m_flags[vi] & VMANIP_FLAG_DUNGEON_UNTOUCHABLE)
375                                 continue;
376                         vmanip.m_data[vi] = MapNode(ndef->getId("mapgen_cobble"));
377                 }
378         }
379
380         // Make +-Z walls
381         for(s16 x=0; x<roomsize.X; x++)
382         for(s16 y=0; y<roomsize.Y; y++)
383         {
384                 {
385                         v3s16 p = roomplace + v3s16(x,y,0);
386                         if(vmanip.m_area.contains(p) == false)
387                                 continue;
388                         u32 vi = vmanip.m_area.index(p);
389                         if(vmanip.m_flags[vi] & VMANIP_FLAG_DUNGEON_UNTOUCHABLE)
390                                 continue;
391                         vmanip.m_data[vi] = MapNode(ndef->getId("mapgen_cobble"));
392                 }
393                 {
394                         v3s16 p = roomplace + v3s16(x,y,roomsize.Z-1);
395                         if(vmanip.m_area.contains(p) == false)
396                                 continue;
397                         u32 vi = vmanip.m_area.index(p);
398                         if(vmanip.m_flags[vi] & VMANIP_FLAG_DUNGEON_UNTOUCHABLE)
399                                 continue;
400                         vmanip.m_data[vi] = MapNode(ndef->getId("mapgen_cobble"));
401                 }
402         }
403
404         // Make +-Y walls (floor and ceiling)
405         for(s16 z=0; z<roomsize.Z; z++)
406         for(s16 x=0; x<roomsize.X; x++)
407         {
408                 {
409                         v3s16 p = roomplace + v3s16(x,0,z);
410                         if(vmanip.m_area.contains(p) == false)
411                                 continue;
412                         u32 vi = vmanip.m_area.index(p);
413                         if(vmanip.m_flags[vi] & VMANIP_FLAG_DUNGEON_UNTOUCHABLE)
414                                 continue;
415                         vmanip.m_data[vi] = MapNode(ndef->getId("mapgen_cobble"));
416                 }
417                 {
418                         v3s16 p = roomplace + v3s16(x,roomsize.Y-1,z);
419                         if(vmanip.m_area.contains(p) == false)
420                                 continue;
421                         u32 vi = vmanip.m_area.index(p);
422                         if(vmanip.m_flags[vi] & VMANIP_FLAG_DUNGEON_UNTOUCHABLE)
423                                 continue;
424                         vmanip.m_data[vi] = MapNode(ndef->getId("mapgen_cobble"));
425                 }
426         }
427
428         // Fill with air
429         for(s16 z=1; z<roomsize.Z-1; z++)
430         for(s16 y=1; y<roomsize.Y-1; y++)
431         for(s16 x=1; x<roomsize.X-1; x++)
432         {
433                 v3s16 p = roomplace + v3s16(x,y,z);
434                 if(vmanip.m_area.contains(p) == false)
435                         continue;
436                 u32 vi = vmanip.m_area.index(p);
437                 vmanip.m_flags[vi] |= VMANIP_FLAG_DUNGEON_UNTOUCHABLE;
438                 vmanip.m_data[vi] = MapNode(CONTENT_AIR);
439         }
440 }
441
442 static void make_fill(VoxelManipulator &vmanip, v3s16 place, v3s16 size,
443                 u8 avoid_flags, MapNode n, u8 or_flags)
444 {
445         for(s16 z=0; z<size.Z; z++)
446         for(s16 y=0; y<size.Y; y++)
447         for(s16 x=0; x<size.X; x++)
448         {
449                 v3s16 p = place + v3s16(x,y,z);
450                 if(vmanip.m_area.contains(p) == false)
451                         continue;
452                 u32 vi = vmanip.m_area.index(p);
453                 if(vmanip.m_flags[vi] & avoid_flags)
454                         continue;
455                 vmanip.m_flags[vi] |= or_flags;
456                 vmanip.m_data[vi] = n;
457         }
458 }
459
460 static void make_hole1(VoxelManipulator &vmanip, v3s16 place,
461                 INodeDefManager *ndef)
462 {
463         make_fill(vmanip, place, v3s16(1,2,1), 0, MapNode(CONTENT_AIR),
464                         VMANIP_FLAG_DUNGEON_INSIDE);
465 }
466
467 static void make_door1(VoxelManipulator &vmanip, v3s16 doorplace, v3s16 doordir,
468                 INodeDefManager *ndef)
469 {
470         make_hole1(vmanip, doorplace, ndef);
471         // Place torch (for testing)
472         //vmanip.m_data[vmanip.m_area.index(doorplace)] = MapNode(ndef->getId("mapgen_torch"));
473 }
474
475 static v3s16 rand_ortho_dir(PseudoRandom &random)
476 {
477         if(random.next()%2==0)
478                 return random.next()%2 ? v3s16(-1,0,0) : v3s16(1,0,0);
479         else
480                 return random.next()%2 ? v3s16(0,0,-1) : v3s16(0,0,1);
481 }
482
483 static v3s16 turn_xz(v3s16 olddir, int t)
484 {
485         v3s16 dir;
486         if(t == 0)
487         {
488                 // Turn right
489                 dir.X = olddir.Z;
490                 dir.Z = -olddir.X;
491                 dir.Y = olddir.Y;
492         }
493         else
494         {
495                 // Turn left
496                 dir.X = -olddir.Z;
497                 dir.Z = olddir.X;
498                 dir.Y = olddir.Y;
499         }
500         return dir;
501 }
502
503 static v3s16 random_turn(PseudoRandom &random, v3s16 olddir)
504 {
505         int turn = random.range(0,2);
506         v3s16 dir;
507         if(turn == 0)
508         {
509                 // Go straight
510                 dir = olddir;
511         }
512         else if(turn == 1)
513                 // Turn right
514                 dir = turn_xz(olddir, 0);
515         else
516                 // Turn left
517                 dir = turn_xz(olddir, 1);
518         return dir;
519 }
520
521 static void make_corridor(VoxelManipulator &vmanip, v3s16 doorplace,
522                 v3s16 doordir, v3s16 &result_place, v3s16 &result_dir,
523                 PseudoRandom &random, INodeDefManager *ndef)
524 {
525         make_hole1(vmanip, doorplace, ndef);
526         v3s16 p0 = doorplace;
527         v3s16 dir = doordir;
528         u32 length;
529         if(random.next()%2)
530                 length = random.range(1,13);
531         else
532                 length = random.range(1,6);
533         length = random.range(1,13);
534         u32 partlength = random.range(1,13);
535         u32 partcount = 0;
536         s16 make_stairs = 0;
537         if(random.next()%2 == 0 && partlength >= 3)
538                 make_stairs = random.next()%2 ? 1 : -1;
539         for(u32 i=0; i<length; i++)
540         {
541                 v3s16 p = p0 + dir;
542                 if(partcount != 0)
543                         p.Y += make_stairs;
544
545                 /*// If already empty
546                 if(vmanip.getNodeNoExNoEmerge(p).getContent()
547                                 == CONTENT_AIR
548                 && vmanip.getNodeNoExNoEmerge(p+v3s16(0,1,0)).getContent()
549                                 == CONTENT_AIR)
550                 {
551                 }*/
552
553                 if(vmanip.m_area.contains(p) == true
554                                 && vmanip.m_area.contains(p+v3s16(0,1,0)) == true)
555                 {
556                         if(make_stairs)
557                         {
558                                 make_fill(vmanip, p+v3s16(-1,-1,-1), v3s16(3,5,3),
559                                                 VMANIP_FLAG_DUNGEON_UNTOUCHABLE, MapNode(ndef->getId("mapgen_cobble")), 0);
560                                 make_fill(vmanip, p, v3s16(1,2,1), 0, MapNode(CONTENT_AIR),
561                                                 VMANIP_FLAG_DUNGEON_INSIDE);
562                                 make_fill(vmanip, p-dir, v3s16(1,2,1), 0, MapNode(CONTENT_AIR),
563                                                 VMANIP_FLAG_DUNGEON_INSIDE);
564                         }
565                         else
566                         {
567                                 make_fill(vmanip, p+v3s16(-1,-1,-1), v3s16(3,4,3),
568                                                 VMANIP_FLAG_DUNGEON_UNTOUCHABLE, MapNode(ndef->getId("mapgen_cobble")), 0);
569                                 make_hole1(vmanip, p, ndef);
570                                 /*make_fill(vmanip, p, v3s16(1,2,1), 0, MapNode(CONTENT_AIR),
571                                                 VMANIP_FLAG_DUNGEON_INSIDE);*/
572                         }
573
574                         p0 = p;
575                 }
576                 else
577                 {
578                         // Can't go here, turn away
579                         dir = turn_xz(dir, random.range(0,1));
580                         make_stairs = -make_stairs;
581                         partcount = 0;
582                         partlength = random.range(1,length);
583                         continue;
584                 }
585
586                 partcount++;
587                 if(partcount >= partlength)
588                 {
589                         partcount = 0;
590
591                         dir = random_turn(random, dir);
592
593                         partlength = random.range(1,length);
594
595                         make_stairs = 0;
596                         if(random.next()%2 == 0 && partlength >= 3)
597                                 make_stairs = random.next()%2 ? 1 : -1;
598                 }
599         }
600         result_place = p0;
601         result_dir = dir;
602 }
603
604 class RoomWalker
605 {
606 public:
607
608         RoomWalker(VoxelManipulator &vmanip_, v3s16 pos, PseudoRandom &random,
609                         INodeDefManager *ndef):
610                         vmanip(vmanip_),
611                         m_pos(pos),
612                         m_random(random),
613                         m_ndef(ndef)
614         {
615                 randomizeDir();
616         }
617
618         void randomizeDir()
619         {
620                 m_dir = rand_ortho_dir(m_random);
621         }
622
623         void setPos(v3s16 pos)
624         {
625                 m_pos = pos;
626         }
627
628         void setDir(v3s16 dir)
629         {
630                 m_dir = dir;
631         }
632
633         bool findPlaceForDoor(v3s16 &result_place, v3s16 &result_dir)
634         {
635                 for(u32 i=0; i<100; i++)
636                 {
637                         v3s16 p = m_pos + m_dir;
638                         v3s16 p1 = p + v3s16(0,1,0);
639                         if(vmanip.m_area.contains(p) == false
640                                         || vmanip.m_area.contains(p1) == false
641                                         || i % 4 == 0)
642                         {
643                                 randomizeDir();
644                                 continue;
645                         }
646                         if(vmanip.getNodeNoExNoEmerge(p).getContent()
647                                         == m_ndef->getId("mapgen_cobble")
648                         && vmanip.getNodeNoExNoEmerge(p1).getContent()
649                                         == m_ndef->getId("mapgen_cobble"))
650                         {
651                                 // Found wall, this is a good place!
652                                 result_place = p;
653                                 result_dir = m_dir;
654                                 // Randomize next direction
655                                 randomizeDir();
656                                 return true;
657                         }
658                         /*
659                                 Determine where to move next
660                         */
661                         // Jump one up if the actual space is there
662                         if(vmanip.getNodeNoExNoEmerge(p+v3s16(0,0,0)).getContent()
663                                         == m_ndef->getId("mapgen_cobble")
664                         && vmanip.getNodeNoExNoEmerge(p+v3s16(0,1,0)).getContent()
665                                         == CONTENT_AIR
666                         && vmanip.getNodeNoExNoEmerge(p+v3s16(0,2,0)).getContent()
667                                         == CONTENT_AIR)
668                                 p += v3s16(0,1,0);
669                         // Jump one down if the actual space is there
670                         if(vmanip.getNodeNoExNoEmerge(p+v3s16(0,1,0)).getContent()
671                                         == m_ndef->getId("mapgen_cobble")
672                         && vmanip.getNodeNoExNoEmerge(p+v3s16(0,0,0)).getContent()
673                                         == CONTENT_AIR
674                         && vmanip.getNodeNoExNoEmerge(p+v3s16(0,-1,0)).getContent()
675                                         == CONTENT_AIR)
676                                 p += v3s16(0,-1,0);
677                         // Check if walking is now possible
678                         if(vmanip.getNodeNoExNoEmerge(p).getContent()
679                                         != CONTENT_AIR
680                         || vmanip.getNodeNoExNoEmerge(p+v3s16(0,1,0)).getContent()
681                                         != CONTENT_AIR)
682                         {
683                                 // Cannot continue walking here
684                                 randomizeDir();
685                                 continue;
686                         }
687                         // Move there
688                         m_pos = p;
689                 }
690                 return false;
691         }
692
693         bool findPlaceForRoomDoor(v3s16 roomsize, v3s16 &result_doorplace,
694                         v3s16 &result_doordir, v3s16 &result_roomplace)
695         {
696                 for(s16 trycount=0; trycount<30; trycount++)
697                 {
698                         v3s16 doorplace;
699                         v3s16 doordir;
700                         bool r = findPlaceForDoor(doorplace, doordir);
701                         if(r == false)
702                                 continue;
703                         v3s16 roomplace;
704                         // X east, Z north, Y up
705 #if 1
706                         if(doordir == v3s16(1,0,0)) // X+
707                                 roomplace = doorplace +
708                                                 v3s16(0,-1,m_random.range(-roomsize.Z+2,-2));
709                         if(doordir == v3s16(-1,0,0)) // X-
710                                 roomplace = doorplace +
711                                                 v3s16(-roomsize.X+1,-1,m_random.range(-roomsize.Z+2,-2));
712                         if(doordir == v3s16(0,0,1)) // Z+
713                                 roomplace = doorplace +
714                                                 v3s16(m_random.range(-roomsize.X+2,-2),-1,0);
715                         if(doordir == v3s16(0,0,-1)) // Z-
716                                 roomplace = doorplace +
717                                                 v3s16(m_random.range(-roomsize.X+2,-2),-1,-roomsize.Z+1);
718 #endif
719 #if 0
720                         if(doordir == v3s16(1,0,0)) // X+
721                                 roomplace = doorplace + v3s16(0,-1,-roomsize.Z/2);
722                         if(doordir == v3s16(-1,0,0)) // X-
723                                 roomplace = doorplace + v3s16(-roomsize.X+1,-1,-roomsize.Z/2);
724                         if(doordir == v3s16(0,0,1)) // Z+
725                                 roomplace = doorplace + v3s16(-roomsize.X/2,-1,0);
726                         if(doordir == v3s16(0,0,-1)) // Z-
727                                 roomplace = doorplace + v3s16(-roomsize.X/2,-1,-roomsize.Z+1);
728 #endif
729
730                         // Check fit
731                         bool fits = true;
732                         for(s16 z=1; z<roomsize.Z-1; z++)
733                         for(s16 y=1; y<roomsize.Y-1; y++)
734                         for(s16 x=1; x<roomsize.X-1; x++)
735                         {
736                                 v3s16 p = roomplace + v3s16(x,y,z);
737                                 if(vmanip.m_area.contains(p) == false)
738                                 {
739                                         fits = false;
740                                         break;
741                                 }
742                                 if(vmanip.m_flags[vmanip.m_area.index(p)]
743                                                 & VMANIP_FLAG_DUNGEON_INSIDE)
744                                 {
745                                         fits = false;
746                                         break;
747                                 }
748                         }
749                         if(fits == false)
750                         {
751                                 // Find new place
752                                 continue;
753                         }
754                         result_doorplace = doorplace;
755                         result_doordir = doordir;
756                         result_roomplace = roomplace;
757                         return true;
758                 }
759                 return false;
760         }
761
762 private:
763         VoxelManipulator &vmanip;
764         v3s16 m_pos;
765         v3s16 m_dir;
766         PseudoRandom &m_random;
767         INodeDefManager *m_ndef;
768 };
769
770 static void make_dungeon1(VoxelManipulator &vmanip, PseudoRandom &random,
771                 INodeDefManager *ndef)
772 {
773         v3s16 areasize = vmanip.m_area.getExtent();
774         v3s16 roomsize;
775         v3s16 roomplace;
776
777         /*
778                 Find place for first room
779         */
780         bool fits = false;
781         for(u32 i=0; i<100; i++)
782         {
783                 roomsize = v3s16(random.range(4,8),random.range(4,6),random.range(4,8));
784                 roomplace = vmanip.m_area.MinEdge + v3s16(
785                                 random.range(0,areasize.X-roomsize.X-1),
786                                 random.range(0,areasize.Y-roomsize.Y-1),
787                                 random.range(0,areasize.Z-roomsize.Z-1));
788                 /*
789                         Check that we're not putting the room to an unknown place,
790                         otherwise it might end up floating in the air
791                 */
792                 fits = true;
793                 for(s16 z=1; z<roomsize.Z-1; z++)
794                 for(s16 y=1; y<roomsize.Y-1; y++)
795                 for(s16 x=1; x<roomsize.X-1; x++)
796                 {
797                         v3s16 p = roomplace + v3s16(x,y,z);
798                         u32 vi = vmanip.m_area.index(p);
799                         if(vmanip.m_flags[vi] & VMANIP_FLAG_DUNGEON_INSIDE)
800                         {
801                                 fits = false;
802                                 break;
803                         }
804                         if(vmanip.m_data[vi].getContent() == CONTENT_IGNORE)
805                         {
806                                 fits = false;
807                                 break;
808                         }
809                 }
810                 if(fits)
811                         break;
812         }
813         // No place found
814         if(fits == false)
815                 return;
816
817         /*
818                 Stores the center position of the last room made, so that
819                 a new corridor can be started from the last room instead of
820                 the new room, if chosen so.
821         */
822         v3s16 last_room_center = roomplace+v3s16(roomsize.X/2,1,roomsize.Z/2);
823
824         u32 room_count = random.range(2,7);
825         for(u32 i=0; i<room_count; i++)
826         {
827                 // Make a room to the determined place
828                 make_room1(vmanip, roomsize, roomplace, ndef);
829
830                 v3s16 room_center = roomplace + v3s16(roomsize.X/2,1,roomsize.Z/2);
831
832                 // Place torch at room center (for testing)
833                 //vmanip.m_data[vmanip.m_area.index(room_center)] = MapNode(ndef->getId("mapgen_torch"));
834
835                 // Quit if last room
836                 if(i == room_count-1)
837                         break;
838
839                 // Determine walker start position
840
841                 bool start_in_last_room = (random.range(0,2)!=0);
842                 //bool start_in_last_room = true;
843
844                 v3s16 walker_start_place;
845
846                 if(start_in_last_room)
847                 {
848                         walker_start_place = last_room_center;
849                 }
850                 else
851                 {
852                         walker_start_place = room_center;
853                         // Store center of current room as the last one
854                         last_room_center = room_center;
855                 }
856
857                 // Create walker and find a place for a door
858                 RoomWalker walker(vmanip, walker_start_place, random, ndef);
859                 v3s16 doorplace;
860                 v3s16 doordir;
861                 bool r = walker.findPlaceForDoor(doorplace, doordir);
862                 if(r == false)
863                         return;
864
865                 if(random.range(0,1)==0)
866                         // Make the door
867                         make_door1(vmanip, doorplace, doordir, ndef);
868                 else
869                         // Don't actually make a door
870                         doorplace -= doordir;
871
872                 // Make a random corridor starting from the door
873                 v3s16 corridor_end;
874                 v3s16 corridor_end_dir;
875                 make_corridor(vmanip, doorplace, doordir, corridor_end,
876                                 corridor_end_dir, random, ndef);
877
878                 // Find a place for a random sized room
879                 roomsize = v3s16(random.range(4,8),random.range(4,6),random.range(4,8));
880                 walker.setPos(corridor_end);
881                 walker.setDir(corridor_end_dir);
882                 r = walker.findPlaceForRoomDoor(roomsize, doorplace, doordir, roomplace);
883                 if(r == false)
884                         return;
885
886                 if(random.range(0,1)==0)
887                         // Make the door
888                         make_door1(vmanip, doorplace, doordir, ndef);
889                 else
890                         // Don't actually make a door
891                         roomplace -= doordir;
892
893         }
894 }
895 #endif
896
897 #if 0
898 static void make_nc(VoxelManipulator &vmanip, PseudoRandom &random,
899                 INodeDefManager *ndef)
900 {
901         v3s16 dir;
902         u8 facedir_i = 0;
903         s32 r = random.range(0, 3);
904         if(r == 0){
905                 dir = v3s16( 1, 0, 0);
906                 facedir_i = 3;
907         }
908         if(r == 1){
909                 dir = v3s16(-1, 0, 0);
910                 facedir_i = 1;
911         }
912         if(r == 2){
913                 dir = v3s16( 0, 0, 1);
914                 facedir_i = 2;
915         }
916         if(r == 3){
917                 dir = v3s16( 0, 0,-1);
918                 facedir_i = 0;
919         }
920         v3s16 p = vmanip.m_area.MinEdge + v3s16(
921                         16+random.range(0,15),
922                         16+random.range(0,15),
923                         16+random.range(0,15));
924         vmanip.m_data[vmanip.m_area.index(p)] = MapNode(ndef->getId("mapgen_nyancat"), facedir_i);
925         u32 length = random.range(3,15);
926         for(u32 j=0; j<length; j++)
927         {
928                 p -= dir;
929                 vmanip.m_data[vmanip.m_area.index(p)] = MapNode(ndef->getId("mapgen_nyancat_rainbow"));
930         }
931 }
932 #endif
933
934 /*
935         Noise functions. Make sure seed is mangled differently in each one.
936 */
937
938 #if 0
939 /*
940         Scaling the output of the noise function affects the overdrive of the
941         contour function, which affects the shape of the output considerably.
942 */
943 #define CAVE_NOISE_SCALE 12.0
944 //#define CAVE_NOISE_SCALE 10.0
945 //#define CAVE_NOISE_SCALE 7.5
946 //#define CAVE_NOISE_SCALE 5.0
947 //#define CAVE_NOISE_SCALE 1.0
948
949 //#define CAVE_NOISE_THRESHOLD (2.5/CAVE_NOISE_SCALE)
950 #define CAVE_NOISE_THRESHOLD (1.5/CAVE_NOISE_SCALE)
951
952 NoiseParams get_cave_noise1_params(u64 seed)
953 {
954         /*return NoiseParams(NOISE_PERLIN_CONTOUR, seed+52534, 5, 0.7,
955                         200, CAVE_NOISE_SCALE);*/
956         /*return NoiseParams(NOISE_PERLIN_CONTOUR, seed+52534, 4, 0.7,
957                         100, CAVE_NOISE_SCALE);*/
958         /*return NoiseParams(NOISE_PERLIN_CONTOUR, seed+52534, 5, 0.6,
959                         100, CAVE_NOISE_SCALE);*/
960         /*return NoiseParams(NOISE_PERLIN_CONTOUR, seed+52534, 5, 0.3,
961                         100, CAVE_NOISE_SCALE);*/
962         return NoiseParams(NOISE_PERLIN_CONTOUR, seed+52534, 4, 0.5,
963                         50, CAVE_NOISE_SCALE);
964         //return NoiseParams(NOISE_CONSTANT_ONE);
965 }
966
967 NoiseParams get_cave_noise2_params(u64 seed)
968 {
969         /*return NoiseParams(NOISE_PERLIN_CONTOUR_FLIP_YZ, seed+10325, 5, 0.7,
970                         200, CAVE_NOISE_SCALE);*/
971         /*return NoiseParams(NOISE_PERLIN_CONTOUR_FLIP_YZ, seed+10325, 4, 0.7,
972                         100, CAVE_NOISE_SCALE);*/
973         /*return NoiseParams(NOISE_PERLIN_CONTOUR_FLIP_YZ, seed+10325, 5, 0.3,
974                         100, CAVE_NOISE_SCALE);*/
975         return NoiseParams(NOISE_PERLIN_CONTOUR_FLIP_YZ, seed+10325, 4, 0.5,
976                         50, CAVE_NOISE_SCALE);
977         //return NoiseParams(NOISE_CONSTANT_ONE);
978 }
979
980 NoiseParams get_ground_noise1_params(u64 seed)
981 {
982         return NoiseParams(NOISE_PERLIN, seed+983240, 4,
983                         0.55, 80.0, 40.0);
984 }
985
986 NoiseParams get_ground_crumbleness_params(u64 seed)
987 {
988         return NoiseParams(NOISE_PERLIN, seed+34413, 3,
989                         1.3, 20.0, 1.0);
990 }
991
992 NoiseParams get_ground_wetness_params(u64 seed)
993 {
994         return NoiseParams(NOISE_PERLIN, seed+32474, 4,
995                         1.1, 40.0, 1.0);
996 }
997
998 bool is_cave(u64 seed, v3s16 p)
999 {
1000         double d1 = noise3d_param(get_cave_noise1_params(seed), p.X,p.Y,p.Z);
1001         double d2 = noise3d_param(get_cave_noise2_params(seed), p.X,p.Y,p.Z);
1002         return d1*d2 > CAVE_NOISE_THRESHOLD;
1003 }
1004
1005 /*
1006         Ground density noise shall be interpreted by using this.
1007
1008         TODO: No perlin noises here, they should be outsourced
1009               and buffered
1010                   NOTE: The speed of these actually isn't terrible
1011 */
1012 bool val_is_ground(double ground_noise1_val, v3s16 p, u64 seed)
1013 {
1014         //return ((double)p.Y < ground_noise1_val);
1015
1016         double f = 0.55 + noise2d_perlin(
1017                         0.5+(float)p.X/250, 0.5+(float)p.Z/250,
1018                         seed+920381, 3, 0.45);
1019         if(f < 0.01)
1020                 f = 0.01;
1021         else if(f >= 1.0)
1022                 f *= 1.6;
1023         double h = WATER_LEVEL + 10 * noise2d_perlin(
1024                         0.5+(float)p.X/250, 0.5+(float)p.Z/250,
1025                         seed+84174, 4, 0.5);
1026         /*double f = 1;
1027         double h = 0;*/
1028         return ((double)p.Y - h < ground_noise1_val * f);
1029 }
1030
1031 /*
1032         Queries whether a position is ground or not.
1033 */
1034 bool is_ground(u64 seed, v3s16 p)
1035 {
1036         double val1 = noise3d_param(get_ground_noise1_params(seed), p.X,p.Y,p.Z);
1037         return val_is_ground(val1, p, seed);
1038 }
1039 #endif
1040
1041 // Amount of trees per area in nodes
1042 double tree_amount_2d(u64 seed, v2s16 p)
1043 {
1044         /*double noise = noise2d_perlin(
1045                         0.5+(float)p.X/250, 0.5+(float)p.Y/250,
1046                         seed+2, 5, 0.66);*/
1047         double noise = noise2d_perlin(
1048                         0.5+(float)p.X/125, 0.5+(float)p.Y/125,
1049                         seed+2, 4, 0.66);
1050         double zeroval = -0.39;
1051         if(noise < zeroval)
1052                 return 0;
1053         else
1054                 return 0.04 * (noise-zeroval) / (1.0-zeroval);
1055 }
1056
1057 #if 0
1058 double surface_humidity_2d(u64 seed, v2s16 p)
1059 {
1060         double noise = noise2d_perlin(
1061                         0.5+(float)p.X/500, 0.5+(float)p.Y/500,
1062                         seed+72384, 4, 0.66);
1063         noise = (noise + 1.0)/2.0;
1064         if(noise < 0.0)
1065                 noise = 0.0;
1066         if(noise > 1.0)
1067                 noise = 1.0;
1068         return noise;
1069 }
1070
1071 /*
1072         Incrementally find ground level from 3d noise
1073 */
1074 s16 find_ground_level_from_noise(u64 seed, v2s16 p2d, s16 precision)
1075 {
1076         // Start a bit fuzzy to make averaging lower precision values
1077         // more useful
1078         s16 level = myrand_range(-precision/2, precision/2);
1079         s16 dec[] = {31000, 100, 20, 4, 1, 0};
1080         s16 i;
1081         for(i = 1; dec[i] != 0 && precision <= dec[i]; i++)
1082         {
1083                 // First find non-ground by going upwards
1084                 // Don't stop in caves.
1085                 {
1086                         s16 max = level+dec[i-1]*2;
1087                         v3s16 p(p2d.X, level, p2d.Y);
1088                         for(; p.Y < max; p.Y += dec[i])
1089                         {
1090                                 if(!is_ground(seed, p))
1091                                 {
1092                                         level = p.Y;
1093                                         break;
1094                                 }
1095                         }
1096                 }
1097                 // Then find ground by going downwards from there.
1098                 // Go in caves, too, when precision is 1.
1099                 {
1100                         s16 min = level-dec[i-1]*2;
1101                         v3s16 p(p2d.X, level, p2d.Y);
1102                         for(; p.Y>min; p.Y-=dec[i])
1103                         {
1104                                 bool ground = is_ground(seed, p);
1105                                 /*if(dec[i] == 1 && is_cave(seed, p))
1106                                         ground = false;*/
1107                                 if(ground)
1108                                 {
1109                                         level = p.Y;
1110                                         break;
1111                                 }
1112                         }
1113                 }
1114         }
1115
1116         // This is more like the actual ground level
1117         level += dec[i-1]/2;
1118
1119         return level;
1120 }
1121
1122 double get_sector_average_ground_level(u64 seed, v2s16 sectorpos, double p=4);
1123
1124 double get_sector_average_ground_level(u64 seed, v2s16 sectorpos, double p)
1125 {
1126         v2s16 node_min = sectorpos*MAP_BLOCKSIZE;
1127         v2s16 node_max = (sectorpos+v2s16(1,1))*MAP_BLOCKSIZE-v2s16(1,1);
1128         double a = 0;
1129         a += find_ground_level_from_noise(seed,
1130                         v2s16(node_min.X, node_min.Y), p);
1131         a += find_ground_level_from_noise(seed,
1132                         v2s16(node_min.X, node_max.Y), p);
1133         a += find_ground_level_from_noise(seed,
1134                         v2s16(node_max.X, node_max.Y), p);
1135         a += find_ground_level_from_noise(seed,
1136                         v2s16(node_max.X, node_min.Y), p);
1137         a += find_ground_level_from_noise(seed,
1138                         v2s16(node_min.X+MAP_BLOCKSIZE/2, node_min.Y+MAP_BLOCKSIZE/2), p);
1139         a /= 5;
1140         return a;
1141 }
1142
1143 double get_sector_maximum_ground_level(u64 seed, v2s16 sectorpos, double p=4);
1144
1145 double get_sector_maximum_ground_level(u64 seed, v2s16 sectorpos, double p)
1146 {
1147         v2s16 node_min = sectorpos*MAP_BLOCKSIZE;
1148         v2s16 node_max = (sectorpos+v2s16(1,1))*MAP_BLOCKSIZE-v2s16(1,1);
1149         double a = -31000;
1150         // Corners
1151         a = MYMAX(a, find_ground_level_from_noise(seed,
1152                         v2s16(node_min.X, node_min.Y), p));
1153         a = MYMAX(a, find_ground_level_from_noise(seed,
1154                         v2s16(node_min.X, node_max.Y), p));
1155         a = MYMAX(a, find_ground_level_from_noise(seed,
1156                         v2s16(node_max.X, node_max.Y), p));
1157         a = MYMAX(a, find_ground_level_from_noise(seed,
1158                         v2s16(node_min.X, node_min.Y), p));
1159         // Center
1160         a = MYMAX(a, find_ground_level_from_noise(seed,
1161                         v2s16(node_min.X+MAP_BLOCKSIZE/2, node_min.Y+MAP_BLOCKSIZE/2), p));
1162         // Side middle points
1163         a = MYMAX(a, find_ground_level_from_noise(seed,
1164                         v2s16(node_min.X+MAP_BLOCKSIZE/2, node_min.Y), p));
1165         a = MYMAX(a, find_ground_level_from_noise(seed,
1166                         v2s16(node_min.X+MAP_BLOCKSIZE/2, node_max.Y), p));
1167         a = MYMAX(a, find_ground_level_from_noise(seed,
1168                         v2s16(node_min.X, node_min.Y+MAP_BLOCKSIZE/2), p));
1169         a = MYMAX(a, find_ground_level_from_noise(seed,
1170                         v2s16(node_max.X, node_min.Y+MAP_BLOCKSIZE/2), p));
1171         return a;
1172 }
1173
1174 double get_sector_minimum_ground_level(u64 seed, v2s16 sectorpos, double p=4);
1175
1176 double get_sector_minimum_ground_level(u64 seed, v2s16 sectorpos, double p)
1177 {
1178         v2s16 node_min = sectorpos*MAP_BLOCKSIZE;
1179         v2s16 node_max = (sectorpos+v2s16(1,1))*MAP_BLOCKSIZE-v2s16(1,1);
1180         double a = 31000;
1181         // Corners
1182         a = MYMIN(a, find_ground_level_from_noise(seed,
1183                         v2s16(node_min.X, node_min.Y), p));
1184         a = MYMIN(a, find_ground_level_from_noise(seed,
1185                         v2s16(node_min.X, node_max.Y), p));
1186         a = MYMIN(a, find_ground_level_from_noise(seed,
1187                         v2s16(node_max.X, node_max.Y), p));
1188         a = MYMIN(a, find_ground_level_from_noise(seed,
1189                         v2s16(node_min.X, node_min.Y), p));
1190         // Center
1191         a = MYMIN(a, find_ground_level_from_noise(seed,
1192                         v2s16(node_min.X+MAP_BLOCKSIZE/2, node_min.Y+MAP_BLOCKSIZE/2), p));
1193         // Side middle points
1194         a = MYMIN(a, find_ground_level_from_noise(seed,
1195                         v2s16(node_min.X+MAP_BLOCKSIZE/2, node_min.Y), p));
1196         a = MYMIN(a, find_ground_level_from_noise(seed,
1197                         v2s16(node_min.X+MAP_BLOCKSIZE/2, node_max.Y), p));
1198         a = MYMIN(a, find_ground_level_from_noise(seed,
1199                         v2s16(node_min.X, node_min.Y+MAP_BLOCKSIZE/2), p));
1200         a = MYMIN(a, find_ground_level_from_noise(seed,
1201                         v2s16(node_max.X, node_min.Y+MAP_BLOCKSIZE/2), p));
1202         return a;
1203 }
1204 #endif
1205
1206 // Required by mapgen.h
1207 bool block_is_underground(u64 seed, v3s16 blockpos)
1208 {
1209         /*s16 minimum_groundlevel = (s16)get_sector_minimum_ground_level(
1210                         seed, v2s16(blockpos.X, blockpos.Z));*/
1211         // Nah, this is just a heuristic, just return something
1212         s16 minimum_groundlevel = WATER_LEVEL;
1213
1214         if(blockpos.Y*MAP_BLOCKSIZE + MAP_BLOCKSIZE <= minimum_groundlevel)
1215                 return true;
1216         else
1217                 return false;
1218 }
1219
1220 #define AVERAGE_MUD_AMOUNT 4
1221
1222 double base_rock_level_2d(u64 seed, v2s16 p)
1223 {
1224         // The base ground level
1225         double base = (double)WATER_LEVEL - (double)AVERAGE_MUD_AMOUNT
1226                         + 20. * noise2d_perlin(
1227                         0.5+(float)p.X/250., 0.5+(float)p.Y/250.,
1228                         seed+82341, 5, 0.6);
1229
1230         /*// A bit hillier one
1231         double base2 = WATER_LEVEL - 4.0 + 40. * noise2d_perlin(
1232                         0.5+(float)p.X/250., 0.5+(float)p.Y/250.,
1233                         seed+93413, 6, 0.69);
1234         if(base2 > base)
1235                 base = base2;*/
1236 #if 1
1237         // Higher ground level
1238         double higher = (double)WATER_LEVEL + 20. + 16. * noise2d_perlin(
1239                         0.5+(float)p.X/500., 0.5+(float)p.Y/500.,
1240                         seed+85039, 5, 0.6);
1241         //higher = 30; // For debugging
1242
1243         // Limit higher to at least base
1244         if(higher < base)
1245                 higher = base;
1246
1247         // Steepness factor of cliffs
1248         double b = 0.85 + 0.5 * noise2d_perlin(
1249                         0.5+(float)p.X/125., 0.5+(float)p.Y/125.,
1250                         seed-932, 5, 0.7);
1251         b = rangelim(b, 0.0, 1000.0);
1252         b = b*b*b*b*b*b*b;
1253         b *= 5;
1254         b = rangelim(b, 0.5, 1000.0);
1255         // Values 1.5...100 give quite horrible looking slopes
1256         if(b > 1.5 && b < 100.0){
1257                 if(b < 10.0)
1258                         b = 1.5;
1259                 else
1260                         b = 100.0;
1261         }
1262         //dstream<<"b="<<b<<std::endl;
1263         //double b = 20;
1264         //b = 0.25;
1265
1266         // Offset to more low
1267         double a_off = -0.20;
1268         // High/low selector
1269         /*double a = 0.5 + b * (a_off + noise2d_perlin(
1270                         0.5+(float)p.X/500., 0.5+(float)p.Y/500.,
1271                         seed+4213, 6, 0.7));*/
1272         double a = (double)0.5 + b * (a_off + noise2d_perlin(
1273                         0.5+(float)p.X/250., 0.5+(float)p.Y/250.,
1274                         seed+4213, 5, 0.69));
1275         // Limit
1276         a = rangelim(a, 0.0, 1.0);
1277
1278         //dstream<<"a="<<a<<std::endl;
1279
1280         double h = base*(1.0-a) + higher*a;
1281 #else
1282         double h = base;
1283 #endif
1284         return h;
1285 }
1286
1287 s16 find_ground_level_from_noise(u64 seed, v2s16 p2d, s16 precision)
1288 {
1289         return base_rock_level_2d(seed, p2d) + AVERAGE_MUD_AMOUNT;
1290 }
1291
1292 double get_mud_add_amount(u64 seed, v2s16 p)
1293 {
1294         return ((float)AVERAGE_MUD_AMOUNT + 2.0 * noise2d_perlin(
1295                         0.5+(float)p.X/200, 0.5+(float)p.Y/200,
1296                         seed+91013, 3, 0.55));
1297 }
1298
1299 bool get_have_beach(u64 seed, v2s16 p2d)
1300 {
1301         // Determine whether to have sand here
1302         double sandnoise = noise2d_perlin(
1303                         0.2+(float)p2d.X/250, 0.7+(float)p2d.Y/250,
1304                         seed+59420, 3, 0.50);
1305
1306         return (sandnoise > 0.15);
1307 }
1308
1309 enum BiomeType
1310 {
1311         BT_NORMAL,
1312         BT_DESERT
1313 };
1314
1315 BiomeType get_biome(u64 seed, v2s16 p2d)
1316 {
1317         // Just do something very simple as for now
1318         double d = noise2d_perlin(
1319                         0.6+(float)p2d.X/250, 0.2+(float)p2d.Y/250,
1320                         seed+9130, 3, 0.50);
1321         if(d > 0.45)
1322                 return BT_DESERT;
1323         if(d > 0.35 && (noise2d( p2d.X, p2d.Y, int(seed) ) + 1.0) > ( 0.45 - d ) * 20.0  )
1324                 return BT_DESERT;
1325         return BT_NORMAL;
1326 };
1327
1328 u32 get_blockseed(u64 seed, v3s16 p)
1329 {
1330         s32 x=p.X, y=p.Y, z=p.Z;
1331         return (u32)(seed%0x100000000ULL) + z*38134234 + y*42123 + x*23;
1332 }
1333
1334 #define VMANIP_FLAG_CAVE VOXELFLAG_CHECKED1
1335
1336 void make_block(BlockMakeData *data)
1337 {
1338         if(data->no_op)
1339         {
1340                 //dstream<<"makeBlock: no-op"<<std::endl;
1341                 return;
1342         }
1343
1344         assert(data->vmanip);
1345         assert(data->nodedef);
1346         assert(data->blockpos_requested.X >= data->blockpos_min.X &&
1347                         data->blockpos_requested.Y >= data->blockpos_min.Y &&
1348                         data->blockpos_requested.Z >= data->blockpos_min.Z);
1349         assert(data->blockpos_requested.X <= data->blockpos_max.X &&
1350                         data->blockpos_requested.Y <= data->blockpos_max.Y &&
1351                         data->blockpos_requested.Z <= data->blockpos_max.Z);
1352
1353         INodeDefManager *ndef = data->nodedef;
1354
1355         // Hack: use minimum block coordinates for old code that assumes
1356         // a single block
1357         v3s16 blockpos = data->blockpos_requested;
1358
1359         /*dstream<<"makeBlock(): ("<<blockpos.X<<","<<blockpos.Y<<","
1360                         <<blockpos.Z<<")"<<std::endl;*/
1361
1362         v3s16 blockpos_min = data->blockpos_min;
1363         v3s16 blockpos_max = data->blockpos_max;
1364         v3s16 blockpos_full_min = blockpos_min - v3s16(1,1,1);
1365         v3s16 blockpos_full_max = blockpos_max + v3s16(1,1,1);
1366
1367         ManualMapVoxelManipulator &vmanip = *(data->vmanip);
1368         // Area of central chunk
1369         v3s16 node_min = blockpos_min*MAP_BLOCKSIZE;
1370         v3s16 node_max = (blockpos_max+v3s16(1,1,1))*MAP_BLOCKSIZE-v3s16(1,1,1);
1371         // Full allocated area
1372         v3s16 full_node_min = (blockpos_min-1)*MAP_BLOCKSIZE;
1373         v3s16 full_node_max = (blockpos_max+2)*MAP_BLOCKSIZE-v3s16(1,1,1);
1374
1375         v3s16 central_area_size = node_max - node_min + v3s16(1,1,1);
1376
1377         const s16 max_spread_amount = MAP_BLOCKSIZE;
1378
1379         int volume_blocks = (blockpos_max.X - blockpos_min.X + 1)
1380                         * (blockpos_max.Y - blockpos_min.Y + 1)
1381                         * (blockpos_max.Z - blockpos_max.Z + 1);
1382
1383         int volume_nodes = volume_blocks *
1384                         MAP_BLOCKSIZE*MAP_BLOCKSIZE*MAP_BLOCKSIZE;
1385
1386         // Generated surface area
1387         //double gen_area_nodes = MAP_BLOCKSIZE*MAP_BLOCKSIZE * rel_volume;
1388
1389         // Horribly wrong heuristic, but better than nothing
1390         bool block_is_underground = (WATER_LEVEL > node_max.Y);
1391
1392         /*
1393                 Create a block-specific seed
1394         */
1395         u32 blockseed = get_blockseed(data->seed, full_node_min);
1396
1397         /*
1398                 Cache some ground type values for speed
1399         */
1400
1401 // Creates variables c_name=id and n_name=node
1402 #define CONTENT_VARIABLE(ndef, name)\
1403         content_t c_##name = ndef->getId("mapgen_" #name);\
1404         MapNode n_##name(c_##name);
1405 // Default to something else if was CONTENT_IGNORE
1406 #define CONTENT_VARIABLE_FALLBACK(name, dname)\
1407         if(c_##name == CONTENT_IGNORE){\
1408                 c_##name = c_##dname;\
1409                 n_##name = n_##dname;\
1410         }
1411
1412         CONTENT_VARIABLE(ndef, stone);
1413         CONTENT_VARIABLE(ndef, air);
1414         CONTENT_VARIABLE(ndef, water_source);
1415         CONTENT_VARIABLE(ndef, dirt);
1416         CONTENT_VARIABLE(ndef, sand);
1417         CONTENT_VARIABLE(ndef, gravel);
1418         CONTENT_VARIABLE(ndef, clay);
1419         CONTENT_VARIABLE(ndef, lava_source);
1420         CONTENT_VARIABLE(ndef, cobble);
1421         CONTENT_VARIABLE(ndef, mossycobble);
1422         CONTENT_VARIABLE(ndef, dirt_with_grass);
1423         CONTENT_VARIABLE(ndef, junglegrass);
1424         CONTENT_VARIABLE(ndef, stone_with_coal);
1425         CONTENT_VARIABLE(ndef, stone_with_iron);
1426         CONTENT_VARIABLE(ndef, mese);
1427         CONTENT_VARIABLE(ndef, desert_sand);
1428         CONTENT_VARIABLE_FALLBACK(desert_sand, sand);
1429         CONTENT_VARIABLE(ndef, desert_stone);
1430         CONTENT_VARIABLE_FALLBACK(desert_stone, stone);
1431
1432         // Maximum height of the stone surface and obstacles.
1433         // This is used to guide the cave generation
1434         s16 stone_surface_max_y = 0;
1435
1436         /*
1437                 Generate general ground level to full area
1438         */
1439         {
1440 #if 1
1441         TimeTaker timer1("Generating ground level");
1442
1443         for(s16 x=node_min.X; x<=node_max.X; x++)
1444         for(s16 z=node_min.Z; z<=node_max.Z; z++)
1445         {
1446                 // Node position
1447                 v2s16 p2d = v2s16(x,z);
1448
1449                 /*
1450                         Skip of already generated
1451                 */
1452                 /*{
1453                         v3s16 p(p2d.X, node_min.Y, p2d.Y);
1454                         if(vmanip.m_data[vmanip.m_area.index(p)].d != CONTENT_AIR)
1455                                 continue;
1456                 }*/
1457
1458                 // Ground height at this point
1459                 float surface_y_f = 0.0;
1460
1461                 // Use perlin noise for ground height
1462                 surface_y_f = base_rock_level_2d(data->seed, p2d);
1463
1464                 /*// Experimental stuff
1465                 {
1466                         float a = highlands_level_2d(data->seed, p2d);
1467                         if(a > surface_y_f)
1468                                 surface_y_f = a;
1469                 }*/
1470
1471                 // Convert to integer
1472                 s16 surface_y = (s16)surface_y_f;
1473
1474                 // Log it
1475                 if(surface_y > stone_surface_max_y)
1476                         stone_surface_max_y = surface_y;
1477
1478                 BiomeType bt = get_biome(data->seed, p2d);
1479                 /*
1480                         Fill ground with stone
1481                 */
1482                 {
1483                         // Use fast index incrementing
1484                         v3s16 em = vmanip.m_area.getExtent();
1485                         u32 i = vmanip.m_area.index(v3s16(p2d.X, node_min.Y, p2d.Y));
1486                         for(s16 y=node_min.Y; y<=node_max.Y; y++)
1487                         {
1488                                 if(vmanip.m_data[i].getContent() == CONTENT_IGNORE){
1489                                         if(y <= surface_y){
1490                                                 if(y > WATER_LEVEL && bt == BT_DESERT)
1491                                                         vmanip.m_data[i] = n_desert_stone;
1492                                                 else
1493                                                         vmanip.m_data[i] = n_stone;
1494                                         } else if(y <= WATER_LEVEL){
1495                                                 vmanip.m_data[i] = MapNode(c_water_source);
1496                                         } else {
1497                                                 vmanip.m_data[i] = MapNode(c_air);
1498                                         }
1499                                 }
1500                                 vmanip.m_area.add_y(em, i, 1);
1501                         }
1502                 }
1503         }
1504 #endif
1505
1506         }//timer1
1507
1508         // Limit dirt flow area by 1 because mud is flown into neighbors.
1509         assert(central_area_size.X == central_area_size.Z);
1510         s16 mudflow_minpos = 0-max_spread_amount+1;
1511         s16 mudflow_maxpos = central_area_size.X+max_spread_amount-2;
1512
1513         /*
1514                 Loop this part, it will make stuff look older and newer nicely
1515         */
1516
1517         const u32 age_loops = 2;
1518         for(u32 i_age=0; i_age<age_loops; i_age++)
1519         { // Aging loop
1520         /******************************
1521                 BEGINNING OF AGING LOOP
1522         ******************************/
1523
1524 #if 1
1525         {
1526         // 24ms @cs=8
1527         //TimeTaker timer1("caves");
1528
1529         /*
1530                 Make caves (this code is relatively horrible)
1531         */
1532         double cave_amount = 6.0 + 6.0 * noise2d_perlin(
1533                         0.5+(double)node_min.X/250, 0.5+(double)node_min.Y/250,
1534                         data->seed+34329, 3, 0.50);
1535         cave_amount = MYMAX(0.0, cave_amount);
1536         u32 caves_count = cave_amount * volume_nodes / 50000;
1537         u32 bruises_count = 1;
1538         PseudoRandom ps(blockseed+21343);
1539         PseudoRandom ps2(blockseed+1032);
1540         if(ps.range(1, 6) == 1)
1541                 bruises_count = ps.range(0, ps.range(0, 2));
1542         if(get_biome(data->seed, v2s16(node_min.X, node_min.Y)) == BT_DESERT){
1543                 caves_count /= 3;
1544                 bruises_count /= 3;
1545         }
1546         for(u32 jj=0; jj<caves_count+bruises_count; jj++)
1547         {
1548                 bool large_cave = (jj >= caves_count);
1549                 s16 min_tunnel_diameter = 2;
1550                 s16 max_tunnel_diameter = ps.range(2,6);
1551                 int dswitchint = ps.range(1,14);
1552                 u16 tunnel_routepoints = 0;
1553                 int part_max_length_rs = 0;
1554                 if(large_cave){
1555                         part_max_length_rs = ps.range(2,4);
1556                         tunnel_routepoints = ps.range(5, ps.range(15,30));
1557                         min_tunnel_diameter = 5;
1558                         max_tunnel_diameter = ps.range(7, ps.range(8,24));
1559                 } else {
1560                         part_max_length_rs = ps.range(2,9);
1561                         tunnel_routepoints = ps.range(10, ps.range(15,30));
1562                 }
1563                 bool large_cave_is_flat = (ps.range(0,1) == 0);
1564
1565                 v3f main_direction(0,0,0);
1566
1567                 // Allowed route area size in nodes
1568                 v3s16 ar = central_area_size;
1569
1570                 // Area starting point in nodes
1571                 v3s16 of = node_min;
1572
1573                 // Allow a bit more
1574                 //(this should be more than the maximum radius of the tunnel)
1575                 //s16 insure = 5; // Didn't work with max_d = 20
1576                 s16 insure = 10;
1577                 s16 more = max_spread_amount - max_tunnel_diameter/2 - insure;
1578                 ar += v3s16(1,0,1) * more * 2;
1579                 of -= v3s16(1,0,1) * more;
1580
1581                 s16 route_y_min = 0;
1582                 // Allow half a diameter + 7 over stone surface
1583                 s16 route_y_max = -of.Y + stone_surface_max_y + max_tunnel_diameter/2 + 7;
1584
1585                 /*// If caves, don't go through surface too often
1586                 if(large_cave == false)
1587                         route_y_max -= ps.range(0, max_tunnel_diameter*2);*/
1588
1589                 // Limit maximum to area
1590                 route_y_max = rangelim(route_y_max, 0, ar.Y-1);
1591
1592                 if(large_cave)
1593                 {
1594                         /*// Minimum is at y=0
1595                         route_y_min = -of.Y - 0;*/
1596                         // Minimum is at y=max_tunnel_diameter/4
1597                         //route_y_min = -of.Y + max_tunnel_diameter/4;
1598                         //s16 min = -of.Y + max_tunnel_diameter/4;
1599                         //s16 min = -of.Y + 0;
1600                         s16 min = 0;
1601                         if(node_min.Y < WATER_LEVEL && node_max.Y > WATER_LEVEL)
1602                         {
1603                                 min = WATER_LEVEL - max_tunnel_diameter/3 - of.Y;
1604                                 route_y_max = WATER_LEVEL + max_tunnel_diameter/3 - of.Y;
1605                         }
1606                         route_y_min = ps.range(min, min + max_tunnel_diameter);
1607                         route_y_min = rangelim(route_y_min, 0, route_y_max);
1608                 }
1609
1610                 /*dstream<<"route_y_min = "<<route_y_min
1611                                 <<", route_y_max = "<<route_y_max<<std::endl;*/
1612
1613                 s16 route_start_y_min = route_y_min;
1614                 s16 route_start_y_max = route_y_max;
1615
1616                 // Start every 4th cave from surface when applicable
1617                 /*bool coming_from_surface = false;
1618                 if(node_min.Y <= 0 && node_max.Y >= 0){
1619                         coming_from_surface = (jj % 4 == 0 && large_cave == false);
1620                         if(coming_from_surface)
1621                                 route_start_y_min = -of.Y + stone_surface_max_y + 10;
1622                 }*/
1623
1624                 route_start_y_min = rangelim(route_start_y_min, 0, ar.Y-1);
1625                 route_start_y_max = rangelim(route_start_y_max, route_start_y_min, ar.Y-1);
1626
1627                 // Randomize starting position
1628                 v3f orp(
1629                         (float)(ps.next()%ar.X)+0.5,
1630                         (float)(ps.range(route_start_y_min, route_start_y_max))+0.5,
1631                         (float)(ps.next()%ar.Z)+0.5
1632                 );
1633
1634                 v3s16 startp(orp.X, orp.Y, orp.Z);
1635                 startp += of;
1636
1637                 MapNode airnode(CONTENT_AIR);
1638                 MapNode waternode(c_water_source);
1639                 MapNode lavanode(c_lava_source);
1640
1641                 /*
1642                         Generate some tunnel starting from orp
1643                 */
1644
1645                 for(u16 j=0; j<tunnel_routepoints; j++)
1646                 {
1647                         if(j%dswitchint==0 && large_cave == false)
1648                         {
1649                                 main_direction = v3f(
1650                                         ((float)(ps.next()%20)-(float)10)/10,
1651                                         ((float)(ps.next()%20)-(float)10)/30,
1652                                         ((float)(ps.next()%20)-(float)10)/10
1653                                 );
1654                                 main_direction *= (float)ps.range(0, 10)/10;
1655                         }
1656
1657                         // Randomize size
1658                         s16 min_d = min_tunnel_diameter;
1659                         s16 max_d = max_tunnel_diameter;
1660                         s16 rs = ps.range(min_d, max_d);
1661
1662                         // Every second section is rough
1663                         bool randomize_xz = (ps2.range(1,2) == 1);
1664
1665                         v3s16 maxlen;
1666                         if(large_cave)
1667                         {
1668                                 maxlen = v3s16(
1669                                         rs*part_max_length_rs,
1670                                         rs*part_max_length_rs/2,
1671                                         rs*part_max_length_rs
1672                                 );
1673                         }
1674                         else
1675                         {
1676                                 maxlen = v3s16(
1677                                         rs*part_max_length_rs,
1678                                         ps.range(1, rs*part_max_length_rs),
1679                                         rs*part_max_length_rs
1680                                 );
1681                         }
1682
1683                         v3f vec;
1684
1685                         vec = v3f(
1686                                 (float)(ps.next()%(maxlen.X*1))-(float)maxlen.X/2,
1687                                 (float)(ps.next()%(maxlen.Y*1))-(float)maxlen.Y/2,
1688                                 (float)(ps.next()%(maxlen.Z*1))-(float)maxlen.Z/2
1689                         );
1690
1691                         // Jump downward sometimes
1692                         if(!large_cave && ps.range(0,12) == 0)
1693                         {
1694                                 vec = v3f(
1695                                         (float)(ps.next()%(maxlen.X*1))-(float)maxlen.X/2,
1696                                         (float)(ps.next()%(maxlen.Y*2))-(float)maxlen.Y*2/2,
1697                                         (float)(ps.next()%(maxlen.Z*1))-(float)maxlen.Z/2
1698                                 );
1699                         }
1700
1701                         /*if(large_cave){
1702                                 v3f p = orp + vec;
1703                                 s16 h = find_ground_level_clever(vmanip,
1704                                                 v2s16(p.X, p.Z), ndef);
1705                                 route_y_min = h - rs/3;
1706                                 route_y_max = h + rs;
1707                         }*/
1708
1709                         vec += main_direction;
1710
1711                         v3f rp = orp + vec;
1712                         if(rp.X < 0)
1713                                 rp.X = 0;
1714                         else if(rp.X >= ar.X)
1715                                 rp.X = ar.X-1;
1716                         if(rp.Y < route_y_min)
1717                                 rp.Y = route_y_min;
1718                         else if(rp.Y >= route_y_max)
1719                                 rp.Y = route_y_max-1;
1720                         if(rp.Z < 0)
1721                                 rp.Z = 0;
1722                         else if(rp.Z >= ar.Z)
1723                                 rp.Z = ar.Z-1;
1724                         vec = rp - orp;
1725
1726                         for(float f=0; f<1.0; f+=1.0/vec.getLength())
1727                         {
1728                                 v3f fp = orp + vec * f;
1729                                 fp.X += 0.1*ps.range(-10,10);
1730                                 fp.Z += 0.1*ps.range(-10,10);
1731                                 v3s16 cp(fp.X, fp.Y, fp.Z);
1732
1733                                 s16 d0 = -rs/2;
1734                                 s16 d1 = d0 + rs;
1735                                 if(randomize_xz){
1736                                         d0 += ps.range(-1,1);
1737                                         d1 += ps.range(-1,1);
1738                                 }
1739                                 for(s16 z0=d0; z0<=d1; z0++)
1740                                 {
1741                                         s16 si = rs/2 - MYMAX(0, abs(z0)-rs/7-1);
1742                                         for(s16 x0=-si-ps.range(0,1); x0<=si-1+ps.range(0,1); x0++)
1743                                         {
1744                                                 s16 maxabsxz = MYMAX(abs(x0), abs(z0));
1745                                                 s16 si2 = rs/2 - MYMAX(0, maxabsxz-rs/7-1);
1746                                                 for(s16 y0=-si2; y0<=si2; y0++)
1747                                                 {
1748                                                         /*// Make better floors in small caves
1749                                                         if(y0 <= -rs/2 && rs<=7)
1750                                                                 continue;*/
1751                                                         if(large_cave_is_flat){
1752                                                                 // Make large caves not so tall
1753                                                                 if(rs > 7 && abs(y0) >= rs/3)
1754                                                                         continue;
1755                                                         }
1756
1757                                                         s16 z = cp.Z + z0;
1758                                                         s16 y = cp.Y + y0;
1759                                                         s16 x = cp.X + x0;
1760                                                         v3s16 p(x,y,z);
1761                                                         p += of;
1762
1763                                                         if(vmanip.m_area.contains(p) == false)
1764                                                                 continue;
1765
1766                                                         u32 i = vmanip.m_area.index(p);
1767
1768                                                         if(large_cave)
1769                                                         {
1770                                                                 if(full_node_min.Y < WATER_LEVEL &&
1771                                                                         full_node_max.Y > WATER_LEVEL){
1772                                                                         if(p.Y <= WATER_LEVEL)
1773                                                                                 vmanip.m_data[i] = waternode;
1774                                                                         else
1775                                                                                 vmanip.m_data[i] = airnode;
1776                                                                 } else if(full_node_max.Y < WATER_LEVEL){
1777                                                                         if(p.Y < startp.Y - 2)
1778                                                                                 vmanip.m_data[i] = lavanode;
1779                                                                         else
1780                                                                                 vmanip.m_data[i] = airnode;
1781                                                                 } else {
1782                                                                         vmanip.m_data[i] = airnode;
1783                                                                 }
1784                                                         } else {
1785                                                                 // Don't replace air or water or lava or ignore
1786                                                                 if(vmanip.m_data[i].getContent() == CONTENT_IGNORE ||
1787                                                                 vmanip.m_data[i].getContent() == CONTENT_AIR ||
1788                                                                 vmanip.m_data[i].getContent() == c_water_source ||
1789                                                                 vmanip.m_data[i].getContent() == c_lava_source)
1790                                                                         continue;
1791
1792                                                                 vmanip.m_data[i] = airnode;
1793
1794                                                                 // Set tunnel flag
1795                                                                 vmanip.m_flags[i] |= VMANIP_FLAG_CAVE;
1796                                                         }
1797                                                 }
1798                                         }
1799                                 }
1800                         }
1801
1802                         orp = rp;
1803                 }
1804
1805         }
1806
1807         }//timer1
1808 #endif
1809
1810 #if 1
1811         {
1812         // 15ms @cs=8
1813         TimeTaker timer1("add mud");
1814
1815         /*
1816                 Add mud to the central chunk
1817         */
1818
1819         for(s16 x=node_min.X; x<=node_max.X; x++)
1820         for(s16 z=node_min.Z; z<=node_max.Z; z++)
1821         {
1822                 // Node position in 2d
1823                 v2s16 p2d = v2s16(x,z);
1824
1825                 // Randomize mud amount
1826                 s16 mud_add_amount = get_mud_add_amount(data->seed, p2d) / 2.0 + 0.5;
1827
1828                 // Find ground level
1829                 s16 surface_y = find_stone_level(vmanip, p2d, ndef);
1830                 // Handle area not found
1831                 if(surface_y == vmanip.m_area.MinEdge.Y - 1)
1832                         continue;
1833
1834                 MapNode addnode(c_dirt);
1835                 BiomeType bt = get_biome(data->seed, p2d);
1836
1837                 if(bt == BT_DESERT)
1838                         addnode = MapNode(c_desert_sand);
1839
1840                 if(bt == BT_DESERT && surface_y + mud_add_amount <= WATER_LEVEL+1){
1841                         addnode = MapNode(c_sand);
1842                 } else if(mud_add_amount <= 0){
1843                         mud_add_amount = 1 - mud_add_amount;
1844                         addnode = MapNode(c_gravel);
1845                 } else if(bt == BT_NORMAL && get_have_beach(data->seed, p2d) &&
1846                                 surface_y + mud_add_amount <= WATER_LEVEL+2){
1847                         addnode = MapNode(c_sand);
1848                 }
1849
1850                 if(bt == BT_DESERT){
1851                         if(surface_y > 20){
1852                                 mud_add_amount = MYMAX(0, mud_add_amount - (surface_y - 20)/5);
1853                         }
1854                 }
1855
1856                 /*
1857                         If topmost node is grass, change it to mud.
1858                         It might be if it was flown to there from a neighboring
1859                         chunk and then converted.
1860                 */
1861                 {
1862                         u32 i = vmanip.m_area.index(v3s16(p2d.X, surface_y, p2d.Y));
1863                         MapNode *n = &vmanip.m_data[i];
1864                         if(n->getContent() == c_dirt_with_grass)
1865                                 *n = MapNode(c_dirt);
1866                 }
1867
1868                 /*
1869                         Add mud on ground
1870                 */
1871                 {
1872                         s16 mudcount = 0;
1873                         v3s16 em = vmanip.m_area.getExtent();
1874                         s16 y_start = surface_y+1;
1875                         u32 i = vmanip.m_area.index(v3s16(p2d.X, y_start, p2d.Y));
1876                         for(s16 y=y_start; y<=node_max.Y; y++)
1877                         {
1878                                 if(mudcount >= mud_add_amount)
1879                                         break;
1880
1881                                 MapNode &n = vmanip.m_data[i];
1882                                 n = addnode;
1883                                 mudcount++;
1884
1885                                 vmanip.m_area.add_y(em, i, 1);
1886                         }
1887                 }
1888
1889         }
1890
1891         }//timer1
1892 #endif
1893
1894         /*
1895                 Add blobs of dirt and gravel underground
1896         */
1897         if(get_biome(data->seed, v2s16(node_min.X, node_min.Y)) == BT_NORMAL)
1898         {
1899         PseudoRandom pr(blockseed+983);
1900         for(int i=0; i<volume_nodes/10/10/10; i++)
1901         {
1902                 bool only_fill_cave = (myrand_range(0,1) != 0);
1903                 v3s16 size(
1904                         pr.range(1, 8),
1905                         pr.range(1, 8),
1906                         pr.range(1, 8)
1907                 );
1908                 v3s16 p0(
1909                         pr.range(node_min.X, node_max.X)-size.X/2,
1910                         pr.range(node_min.Y, node_max.Y)-size.Y/2,
1911                         pr.range(node_min.Z, node_max.Z)-size.Z/2
1912                 );
1913                 MapNode n1;
1914                 if(p0.Y > -32 && pr.range(0,1) == 0)
1915                         n1 = MapNode(c_dirt);
1916                 else
1917                         n1 = MapNode(c_gravel);
1918                 for(int x1=0; x1<size.X; x1++)
1919                 for(int y1=0; y1<size.Y; y1++)
1920                 for(int z1=0; z1<size.Z; z1++)
1921                 {
1922                         v3s16 p = p0 + v3s16(x1,y1,z1);
1923                         u32 i = vmanip.m_area.index(p);
1924                         if(!vmanip.m_area.contains(i))
1925                                 continue;
1926                         // Cancel if not stone and not cave air
1927                         if(vmanip.m_data[i].getContent() != c_stone &&
1928                                         !(vmanip.m_flags[i] & VMANIP_FLAG_CAVE))
1929                                 continue;
1930                         if(only_fill_cave && !(vmanip.m_flags[i] & VMANIP_FLAG_CAVE))
1931                                 continue;
1932                         vmanip.m_data[i] = n1;
1933                 }
1934         }
1935         }
1936
1937 #if 1
1938         {
1939         // 340ms @cs=8
1940         TimeTaker timer1("flow mud");
1941
1942         /*
1943                 Flow mud away from steep edges
1944         */
1945
1946         // Iterate a few times
1947         for(s16 k=0; k<3; k++)
1948         {
1949
1950         for(s16 x=mudflow_minpos; x<=mudflow_maxpos; x++)
1951         for(s16 z=mudflow_minpos; z<=mudflow_maxpos; z++)
1952         {
1953                 // Invert coordinates every 2nd iteration
1954                 if(k%2 == 0)
1955                 {
1956                         x = mudflow_maxpos - (x-mudflow_minpos);
1957                         z = mudflow_maxpos - (z-mudflow_minpos);
1958                 }
1959
1960                 // Node position in 2d
1961                 v2s16 p2d = v2s16(node_min.X, node_min.Z) + v2s16(x,z);
1962
1963                 v3s16 em = vmanip.m_area.getExtent();
1964                 u32 i = vmanip.m_area.index(v3s16(p2d.X, node_max.Y, p2d.Y));
1965                 s16 y=node_max.Y;
1966
1967                 while(y >= node_min.Y)
1968                 {
1969
1970                 for(;; y--)
1971                 {
1972                         MapNode *n = NULL;
1973                         // Find mud
1974                         for(; y>=node_min.Y; y--)
1975                         {
1976                                 n = &vmanip.m_data[i];
1977                                 //if(content_walkable(n->d))
1978                                 //      break;
1979                                 if(n->getContent() == c_dirt ||
1980                                                 n->getContent() == c_dirt_with_grass ||
1981                                                 n->getContent() == c_gravel)
1982                                         break;
1983
1984                                 vmanip.m_area.add_y(em, i, -1);
1985                         }
1986
1987                         // Stop if out of area
1988                         //if(vmanip.m_area.contains(i) == false)
1989                         if(y < node_min.Y)
1990                                 break;
1991
1992                         /*// If not mud, do nothing to it
1993                         MapNode *n = &vmanip.m_data[i];
1994                         if(n->d != CONTENT_MUD && n->d != CONTENT_GRASS)
1995                                 continue;*/
1996
1997                         if(n->getContent() == c_dirt ||
1998                                         n->getContent() == c_dirt_with_grass)
1999                         {
2000                                 // Make it exactly mud
2001                                 n->setContent(c_dirt);
2002
2003                                 /*
2004                                         Don't flow it if the stuff under it is not mud
2005                                 */
2006                                 {
2007                                         u32 i2 = i;
2008                                         vmanip.m_area.add_y(em, i2, -1);
2009                                         // Cancel if out of area
2010                                         if(vmanip.m_area.contains(i2) == false)
2011                                                 continue;
2012                                         MapNode *n2 = &vmanip.m_data[i2];
2013                                         if(n2->getContent() != c_dirt &&
2014                                                         n2->getContent() != c_dirt_with_grass)
2015                                                 continue;
2016                                 }
2017                         }
2018
2019                         /*s16 recurse_count = 0;
2020         mudflow_recurse:*/
2021
2022                         v3s16 dirs4[4] = {
2023                                 v3s16(0,0,1), // back
2024                                 v3s16(1,0,0), // right
2025                                 v3s16(0,0,-1), // front
2026                                 v3s16(-1,0,0), // left
2027                         };
2028
2029                         // Theck that upper is air or doesn't exist.
2030                         // Cancel dropping if upper keeps it in place
2031                         u32 i3 = i;
2032                         vmanip.m_area.add_y(em, i3, 1);
2033                         if(vmanip.m_area.contains(i3) == true
2034                                         && ndef->get(vmanip.m_data[i3]).walkable)
2035                         {
2036                                 continue;
2037                         }
2038
2039                         // Drop mud on side
2040
2041                         for(u32 di=0; di<4; di++)
2042                         {
2043                                 v3s16 dirp = dirs4[di];
2044                                 u32 i2 = i;
2045                                 // Move to side
2046                                 vmanip.m_area.add_p(em, i2, dirp);
2047                                 // Fail if out of area
2048                                 if(vmanip.m_area.contains(i2) == false)
2049                                         continue;
2050                                 // Check that side is air
2051                                 MapNode *n2 = &vmanip.m_data[i2];
2052                                 if(ndef->get(*n2).walkable)
2053                                         continue;
2054                                 // Check that under side is air
2055                                 vmanip.m_area.add_y(em, i2, -1);
2056                                 if(vmanip.m_area.contains(i2) == false)
2057                                         continue;
2058                                 n2 = &vmanip.m_data[i2];
2059                                 if(ndef->get(*n2).walkable)
2060                                         continue;
2061                                 /*// Check that under that is air (need a drop of 2)
2062                                 vmanip.m_area.add_y(em, i2, -1);
2063                                 if(vmanip.m_area.contains(i2) == false)
2064                                         continue;
2065                                 n2 = &vmanip.m_data[i2];
2066                                 if(content_walkable(n2->d))
2067                                         continue;*/
2068                                 // Loop further down until not air
2069                                 bool dropped_to_unknown = false;
2070                                 do{
2071                                         vmanip.m_area.add_y(em, i2, -1);
2072                                         n2 = &vmanip.m_data[i2];
2073                                         // if out of known area
2074                                         if(vmanip.m_area.contains(i2) == false
2075                                                         || n2->getContent() == CONTENT_IGNORE){
2076                                                 dropped_to_unknown = true;
2077                                                 break;
2078                                         }
2079                                 }while(ndef->get(*n2).walkable == false);
2080                                 // Loop one up so that we're in air
2081                                 vmanip.m_area.add_y(em, i2, 1);
2082                                 n2 = &vmanip.m_data[i2];
2083
2084                                 bool old_is_water = (n->getContent() == c_water_source);
2085                                 // Move mud to new place
2086                                 if(!dropped_to_unknown) {
2087                                         *n2 = *n;
2088                                         // Set old place to be air (or water)
2089                                         if(old_is_water)
2090                                                 *n = MapNode(c_water_source);
2091                                         else
2092                                                 *n = MapNode(CONTENT_AIR);
2093                                 }
2094
2095                                 // Done
2096                                 break;
2097                         }
2098                 }
2099                 }
2100         }
2101
2102         }
2103
2104         }//timer1
2105 #endif
2106
2107         } // Aging loop
2108         /***********************
2109                 END OF AGING LOOP
2110         ************************/
2111
2112         /*
2113                 Add top and bottom side of water to transforming_liquid queue
2114         */
2115
2116         for(s16 x=full_node_min.X; x<=full_node_max.X; x++)
2117         for(s16 z=full_node_min.Z; z<=full_node_max.Z; z++)
2118         {
2119                 // Node position
2120                 v2s16 p2d(x,z);
2121                 {
2122                         bool water_found = false;
2123                         // Use fast index incrementing
2124                         v3s16 em = vmanip.m_area.getExtent();
2125                         u32 i = vmanip.m_area.index(v3s16(p2d.X, full_node_max.Y, p2d.Y));
2126                         for(s16 y=full_node_max.Y; y>=full_node_min.Y; y--)
2127                         {
2128                                 if(y == full_node_max.Y){
2129                                         water_found =
2130                                                 (vmanip.m_data[i].getContent() == c_water_source ||
2131                                                 vmanip.m_data[i].getContent() == c_lava_source);
2132                                 }
2133                                 else if(water_found == false)
2134                                 {
2135                                         if(vmanip.m_data[i].getContent() == c_water_source ||
2136                                                         vmanip.m_data[i].getContent() == c_lava_source)
2137                                         {
2138                                                 v3s16 p = v3s16(p2d.X, y, p2d.Y);
2139                                                 data->transforming_liquid.push_back(p);
2140                                                 water_found = true;
2141                                         }
2142                                 }
2143                                 else
2144                                 {
2145                                         // This can be done because water_found can only
2146                                         // turn to true and end up here after going through
2147                                         // a single block.
2148                                         if(vmanip.m_data[i+1].getContent() != c_water_source ||
2149                                                         vmanip.m_data[i+1].getContent() != c_lava_source)
2150                                         {
2151                                                 v3s16 p = v3s16(p2d.X, y+1, p2d.Y);
2152                                                 data->transforming_liquid.push_back(p);
2153                                                 water_found = false;
2154                                         }
2155                                 }
2156
2157                                 vmanip.m_area.add_y(em, i, -1);
2158                         }
2159                 }
2160         }
2161
2162         /*
2163                 Grow grass
2164         */
2165
2166         for(s16 x=full_node_min.X; x<=full_node_max.X; x++)
2167         for(s16 z=full_node_min.Z; z<=full_node_max.Z; z++)
2168         {
2169                 // Node position in 2d
2170                 v2s16 p2d = v2s16(x,z);
2171
2172                 /*
2173                         Find the lowest surface to which enough light ends up
2174                         to make grass grow.
2175
2176                         Basically just wait until not air and not leaves.
2177                 */
2178                 s16 surface_y = 0;
2179                 {
2180                         v3s16 em = vmanip.m_area.getExtent();
2181                         u32 i = vmanip.m_area.index(v3s16(p2d.X, node_max.Y, p2d.Y));
2182                         s16 y;
2183                         // Go to ground level
2184                         for(y=node_max.Y; y>=full_node_min.Y; y--)
2185                         {
2186                                 MapNode &n = vmanip.m_data[i];
2187                                 if(ndef->get(n).param_type != CPT_LIGHT
2188                                                 || ndef->get(n).liquid_type != LIQUID_NONE)
2189                                         break;
2190                                 vmanip.m_area.add_y(em, i, -1);
2191                         }
2192                         if(y >= full_node_min.Y)
2193                                 surface_y = y;
2194                         else
2195                                 surface_y = full_node_min.Y;
2196                 }
2197
2198                 u32 i = vmanip.m_area.index(p2d.X, surface_y, p2d.Y);
2199                 MapNode *n = &vmanip.m_data[i];
2200                 if(n->getContent() == c_dirt){
2201                         // Well yeah, this can't be overground...
2202                         if(surface_y < WATER_LEVEL - 20)
2203                                 continue;
2204                         n->setContent(c_dirt_with_grass);
2205                 }
2206         }
2207
2208         /*
2209                 Generate some trees
2210         */
2211         assert(central_area_size.X == central_area_size.Z);
2212         {
2213                 // Divide area into parts
2214                 s16 div = 8;
2215                 s16 sidelen = central_area_size.X / div;
2216                 double area = sidelen * sidelen;
2217                 for(s16 x0=0; x0<div; x0++)
2218                 for(s16 z0=0; z0<div; z0++)
2219                 {
2220                         // Center position of part of division
2221                         v2s16 p2d_center(
2222                                 node_min.X + sidelen/2 + sidelen*x0,
2223                                 node_min.Z + sidelen/2 + sidelen*z0
2224                         );
2225                         // Minimum edge of part of division
2226                         v2s16 p2d_min(
2227                                 node_min.X + sidelen*x0,
2228                                 node_min.Z + sidelen*z0
2229                         );
2230                         // Maximum edge of part of division
2231                         v2s16 p2d_max(
2232                                 node_min.X + sidelen + sidelen*x0 - 1,
2233                                 node_min.Z + sidelen + sidelen*z0 - 1
2234                         );
2235                         // Amount of trees
2236                         u32 tree_count = area * tree_amount_2d(data->seed, p2d_center);
2237                         // Put trees in random places on part of division
2238                         for(u32 i=0; i<tree_count; i++)
2239                         {
2240                                 s16 x = myrand_range(p2d_min.X, p2d_max.X);
2241                                 s16 z = myrand_range(p2d_min.Y, p2d_max.Y);
2242                                 s16 y = find_ground_level(vmanip, v2s16(x,z), ndef);
2243                                 // Don't make a tree under water level
2244                                 if(y < WATER_LEVEL)
2245                                         continue;
2246                                 // Don't make a tree so high that it doesn't fit
2247                                 if(y > node_max.Y - 6)
2248                                         continue;
2249                                 v3s16 p(x,y,z);
2250                                 /*
2251                                         Trees grow only on mud and grass
2252                                 */
2253                                 {
2254                                         u32 i = vmanip.m_area.index(v3s16(p));
2255                                         MapNode *n = &vmanip.m_data[i];
2256                                         if(n->getContent() != c_dirt
2257                                                         && n->getContent() != c_dirt_with_grass)
2258                                                 continue;
2259                                 }
2260                                 p.Y++;
2261                                 // Make a tree
2262                                 treegen::make_tree(vmanip, p, false, ndef);
2263                         }
2264                 }
2265         }
2266
2267 #if 0
2268         /*
2269                 Make base ground level
2270         */
2271
2272         for(s16 x=node_min.X; x<=node_max.X; x++)
2273         for(s16 z=node_min.Z; z<=node_max.Z; z++)
2274         {
2275                 // Node position
2276                 v2s16 p2d(x,z);
2277                 {
2278                         // Use fast index incrementing
2279                         v3s16 em = vmanip.m_area.getExtent();
2280                         u32 i = vmanip.m_area.index(v3s16(p2d.X, node_min.Y, p2d.Y));
2281                         for(s16 y=node_min.Y; y<=node_max.Y; y++)
2282                         {
2283                                 // Only modify places that have no content
2284                                 if(vmanip.m_data[i].getContent() == CONTENT_IGNORE)
2285                                 {
2286                                         // First priority: make air and water.
2287                                         // This avoids caves inside water.
2288                                         if(all_is_ground_except_caves == false
2289                                                         && val_is_ground(noisebuf_ground.get(x,y,z),
2290                                                         v3s16(x,y,z), data->seed) == false)
2291                                         {
2292                                                 if(y <= WATER_LEVEL)
2293                                                         vmanip.m_data[i] = n_water_source;
2294                                                 else
2295                                                         vmanip.m_data[i] = n_air;
2296                                         }
2297                                         else if(noisebuf_cave.get(x,y,z) > CAVE_NOISE_THRESHOLD)
2298                                                 vmanip.m_data[i] = n_air;
2299                                         else
2300                                                 vmanip.m_data[i] = n_stone;
2301                                 }
2302
2303                                 vmanip->m_area.add_y(em, i, 1);
2304                         }
2305                 }
2306         }
2307
2308         /*
2309                 Add mud and sand and others underground (in place of stone)
2310         */
2311
2312         for(s16 x=node_min.X; x<=node_max.X; x++)
2313         for(s16 z=node_min.Z; z<=node_max.Z; z++)
2314         {
2315                 // Node position
2316                 v2s16 p2d(x,z);
2317                 {
2318                         // Use fast index incrementing
2319                         v3s16 em = vmanip.m_area.getExtent();
2320                         u32 i = vmanip.m_area.index(v3s16(p2d.X, node_max.Y, p2d.Y));
2321                         for(s16 y=node_max.Y; y>=node_min.Y; y--)
2322                         {
2323                                 if(vmanip.m_data[i].getContent() == c_stone)
2324                                 {
2325                                         if(noisebuf_ground_crumbleness.get(x,y,z) > 1.3)
2326                                         {
2327                                                 if(noisebuf_ground_wetness.get(x,y,z) > 0.0)
2328                                                         vmanip.m_data[i] = n_dirt;
2329                                                 else
2330                                                         vmanip.m_data[i] = n_sand;
2331                                         }
2332                                         else if(noisebuf_ground_crumbleness.get(x,y,z) > 0.7)
2333                                         {
2334                                                 if(noisebuf_ground_wetness.get(x,y,z) < -0.6)
2335                                                         vmanip.m_data[i] = n_gravel;
2336                                         }
2337                                         else if(noisebuf_ground_crumbleness.get(x,y,z) <
2338                                                         -3.0 + MYMIN(0.1 * sqrt((float)MYMAX(0, -y)), 1.5))
2339                                         {
2340                                                 vmanip.m_data[i] = n_lava_source;
2341                                                 for(s16 x1=-1; x1<=1; x1++)
2342                                                 for(s16 y1=-1; y1<=1; y1++)
2343                                                 for(s16 z1=-1; z1<=1; z1++)
2344                                                         data->transforming_liquid.push_back(
2345                                                                         v3s16(p2d.X+x1, y+y1, p2d.Y+z1));
2346                                         }
2347                                 }
2348
2349                                 vmanip->m_area.add_y(em, i, -1);
2350                         }
2351                 }
2352         }
2353
2354         /*
2355                 Add dungeons
2356         */
2357
2358         //if(node_min.Y < approx_groundlevel)
2359         //if(myrand() % 3 == 0)
2360         //if(myrand() % 3 == 0 && node_min.Y < approx_groundlevel)
2361         //if(myrand() % 100 == 0 && node_min.Y < approx_groundlevel)
2362         //float dungeon_rarity = g_settings.getFloat("dungeon_rarity");
2363         float dungeon_rarity = 0.02;
2364         if(((noise3d(blockpos.X,blockpos.Y,blockpos.Z,data->seed)+1.0)/2.0)
2365                         < dungeon_rarity
2366                         && node_min.Y < approx_groundlevel)
2367         {
2368                 // Dungeon generator doesn't modify places which have this set
2369                 vmanip->clearFlag(VMANIP_FLAG_DUNGEON_INSIDE
2370                                 | VMANIP_FLAG_DUNGEON_PRESERVE);
2371
2372                 // Set all air and water to be untouchable to make dungeons open
2373                 // to caves and open air
2374                 for(s16 x=full_node_min.X; x<=full_node_max.X; x++)
2375                 for(s16 z=full_node_min.Z; z<=full_node_max.Z; z++)
2376                 {
2377                         // Node position
2378                         v2s16 p2d(x,z);
2379                         {
2380                                 // Use fast index incrementing
2381                                 v3s16 em = vmanip.m_area.getExtent();
2382                                 u32 i = vmanip.m_area.index(v3s16(p2d.X, full_node_max.Y, p2d.Y));
2383                                 for(s16 y=full_node_max.Y; y>=full_node_min.Y; y--)
2384                                 {
2385                                         if(vmanip.m_data[i].getContent() == CONTENT_AIR)
2386                                                 vmanip.m_flags[i] |= VMANIP_FLAG_DUNGEON_PRESERVE;
2387                                         else if(vmanip.m_data[i].getContent() == c_water_source)
2388                                                 vmanip.m_flags[i] |= VMANIP_FLAG_DUNGEON_PRESERVE;
2389                                         vmanip->m_area.add_y(em, i, -1);
2390                                 }
2391                         }
2392                 }
2393
2394                 PseudoRandom random(blockseed+2);
2395
2396                 // Add it
2397                 make_dungeon1(vmanip, random, ndef);
2398
2399                 // Convert some cobble to mossy cobble
2400                 for(s16 x=full_node_min.X; x<=full_node_max.X; x++)
2401                 for(s16 z=full_node_min.Z; z<=full_node_max.Z; z++)
2402                 {
2403                         // Node position
2404                         v2s16 p2d(x,z);
2405                         {
2406                                 // Use fast index incrementing
2407                                 v3s16 em = vmanip.m_area.getExtent();
2408                                 u32 i = vmanip.m_area.index(v3s16(p2d.X, full_node_max.Y, p2d.Y));
2409                                 for(s16 y=full_node_max.Y; y>=full_node_min.Y; y--)
2410                                 {
2411                                         // (noisebuf not used because it doesn't contain the
2412                                         //  full area)
2413                                         double wetness = noise3d_param(
2414                                                         get_ground_wetness_params(data->seed), x,y,z);
2415                                         double d = noise3d_perlin((float)x/2.5,
2416                                                         (float)y/2.5,(float)z/2.5,
2417                                                         blockseed, 2, 1.4);
2418                                         if(vmanip.m_data[i].getContent() == c_cobble)
2419                                         {
2420                                                 if(d < wetness/3.0)
2421                                                 {
2422                                                         vmanip.m_data[i].setContent(c_mossycobble);
2423                                                 }
2424                                         }
2425                                         /*else if(vmanip.m_flags[i] & VMANIP_FLAG_DUNGEON_INSIDE)
2426                                         {
2427                                                 if(wetness > 1.2)
2428                                                         vmanip.m_data[i].setContent(c_dirt);
2429                                         }*/
2430                                         vmanip->m_area.add_y(em, i, -1);
2431                                 }
2432                         }
2433                 }
2434         }
2435
2436         /*
2437                 Add NC
2438         */
2439         {
2440                 PseudoRandom ncrandom(blockseed+9324342);
2441                 if(ncrandom.range(0, 1000) == 0 && blockpos.Y <= -3)
2442                 {
2443                         make_nc(vmanip, ncrandom, ndef);
2444                 }
2445         }
2446
2447         /*
2448                 Add top and bottom side of water to transforming_liquid queue
2449         */
2450
2451         for(s16 x=node_min.X; x<=node_max.X; x++)
2452         for(s16 z=node_min.Z; z<=node_max.Z; z++)
2453         {
2454                 // Node position
2455                 v2s16 p2d(x,z);
2456                 {
2457                         bool water_found = false;
2458                         // Use fast index incrementing
2459                         v3s16 em = vmanip.m_area.getExtent();
2460                         u32 i = vmanip.m_area.index(v3s16(p2d.X, node_max.Y, p2d.Y));
2461                         for(s16 y=node_max.Y; y>=node_min.Y; y--)
2462                         {
2463                                 if(water_found == false)
2464                                 {
2465                                         if(vmanip.m_data[i].getContent() == c_water_source)
2466                                         {
2467                                                 v3s16 p = v3s16(p2d.X, y, p2d.Y);
2468                                                 data->transforming_liquid.push_back(p);
2469                                                 water_found = true;
2470                                         }
2471                                 }
2472                                 else
2473                                 {
2474                                         // This can be done because water_found can only
2475                                         // turn to true and end up here after going through
2476                                         // a single block.
2477                                         if(vmanip.m_data[i+1].getContent() != c_water_source)
2478                                         {
2479                                                 v3s16 p = v3s16(p2d.X, y+1, p2d.Y);
2480                                                 data->transforming_liquid.push_back(p);
2481                                                 water_found = false;
2482                                         }
2483                                 }
2484
2485                                 vmanip->m_area.add_y(em, i, -1);
2486                         }
2487                 }
2488         }
2489
2490         /*
2491                 If close to ground level
2492         */
2493
2494         //if(abs(approx_ground_depth) < 30)
2495         if(minimum_ground_depth < 5 && maximum_ground_depth > -5)
2496         {
2497                 /*
2498                         Add grass and mud
2499                 */
2500
2501                 for(s16 x=node_min.X; x<=node_max.X; x++)
2502                 for(s16 z=node_min.Z; z<=node_max.Z; z++)
2503                 {
2504                         // Node position
2505                         v2s16 p2d(x,z);
2506                         {
2507                                 bool possibly_have_sand = get_have_beach(data->seed, p2d);
2508                                 bool have_sand = false;
2509                                 u32 current_depth = 0;
2510                                 bool air_detected = false;
2511                                 bool water_detected = false;
2512                                 bool have_clay = false;
2513
2514                                 // Use fast index incrementing
2515                                 s16 start_y = node_max.Y+2;
2516                                 v3s16 em = vmanip.m_area.getExtent();
2517                                 u32 i = vmanip.m_area.index(v3s16(p2d.X, start_y, p2d.Y));
2518                                 for(s16 y=start_y; y>=node_min.Y-3; y--)
2519                                 {
2520                                         if(vmanip.m_data[i].getContent() == c_water_source)
2521                                                 water_detected = true;
2522                                         if(vmanip.m_data[i].getContent() == CONTENT_AIR)
2523                                                 air_detected = true;
2524
2525                                         if((vmanip.m_data[i].getContent() == c_stone
2526                                                         || vmanip.m_data[i].getContent() == c_dirt_with_grass
2527                                                         || vmanip.m_data[i].getContent() == c_dirt
2528                                                         || vmanip.m_data[i].getContent() == c_sand
2529                                                         || vmanip.m_data[i].getContent() == c_gravel
2530                                                         ) && (air_detected || water_detected))
2531                                         {
2532                                                 if(current_depth == 0 && y <= WATER_LEVEL+2
2533                                                                 && possibly_have_sand)
2534                                                         have_sand = true;
2535
2536                                                 if(current_depth < 4)
2537                                                 {
2538                                                         if(have_sand)
2539                                                         {
2540                                                                 vmanip.m_data[i] = MapNode(c_sand);
2541                                                         }
2542                                                         #if 1
2543                                                         else if(current_depth==0 && !water_detected
2544                                                                         && y >= WATER_LEVEL && air_detected)
2545                                                                 vmanip.m_data[i] = MapNode(c_dirt_with_grass);
2546                                                         #endif
2547                                                         else
2548                                                                 vmanip.m_data[i] = MapNode(c_dirt);
2549                                                 }
2550                                                 else
2551                                                 {
2552                                                         if(vmanip.m_data[i].getContent() == c_dirt
2553                                                                 || vmanip.m_data[i].getContent() == c_dirt_with_grass)
2554                                                                 vmanip.m_data[i] = MapNode(c_stone);
2555                                                 }
2556
2557                                                 current_depth++;
2558
2559                                                 if(current_depth >= 8)
2560                                                         break;
2561                                         }
2562                                         else if(current_depth != 0)
2563                                                 break;
2564
2565                                         vmanip->m_area.add_y(em, i, -1);
2566                                 }
2567                         }
2568                 }
2569
2570                 /*
2571                         Calculate some stuff
2572                 */
2573
2574                 float surface_humidity = surface_humidity_2d(data->seed, p2d_center);
2575                 bool is_jungle = surface_humidity > 0.75;
2576                 // Amount of trees
2577                 u32 tree_count = gen_area_nodes * tree_amount_2d(data->seed, p2d_center);
2578                 if(is_jungle)
2579                         tree_count *= 5;
2580
2581                 /*
2582                         Add trees
2583                 */
2584                 PseudoRandom treerandom(blockseed);
2585                 // Put trees in random places on part of division
2586                 for(u32 i=0; i<tree_count; i++)
2587                 {
2588                         s16 x = treerandom.range(node_min.X, node_max.X);
2589                         s16 z = treerandom.range(node_min.Z, node_max.Z);
2590                         //s16 y = find_ground_level(vmanip, v2s16(x,z));
2591                         s16 y = find_ground_level_from_noise(data->seed, v2s16(x,z), 4);
2592                         // Don't make a tree under water level
2593                         if(y < WATER_LEVEL)
2594                                 continue;
2595                         // Make sure tree fits (only trees whose starting point is
2596                         // at this block are added)
2597                         if(y < node_min.Y || y > node_max.Y)
2598                                 continue;
2599                         /*
2600                                 Find exact ground level
2601                         */
2602                         v3s16 p(x,y+6,z);
2603                         bool found = false;
2604                         for(; p.Y >= y-6; p.Y--)
2605                         {
2606                                 u32 i = vmanip->m_area.index(p);
2607                                 MapNode *n = &vmanip->m_data[i];
2608                                 if(n->getContent() != CONTENT_AIR && n->getContent() != c_water_source && n->getContent() != CONTENT_IGNORE)
2609                                 {
2610                                         found = true;
2611                                         break;
2612                                 }
2613                         }
2614                         // If not found, handle next one
2615                         if(found == false)
2616                                 continue;
2617
2618                         {
2619                                 u32 i = vmanip->m_area.index(p);
2620                                 MapNode *n = &vmanip->m_data[i];
2621
2622                                 if(n->getContent() != c_dirt && n->getContent() != c_dirt_with_grass && n->getContent() != c_sand)
2623                                                 continue;
2624
2625                                 // Papyrus grows only on mud and in water
2626                                 if(n->getContent() == c_dirt && y <= WATER_LEVEL)
2627                                 {
2628                                         p.Y++;
2629                                         make_papyrus(vmanip, p, ndef);
2630                                 }
2631                                 // Trees grow only on mud and grass, on land
2632                                 else if((n->getContent() == c_dirt || n->getContent() == c_dirt_with_grass) && y > WATER_LEVEL + 2)
2633                                 {
2634                                         p.Y++;
2635                                         //if(surface_humidity_2d(data->seed, v2s16(x, y)) < 0.5)
2636                                         if(is_jungle == false)
2637                                         {
2638                                                 bool is_apple_tree;
2639                                                 if(myrand_range(0,4) != 0)
2640                                                         is_apple_tree = false;
2641                                                 else
2642                                                         is_apple_tree = noise2d_perlin(
2643                                                                         0.5+(float)p.X/100, 0.5+(float)p.Z/100,
2644                                                                         data->seed+342902, 3, 0.45) > 0.2;
2645                                                 make_tree(vmanip, p, is_apple_tree, ndef);
2646                                         }
2647                                         else
2648                                                 make_jungletree(vmanip, p, ndef);
2649                                 }
2650                                 // Cactii grow only on sand, on land
2651                                 else if(n->getContent() == c_sand && y > WATER_LEVEL + 2)
2652                                 {
2653                                         p.Y++;
2654                                         make_cactus(vmanip, p, ndef);
2655                                 }
2656                         }
2657                 }
2658
2659                 /*
2660                         Add jungle grass
2661                 */
2662                 if(is_jungle)
2663                 {
2664                         PseudoRandom grassrandom(blockseed);
2665                         for(u32 i=0; i<surface_humidity*5*tree_count; i++)
2666                         {
2667                                 s16 x = grassrandom.range(node_min.X, node_max.X);
2668                                 s16 z = grassrandom.range(node_min.Z, node_max.Z);
2669                                 s16 y = find_ground_level_from_noise(data->seed, v2s16(x,z), 4);
2670                                 if(y < WATER_LEVEL)
2671                                         continue;
2672                                 if(y < node_min.Y || y > node_max.Y)
2673                                         continue;
2674                                 /*
2675                                         Find exact ground level
2676                                 */
2677                                 v3s16 p(x,y+6,z);
2678                                 bool found = false;
2679                                 for(; p.Y >= y-6; p.Y--)
2680                                 {
2681                                         u32 i = vmanip->m_area.index(p);
2682                                         MapNode *n = &vmanip->m_data[i];
2683                                         if(data->nodedef->get(*n).is_ground_content)
2684                                         {
2685                                                 found = true;
2686                                                 break;
2687                                         }
2688                                 }
2689                                 // If not found, handle next one
2690                                 if(found == false)
2691                                         continue;
2692                                 p.Y++;
2693                                 if(vmanip.m_area.contains(p) == false)
2694                                         continue;
2695                                 if(vmanip.m_data[vmanip.m_area.index(p)].getContent() != CONTENT_AIR)
2696                                         continue;
2697                                 /*p.Y--;
2698                                 if(vmanip.m_area.contains(p))
2699                                         vmanip.m_data[vmanip.m_area.index(p)] = c_dirt;
2700                                 p.Y++;*/
2701                                 if(vmanip.m_area.contains(p))
2702                                         vmanip.m_data[vmanip.m_area.index(p)] = c_junglegrass;
2703                         }
2704                 }
2705
2706 #if 0
2707                 /*
2708                         Add some kind of random stones
2709                 */
2710
2711                 u32 random_stone_count = gen_area_nodes *
2712                                 randomstone_amount_2d(data->seed, p2d_center);
2713                 // Put in random places on part of division
2714                 for(u32 i=0; i<random_stone_count; i++)
2715                 {
2716                         s16 x = myrand_range(node_min.X, node_max.X);
2717                         s16 z = myrand_range(node_min.Z, node_max.Z);
2718                         s16 y = find_ground_level_from_noise(data->seed, v2s16(x,z), 1);
2719                         // Don't add under water level
2720                         /*if(y < WATER_LEVEL)
2721                                 continue;*/
2722                         // Don't add if doesn't belong to this block
2723                         if(y < node_min.Y || y > node_max.Y)
2724                                 continue;
2725                         v3s16 p(x,y,z);
2726                         // Filter placement
2727                         /*{
2728                                 u32 i = vmanip->m_area.index(v3s16(p));
2729                                 MapNode *n = &vmanip->m_data[i];
2730                                 if(n->getContent() != c_dirt && n->getContent() != c_dirt_with_grass)
2731                                         continue;
2732                         }*/
2733                         // Will be placed one higher
2734                         p.Y++;
2735                         // Add it
2736                         make_randomstone(vmanip, p);
2737                 }
2738 #endif
2739
2740 #if 0
2741                 /*
2742                         Add larger stones
2743                 */
2744
2745                 u32 large_stone_count = gen_area_nodes *
2746                                 largestone_amount_2d(data->seed, p2d_center);
2747                 //u32 large_stone_count = 1;
2748                 // Put in random places on part of division
2749                 for(u32 i=0; i<large_stone_count; i++)
2750                 {
2751                         s16 x = myrand_range(node_min.X, node_max.X);
2752                         s16 z = myrand_range(node_min.Z, node_max.Z);
2753                         s16 y = find_ground_level_from_noise(data->seed, v2s16(x,z), 1);
2754                         // Don't add under water level
2755                         /*if(y < WATER_LEVEL)
2756                                 continue;*/
2757                         // Don't add if doesn't belong to this block
2758                         if(y < node_min.Y || y > node_max.Y)
2759                                 continue;
2760                         v3s16 p(x,y,z);
2761                         // Filter placement
2762                         /*{
2763                                 u32 i = vmanip->m_area.index(v3s16(p));
2764                                 MapNode *n = &vmanip->m_data[i];
2765                                 if(n->getContent() != c_dirt && n->getContent() != c_dirt_with_grass)
2766                                         continue;
2767                         }*/
2768                         // Will be placed one lower
2769                         p.Y--;
2770                         // Add it
2771                         make_largestone(vmanip, p);
2772                 }
2773 #endif
2774         }
2775
2776         /*
2777                 Add minerals
2778         */
2779
2780         {
2781                 PseudoRandom mineralrandom(blockseed);
2782
2783                 /*
2784                         Add meseblocks
2785                 */
2786                 for(s16 i=0; i<approx_ground_depth/4; i++)
2787                 {
2788                         if(mineralrandom.next()%50 == 0)
2789                         {
2790                                 s16 x = mineralrandom.range(node_min.X+1, node_max.X-1);
2791                                 s16 y = mineralrandom.range(node_min.Y+1, node_max.Y-1);
2792                                 s16 z = mineralrandom.range(node_min.Z+1, node_max.Z-1);
2793                                 for(u16 i=0; i<27; i++)
2794                                 {
2795                                         v3s16 p = v3s16(x,y,z) + g_27dirs[i];
2796                                         u32 vi = vmanip.m_area.index(p);
2797                                         if(vmanip.m_data[vi].getContent() == c_stone)
2798                                                 if(mineralrandom.next()%8 == 0)
2799                                                         vmanip.m_data[vi] = MapNode(c_mese);
2800                                 }
2801
2802                         }
2803                 }
2804                 /*
2805                         Add others
2806                 */
2807                 {
2808                         u16 a = mineralrandom.range(0,15);
2809                         a = a*a*a;
2810                         u16 amount = 20 * a/1000;
2811                         for(s16 i=0; i<amount; i++)
2812                         {
2813                                 s16 x = mineralrandom.range(node_min.X+1, node_max.X-1);
2814                                 s16 y = mineralrandom.range(node_min.Y+1, node_max.Y-1);
2815                                 s16 z = mineralrandom.range(node_min.Z+1, node_max.Z-1);
2816
2817                                 u8 base_content = c_stone;
2818                                 MapNode new_content(CONTENT_IGNORE);
2819                                 u32 sparseness = 6;
2820
2821                                 if(noisebuf_ground_crumbleness.get(x,y+5,z) < -0.1)
2822                                 {
2823                                         new_content = MapNode(c_stone_with_coal);
2824                                 }
2825                                 else
2826                                 {
2827                                         if(noisebuf_ground_wetness.get(x,y+5,z) > 0.0)
2828                                                 new_content = MapNode(c_stone_with_iron);
2829                                         /*if(noisebuf_ground_wetness.get(x,y,z) > 0.0)
2830                                                 vmanip.m_data[i] = MapNode(c_dirt);
2831                                         else
2832                                                 vmanip.m_data[i] = MapNode(c_sand);*/
2833                                 }
2834                                 /*else if(noisebuf_ground_crumbleness.get(x,y,z) > 0.1)
2835                                 {
2836                                 }*/
2837
2838                                 if(new_content.getContent() != CONTENT_IGNORE)
2839                                 {
2840                                         for(u16 i=0; i<27; i++)
2841                                         {
2842                                                 v3s16 p = v3s16(x,y,z) + g_27dirs[i];
2843                                                 u32 vi = vmanip.m_area.index(p);
2844                                                 if(vmanip.m_data[vi].getContent() == base_content)
2845                                                 {
2846                                                         if(mineralrandom.next()%sparseness == 0)
2847                                                                 vmanip.m_data[vi] = new_content;
2848                                                 }
2849                                         }
2850                                 }
2851                         }
2852                 }
2853                 /*
2854                         Add coal
2855                 */
2856                 //for(s16 i=0; i < MYMAX(0, 50 - abs(node_min.Y+8 - (-30))); i++)
2857                 //for(s16 i=0; i<50; i++)
2858                 u16 coal_amount = 30;
2859                 u16 coal_rareness = 60 / coal_amount;
2860                 if(coal_rareness == 0)
2861                         coal_rareness = 1;
2862                 if(mineralrandom.next()%coal_rareness == 0)
2863                 {
2864                         u16 a = mineralrandom.next() % 16;
2865                         u16 amount = coal_amount * a*a*a / 1000;
2866                         for(s16 i=0; i<amount; i++)
2867                         {
2868                                 s16 x = mineralrandom.range(node_min.X+1, node_max.X-1);
2869                                 s16 y = mineralrandom.range(node_min.Y+1, node_max.Y-1);
2870                                 s16 z = mineralrandom.range(node_min.Z+1, node_max.Z-1);
2871                                 for(u16 i=0; i<27; i++)
2872                                 {
2873                                         v3s16 p = v3s16(x,y,z) + g_27dirs[i];
2874                                         u32 vi = vmanip.m_area.index(p);
2875                                         if(vmanip.m_data[vi].getContent() == c_stone)
2876                                                 if(mineralrandom.next()%8 == 0)
2877                                                         vmanip.m_data[vi] = MapNode(c_stone_with_coal);
2878                                 }
2879                         }
2880                 }
2881                 /*
2882                         Add iron
2883                 */
2884                 u16 iron_amount = 8;
2885                 u16 iron_rareness = 60 / iron_amount;
2886                 if(iron_rareness == 0)
2887                         iron_rareness = 1;
2888                 if(mineralrandom.next()%iron_rareness == 0)
2889                 {
2890                         u16 a = mineralrandom.next() % 16;
2891                         u16 amount = iron_amount * a*a*a / 1000;
2892                         for(s16 i=0; i<amount; i++)
2893                         {
2894                                 s16 x = mineralrandom.range(node_min.X+1, node_max.X-1);
2895                                 s16 y = mineralrandom.range(node_min.Y+1, node_max.Y-1);
2896                                 s16 z = mineralrandom.range(node_min.Z+1, node_max.Z-1);
2897                                 for(u16 i=0; i<27; i++)
2898                                 {
2899                                         v3s16 p = v3s16(x,y,z) + g_27dirs[i];
2900                                         u32 vi = vmanip.m_area.index(p);
2901                                         if(vmanip.m_data[vi].getContent() == c_stone)
2902                                                 if(mineralrandom.next()%8 == 0)
2903                                                         vmanip.m_data[vi] = MapNode(c_stone_with_iron);
2904                                 }
2905                         }
2906                 }
2907         }
2908 #endif
2909
2910         /*
2911                 Calculate lighting
2912         */
2913         {
2914         ScopeProfiler sp(g_profiler, "EmergeThread: mapgen lighting update",
2915                         SPT_AVG);
2916         //VoxelArea a(node_min, node_max);
2917         VoxelArea a(node_min-v3s16(1,0,1)*MAP_BLOCKSIZE,
2918                         node_max+v3s16(1,0,1)*MAP_BLOCKSIZE);
2919         /*VoxelArea a(node_min-v3s16(1,0,1)*MAP_BLOCKSIZE/2,
2920                         node_max+v3s16(1,0,1)*MAP_BLOCKSIZE/2);*/
2921         enum LightBank banks[2] = {LIGHTBANK_DAY, LIGHTBANK_NIGHT};
2922         for(int i=0; i<2; i++)
2923         {
2924                 enum LightBank bank = banks[i];
2925
2926                 core::map<v3s16, bool> light_sources;
2927                 core::map<v3s16, u8> unlight_from;
2928
2929                 voxalgo::clearLightAndCollectSources(vmanip, a, bank, ndef,
2930                                 light_sources, unlight_from);
2931
2932                 bool inexistent_top_provides_sunlight = !block_is_underground;
2933                 voxalgo::SunlightPropagateResult res = voxalgo::propagateSunlight(
2934                                 vmanip, a, inexistent_top_provides_sunlight,
2935                                 light_sources, ndef);
2936                 // TODO: Do stuff according to bottom_sunlight_valid
2937
2938                 vmanip.unspreadLight(bank, unlight_from, light_sources, ndef);
2939
2940                 vmanip.spreadLight(bank, light_sources, ndef);
2941         }
2942         }
2943 }
2944
2945 #endif ///BIG COMMENT
2946
2947 BlockMakeData::BlockMakeData():
2948         no_op(false),
2949         vmanip(NULL),
2950         seed(0),
2951         nodedef(NULL)
2952 {}
2953
2954 BlockMakeData::~BlockMakeData()
2955 {
2956         delete vmanip;
2957 }
2958
2959 //}; // namespace mapgen
2960
2961