3 Copyright (C) 2010-2011 celeron55, Perttu Ahola <celeron55@gmail.com>
5 This program is free software; you can redistribute it and/or modify
6 it under the terms of the GNU General Public License as published by
7 the Free Software Foundation; either version 2 of the License, or
8 (at your option) any later version.
10 This program is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 GNU General Public License for more details.
15 You should have received a copy of the GNU 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.
22 #include "content_mapnode.h"
27 //#include "serverobject.h"
28 #include "content_sao.h"
34 Some helper functions for the map generator
38 static s16 find_ground_level(VoxelManipulator &vmanip, v2s16 p2d)
40 v3s16 em = vmanip.m_area.getExtent();
41 s16 y_nodes_max = vmanip.m_area.MaxEdge.Y;
42 s16 y_nodes_min = vmanip.m_area.MinEdge.Y;
43 u32 i = vmanip.m_area.index(v3s16(p2d.X, y_nodes_max, p2d.Y));
45 for(y=y_nodes_max; y>=y_nodes_min; y--)
47 MapNode &n = vmanip.m_data[i];
48 if(content_walkable(n.d))
51 vmanip.m_area.add_y(em, i, -1);
59 static s16 find_ground_level_clever(VoxelManipulator &vmanip, v2s16 p2d)
61 v3s16 em = vmanip.m_area.getExtent();
62 s16 y_nodes_max = vmanip.m_area.MaxEdge.Y;
63 s16 y_nodes_min = vmanip.m_area.MinEdge.Y;
64 u32 i = vmanip.m_area.index(v3s16(p2d.X, y_nodes_max, p2d.Y));
66 for(y=y_nodes_max; y>=y_nodes_min; y--)
68 MapNode &n = vmanip.m_data[i];
69 if(content_walkable(n.d)
70 && n.d != CONTENT_TREE
71 && n.d != CONTENT_LEAVES)
74 vmanip.m_area.add_y(em, i, -1);
83 static void make_tree(VoxelManipulator &vmanip, v3s16 p0)
85 MapNode treenode(CONTENT_TREE);
86 MapNode leavesnode(CONTENT_LEAVES);
88 s16 trunk_h = myrand_range(3, 6);
90 for(s16 ii=0; ii<trunk_h; ii++)
92 if(vmanip.m_area.contains(p1))
93 vmanip.m_data[vmanip.m_area.index(p1)] = treenode;
97 // p1 is now the last piece of the trunk
100 VoxelArea leaves_a(v3s16(-2,-2,-2), v3s16(2,2,2));
101 //SharedPtr<u8> leaves_d(new u8[leaves_a.getVolume()]);
102 Buffer<u8> leaves_d(leaves_a.getVolume());
103 for(s32 i=0; i<leaves_a.getVolume(); i++)
106 // Force leaves at near the end of the trunk
109 for(s16 z=-d; z<=d; z++)
110 for(s16 y=-d; y<=d; y++)
111 for(s16 x=-d; x<=d; x++)
113 leaves_d[leaves_a.index(v3s16(x,y,z))] = 1;
117 // Add leaves randomly
118 for(u32 iii=0; iii<7; iii++)
123 myrand_range(leaves_a.MinEdge.X, leaves_a.MaxEdge.X-d),
124 myrand_range(leaves_a.MinEdge.Y, leaves_a.MaxEdge.Y-d),
125 myrand_range(leaves_a.MinEdge.Z, leaves_a.MaxEdge.Z-d)
128 for(s16 z=0; z<=d; z++)
129 for(s16 y=0; y<=d; y++)
130 for(s16 x=0; x<=d; x++)
132 leaves_d[leaves_a.index(p+v3s16(x,y,z))] = 1;
136 // Blit leaves to vmanip
137 for(s16 z=leaves_a.MinEdge.Z; z<=leaves_a.MaxEdge.Z; z++)
138 for(s16 y=leaves_a.MinEdge.Y; y<=leaves_a.MaxEdge.Y; y++)
139 for(s16 x=leaves_a.MinEdge.X; x<=leaves_a.MaxEdge.X; x++)
143 if(vmanip.m_area.contains(p) == false)
145 u32 vi = vmanip.m_area.index(p);
146 if(vmanip.m_data[vi].d != CONTENT_AIR
147 && vmanip.m_data[vi].d != CONTENT_IGNORE)
149 u32 i = leaves_a.index(x,y,z);
151 vmanip.m_data[vi] = leavesnode;
155 void make_papyrus(VoxelManipulator &vmanip, v3s16 p0)
157 MapNode papyrusnode(CONTENT_PAPYRUS);
159 s16 trunk_h = myrand_range(2, 3);
161 for(s16 ii=0; ii<trunk_h; ii++)
163 if(vmanip.m_area.contains(p1))
164 vmanip.m_data[vmanip.m_area.index(p1)] = papyrusnode;
169 void make_cactus(VoxelManipulator &vmanip, v3s16 p0)
171 MapNode cactusnode(CONTENT_CACTUS);
175 for(s16 ii=0; ii<trunk_h; ii++)
177 if(vmanip.m_area.contains(p1))
178 vmanip.m_data[vmanip.m_area.index(p1)] = cactusnode;
184 static void make_randomstone(VoxelManipulator &vmanip, v3s16 p0)
186 MapNode stonenode(CONTENT_STONE);
188 s16 size = myrand_range(3, 6);
190 VoxelArea stone_a(v3s16(-2,0,-2), v3s16(2,size,2));
191 Buffer<u8> stone_d(stone_a.getVolume());
192 for(s32 i=0; i<stone_a.getVolume(); i++)
195 // Force stone at bottom to make it usually touch the ground
197 for(s16 z=0; z<=0; z++)
198 for(s16 y=0; y<=0; y++)
199 for(s16 x=0; x<=0; x++)
201 stone_d[stone_a.index(v3s16(x,y,z))] = 1;
205 // Generate from perlin noise
206 for(s16 z=stone_a.MinEdge.Z; z<=stone_a.MaxEdge.Z; z++)
207 for(s16 y=stone_a.MinEdge.Y; y<=stone_a.MaxEdge.Y; y++)
208 for(s16 x=stone_a.MinEdge.X; x<=stone_a.MaxEdge.X; x++)
210 double d = noise3d_perlin((float)x/3.,(float)z/3.,(float)y/3.,
211 p0.Z*4243+p0.Y*34+p0.X, 2, 0.5);
212 if(z == stone_a.MinEdge.Z || z == stone_a.MaxEdge.Z)
214 if(/*y == stone_a.MinEdge.Y ||*/ y == stone_a.MaxEdge.Y)
216 if(x == stone_a.MinEdge.X || x == stone_a.MaxEdge.X)
220 u32 vi = stone_a.index(v3s16(x,y,z));
225 /*// Add stone randomly
226 for(u32 iii=0; iii<7; iii++)
231 myrand_range(stone_a.MinEdge.X, stone_a.MaxEdge.X-d),
232 myrand_range(stone_a.MinEdge.Y, stone_a.MaxEdge.Y-d),
233 myrand_range(stone_a.MinEdge.Z, stone_a.MaxEdge.Z-d)
236 for(s16 z=0; z<=d; z++)
237 for(s16 y=0; y<=d; y++)
238 for(s16 x=0; x<=d; x++)
240 stone_d[stone_a.index(p+v3s16(x,y,z))] = 1;
244 // Blit stone to vmanip
245 for(s16 z=stone_a.MinEdge.Z; z<=stone_a.MaxEdge.Z; z++)
246 for(s16 y=stone_a.MinEdge.Y; y<=stone_a.MaxEdge.Y; y++)
247 for(s16 x=stone_a.MinEdge.X; x<=stone_a.MaxEdge.X; x++)
251 if(vmanip.m_area.contains(p) == false)
253 u32 vi = vmanip.m_area.index(p);
254 if(vmanip.m_data[vi].d != CONTENT_AIR
255 && vmanip.m_data[vi].d != CONTENT_IGNORE)
257 u32 i = stone_a.index(x,y,z);
259 vmanip.m_data[vi] = stonenode;
265 static void make_largestone(VoxelManipulator &vmanip, v3s16 p0)
267 MapNode stonenode(CONTENT_STONE);
269 s16 size = myrand_range(8, 16);
271 VoxelArea stone_a(v3s16(-size/2,0,-size/2), v3s16(size/2,size,size/2));
272 Buffer<u8> stone_d(stone_a.getVolume());
273 for(s32 i=0; i<stone_a.getVolume(); i++)
276 // Force stone at bottom to make it usually touch the ground
278 for(s16 z=0; z<=0; z++)
279 for(s16 y=0; y<=0; y++)
280 for(s16 x=0; x<=0; x++)
282 stone_d[stone_a.index(v3s16(x,y,z))] = 1;
286 // Generate from perlin noise
287 for(s16 z=stone_a.MinEdge.Z; z<=stone_a.MaxEdge.Z; z++)
288 for(s16 y=stone_a.MinEdge.Y; y<=stone_a.MaxEdge.Y; y++)
289 for(s16 x=stone_a.MinEdge.X; x<=stone_a.MaxEdge.X; x++)
292 d += noise3d_perlin((float)x/10.,(float)z/10.,(float)y/10.,
293 p0.Z*5123+p0.Y*2439+p0.X, 2, 0.5);
294 double mid_z = (stone_a.MaxEdge.Z+stone_a.MinEdge.Z)/2;
295 double mid_x = (stone_a.MaxEdge.X+stone_a.MinEdge.X)/2;
296 double mid_y = (stone_a.MaxEdge.Y+stone_a.MinEdge.Y)/2;
297 double dz = (double)z-mid_z;
298 double dx = (double)x-mid_x;
299 double dy = MYMAX(0, (double)y-mid_y);
300 double r = sqrt(dz*dz+dx*dx+dy*dy);
301 d /= (2*r/size)*2 + 0.01;
304 u32 vi = stone_a.index(v3s16(x,y,z));
309 /*// Add stone randomly
310 for(u32 iii=0; iii<7; iii++)
315 myrand_range(stone_a.MinEdge.X, stone_a.MaxEdge.X-d),
316 myrand_range(stone_a.MinEdge.Y, stone_a.MaxEdge.Y-d),
317 myrand_range(stone_a.MinEdge.Z, stone_a.MaxEdge.Z-d)
320 for(s16 z=0; z<=d; z++)
321 for(s16 y=0; y<=d; y++)
322 for(s16 x=0; x<=d; x++)
324 stone_d[stone_a.index(p+v3s16(x,y,z))] = 1;
328 // Blit stone to vmanip
329 for(s16 z=stone_a.MinEdge.Z; z<=stone_a.MaxEdge.Z; z++)
330 for(s16 y=stone_a.MinEdge.Y; y<=stone_a.MaxEdge.Y; y++)
331 for(s16 x=stone_a.MinEdge.X; x<=stone_a.MaxEdge.X; x++)
335 if(vmanip.m_area.contains(p) == false)
337 u32 vi = vmanip.m_area.index(p);
338 /*if(vmanip.m_data[vi].d != CONTENT_AIR
339 && vmanip.m_data[vi].d != CONTENT_IGNORE)
341 u32 i = stone_a.index(x,y,z);
343 vmanip.m_data[vi] = stonenode;
349 Dungeon making routines
352 #define VMANIP_FLAG_DUNGEON_INSIDE VOXELFLAG_CHECKED1
353 #define VMANIP_FLAG_DUNGEON_PRESERVE VOXELFLAG_CHECKED2
354 #define VMANIP_FLAG_DUNGEON_UNTOUCHABLE (\
355 VMANIP_FLAG_DUNGEON_INSIDE|VMANIP_FLAG_DUNGEON_PRESERVE)
357 static void make_room1(VoxelManipulator &vmanip, v3s16 roomsize, v3s16 roomplace)
360 for(s16 z=0; z<roomsize.Z; z++)
361 for(s16 y=0; y<roomsize.Y; y++)
364 v3s16 p = roomplace + v3s16(0,y,z);
365 if(vmanip.m_area.contains(p) == false)
367 u32 vi = vmanip.m_area.index(p);
368 if(vmanip.m_flags[vi] & VMANIP_FLAG_DUNGEON_UNTOUCHABLE)
370 vmanip.m_data[vi] = MapNode(CONTENT_COBBLE);
373 v3s16 p = roomplace + v3s16(roomsize.X-1,y,z);
374 if(vmanip.m_area.contains(p) == false)
376 u32 vi = vmanip.m_area.index(p);
377 if(vmanip.m_flags[vi] & VMANIP_FLAG_DUNGEON_UNTOUCHABLE)
379 vmanip.m_data[vi] = MapNode(CONTENT_COBBLE);
384 for(s16 x=0; x<roomsize.X; x++)
385 for(s16 y=0; y<roomsize.Y; y++)
388 v3s16 p = roomplace + v3s16(x,y,0);
389 if(vmanip.m_area.contains(p) == false)
391 u32 vi = vmanip.m_area.index(p);
392 if(vmanip.m_flags[vi] & VMANIP_FLAG_DUNGEON_UNTOUCHABLE)
394 vmanip.m_data[vi] = MapNode(CONTENT_COBBLE);
397 v3s16 p = roomplace + v3s16(x,y,roomsize.Z-1);
398 if(vmanip.m_area.contains(p) == false)
400 u32 vi = vmanip.m_area.index(p);
401 if(vmanip.m_flags[vi] & VMANIP_FLAG_DUNGEON_UNTOUCHABLE)
403 vmanip.m_data[vi] = MapNode(CONTENT_COBBLE);
407 // Make +-Y walls (floor and ceiling)
408 for(s16 z=0; z<roomsize.Z; z++)
409 for(s16 x=0; x<roomsize.X; x++)
412 v3s16 p = roomplace + v3s16(x,0,z);
413 if(vmanip.m_area.contains(p) == false)
415 u32 vi = vmanip.m_area.index(p);
416 if(vmanip.m_flags[vi] & VMANIP_FLAG_DUNGEON_UNTOUCHABLE)
418 vmanip.m_data[vi] = MapNode(CONTENT_COBBLE);
421 v3s16 p = roomplace + v3s16(x,roomsize.Y-1,z);
422 if(vmanip.m_area.contains(p) == false)
424 u32 vi = vmanip.m_area.index(p);
425 if(vmanip.m_flags[vi] & VMANIP_FLAG_DUNGEON_UNTOUCHABLE)
427 vmanip.m_data[vi] = MapNode(CONTENT_COBBLE);
432 for(s16 z=1; z<roomsize.Z-1; z++)
433 for(s16 y=1; y<roomsize.Y-1; y++)
434 for(s16 x=1; x<roomsize.X-1; x++)
436 v3s16 p = roomplace + v3s16(x,y,z);
437 if(vmanip.m_area.contains(p) == false)
439 u32 vi = vmanip.m_area.index(p);
440 vmanip.m_flags[vi] |= VMANIP_FLAG_DUNGEON_UNTOUCHABLE;
441 vmanip.m_data[vi] = MapNode(CONTENT_AIR);
445 static void make_fill(VoxelManipulator &vmanip, v3s16 place, v3s16 size,
446 u8 avoid_flags, MapNode n, u8 or_flags)
448 for(s16 z=0; z<size.Z; z++)
449 for(s16 y=0; y<size.Y; y++)
450 for(s16 x=0; x<size.X; x++)
452 v3s16 p = place + v3s16(x,y,z);
453 if(vmanip.m_area.contains(p) == false)
455 u32 vi = vmanip.m_area.index(p);
456 if(vmanip.m_flags[vi] & avoid_flags)
458 vmanip.m_flags[vi] |= or_flags;
459 vmanip.m_data[vi] = n;
463 static void make_hole1(VoxelManipulator &vmanip, v3s16 place)
465 make_fill(vmanip, place, v3s16(1,2,1), 0, MapNode(CONTENT_AIR),
466 VMANIP_FLAG_DUNGEON_INSIDE);
469 static void make_door1(VoxelManipulator &vmanip, v3s16 doorplace, v3s16 doordir)
471 make_hole1(vmanip, doorplace);
472 // Place torch (for testing)
473 //vmanip.m_data[vmanip.m_area.index(doorplace)] = MapNode(CONTENT_TORCH);
476 static v3s16 rand_ortho_dir(PseudoRandom &random)
478 if(random.next()%2==0)
479 return random.next()%2 ? v3s16(-1,0,0) : v3s16(1,0,0);
481 return random.next()%2 ? v3s16(0,0,-1) : v3s16(0,0,1);
484 static v3s16 turn_xz(v3s16 olddir, int t)
504 static v3s16 random_turn(PseudoRandom &random, v3s16 olddir)
506 int turn = random.range(0,2);
515 dir = turn_xz(olddir, 0);
518 dir = turn_xz(olddir, 1);
522 static void make_corridor(VoxelManipulator &vmanip, v3s16 doorplace,
523 v3s16 doordir, v3s16 &result_place, v3s16 &result_dir,
524 PseudoRandom &random)
526 make_hole1(vmanip, doorplace);
527 v3s16 p0 = doorplace;
531 length = random.range(1,13);
533 length = random.range(1,6);
534 length = random.range(1,13);
535 u32 partlength = random.range(1,13);
538 if(random.next()%2 == 0 && partlength >= 3)
539 make_stairs = random.next()%2 ? 1 : -1;
540 for(u32 i=0; i<length; i++)
546 /*// If already empty
547 if(vmanip.getNodeNoExNoEmerge(p).d
549 && vmanip.getNodeNoExNoEmerge(p+v3s16(0,1,0)).d
554 if(vmanip.m_area.contains(p) == true
555 && vmanip.m_area.contains(p+v3s16(0,1,0)) == true)
559 make_fill(vmanip, p+v3s16(-1,-1,-1), v3s16(3,5,3),
560 VMANIP_FLAG_DUNGEON_UNTOUCHABLE, MapNode(CONTENT_COBBLE), 0);
561 make_fill(vmanip, p, v3s16(1,2,1), 0, MapNode(CONTENT_AIR),
562 VMANIP_FLAG_DUNGEON_INSIDE);
563 make_fill(vmanip, p-dir, v3s16(1,2,1), 0, MapNode(CONTENT_AIR),
564 VMANIP_FLAG_DUNGEON_INSIDE);
568 make_fill(vmanip, p+v3s16(-1,-1,-1), v3s16(3,4,3),
569 VMANIP_FLAG_DUNGEON_UNTOUCHABLE, MapNode(CONTENT_COBBLE), 0);
570 make_hole1(vmanip, p);
571 /*make_fill(vmanip, p, v3s16(1,2,1), 0, MapNode(CONTENT_AIR),
572 VMANIP_FLAG_DUNGEON_INSIDE);*/
579 // Can't go here, turn away
580 dir = turn_xz(dir, random.range(0,1));
581 make_stairs = -make_stairs;
583 partlength = random.range(1,length);
588 if(partcount >= partlength)
592 dir = random_turn(random, dir);
594 partlength = random.range(1,length);
597 if(random.next()%2 == 0 && partlength >= 3)
598 make_stairs = random.next()%2 ? 1 : -1;
609 RoomWalker(VoxelManipulator &vmanip_, v3s16 pos, PseudoRandom &random):
619 m_dir = rand_ortho_dir(m_random);
622 void setPos(v3s16 pos)
627 void setDir(v3s16 dir)
632 bool findPlaceForDoor(v3s16 &result_place, v3s16 &result_dir)
634 for(u32 i=0; i<100; i++)
636 v3s16 p = m_pos + m_dir;
637 v3s16 p1 = p + v3s16(0,1,0);
638 if(vmanip.m_area.contains(p) == false
639 || vmanip.m_area.contains(p1) == false
645 if(vmanip.getNodeNoExNoEmerge(p).d
647 && vmanip.getNodeNoExNoEmerge(p1).d
650 // Found wall, this is a good place!
653 // Randomize next direction
658 Determine where to move next
660 // Jump one up if the actual space is there
661 if(vmanip.getNodeNoExNoEmerge(p+v3s16(0,0,0)).d
663 && vmanip.getNodeNoExNoEmerge(p+v3s16(0,1,0)).d
665 && vmanip.getNodeNoExNoEmerge(p+v3s16(0,2,0)).d
668 // Jump one down if the actual space is there
669 if(vmanip.getNodeNoExNoEmerge(p+v3s16(0,1,0)).d
671 && vmanip.getNodeNoExNoEmerge(p+v3s16(0,0,0)).d
673 && vmanip.getNodeNoExNoEmerge(p+v3s16(0,-1,0)).d
676 // Check if walking is now possible
677 if(vmanip.getNodeNoExNoEmerge(p).d
679 || vmanip.getNodeNoExNoEmerge(p+v3s16(0,1,0)).d
682 // Cannot continue walking here
692 bool findPlaceForRoomDoor(v3s16 roomsize, v3s16 &result_doorplace,
693 v3s16 &result_doordir, v3s16 &result_roomplace)
695 for(s16 trycount=0; trycount<30; trycount++)
699 bool r = findPlaceForDoor(doorplace, doordir);
703 // X east, Z north, Y up
705 if(doordir == v3s16(1,0,0)) // X+
706 roomplace = doorplace +
707 v3s16(0,-1,m_random.range(-roomsize.Z+2,-2));
708 if(doordir == v3s16(-1,0,0)) // X-
709 roomplace = doorplace +
710 v3s16(-roomsize.X+1,-1,m_random.range(-roomsize.Z+2,-2));
711 if(doordir == v3s16(0,0,1)) // Z+
712 roomplace = doorplace +
713 v3s16(m_random.range(-roomsize.X+2,-2),-1,0);
714 if(doordir == v3s16(0,0,-1)) // Z-
715 roomplace = doorplace +
716 v3s16(m_random.range(-roomsize.X+2,-2),-1,-roomsize.Z+1);
719 if(doordir == v3s16(1,0,0)) // X+
720 roomplace = doorplace + v3s16(0,-1,-roomsize.Z/2);
721 if(doordir == v3s16(-1,0,0)) // X-
722 roomplace = doorplace + v3s16(-roomsize.X+1,-1,-roomsize.Z/2);
723 if(doordir == v3s16(0,0,1)) // Z+
724 roomplace = doorplace + v3s16(-roomsize.X/2,-1,0);
725 if(doordir == v3s16(0,0,-1)) // Z-
726 roomplace = doorplace + v3s16(-roomsize.X/2,-1,-roomsize.Z+1);
731 for(s16 z=1; z<roomsize.Z-1; z++)
732 for(s16 y=1; y<roomsize.Y-1; y++)
733 for(s16 x=1; x<roomsize.X-1; x++)
735 v3s16 p = roomplace + v3s16(x,y,z);
736 if(vmanip.m_area.contains(p) == false)
741 if(vmanip.m_flags[vmanip.m_area.index(p)]
742 & VMANIP_FLAG_DUNGEON_INSIDE)
753 result_doorplace = doorplace;
754 result_doordir = doordir;
755 result_roomplace = roomplace;
762 VoxelManipulator &vmanip;
765 PseudoRandom &m_random;
768 static void make_dungeon1(VoxelManipulator &vmanip, PseudoRandom &random)
770 v3s16 areasize = vmanip.m_area.getExtent();
775 Find place for first room
778 for(u32 i=0; i<100; i++)
780 roomsize = v3s16(random.range(4,8),random.range(4,6),random.range(4,8));
781 roomplace = vmanip.m_area.MinEdge + v3s16(
782 random.range(0,areasize.X-roomsize.X-1),
783 random.range(0,areasize.Y-roomsize.Y-1),
784 random.range(0,areasize.Z-roomsize.Z-1));
786 Check that we're not putting the room to an unknown place,
787 otherwise it might end up floating in the air
790 for(s16 z=1; z<roomsize.Z-1; z++)
791 for(s16 y=1; y<roomsize.Y-1; y++)
792 for(s16 x=1; x<roomsize.X-1; x++)
794 v3s16 p = roomplace + v3s16(x,y,z);
795 u32 vi = vmanip.m_area.index(p);
796 if(vmanip.m_flags[vi] & VMANIP_FLAG_DUNGEON_INSIDE)
801 if(vmanip.m_data[vi].d == CONTENT_IGNORE)
815 Stores the center position of the last room made, so that
816 a new corridor can be started from the last room instead of
817 the new room, if chosen so.
819 v3s16 last_room_center = roomplace+v3s16(roomsize.X/2,1,roomsize.Z/2);
821 u32 room_count = random.range(2,7);
822 for(u32 i=0; i<room_count; i++)
824 // Make a room to the determined place
825 make_room1(vmanip, roomsize, roomplace);
827 v3s16 room_center = roomplace + v3s16(roomsize.X/2,1,roomsize.Z/2);
829 // Place torch at room center (for testing)
830 //vmanip.m_data[vmanip.m_area.index(room_center)] = MapNode(CONTENT_TORCH);
833 if(i == room_count-1)
836 // Determine walker start position
838 bool start_in_last_room = (random.range(0,2)!=0);
839 //bool start_in_last_room = true;
841 v3s16 walker_start_place;
843 if(start_in_last_room)
845 walker_start_place = last_room_center;
849 walker_start_place = room_center;
850 // Store center of current room as the last one
851 last_room_center = room_center;
854 // Create walker and find a place for a door
855 RoomWalker walker(vmanip, walker_start_place, random);
858 bool r = walker.findPlaceForDoor(doorplace, doordir);
862 if(random.range(0,1)==0)
864 make_door1(vmanip, doorplace, doordir);
866 // Don't actually make a door
867 doorplace -= doordir;
869 // Make a random corridor starting from the door
871 v3s16 corridor_end_dir;
872 make_corridor(vmanip, doorplace, doordir, corridor_end,
873 corridor_end_dir, random);
875 // Find a place for a random sized room
876 roomsize = v3s16(random.range(4,8),random.range(4,6),random.range(4,8));
877 walker.setPos(corridor_end);
878 walker.setDir(corridor_end_dir);
879 r = walker.findPlaceForRoomDoor(roomsize, doorplace, doordir, roomplace);
883 if(random.range(0,1)==0)
885 make_door1(vmanip, doorplace, doordir);
887 // Don't actually make a door
888 roomplace -= doordir;
894 Noise functions. Make sure seed is mangled differently in each one.
898 Scaling the output of the noise function affects the overdrive of the
899 contour function, which affects the shape of the output considerably.
901 #define CAVE_NOISE_SCALE 12.0
902 //#define CAVE_NOISE_SCALE 10.0
903 //#define CAVE_NOISE_SCALE 7.5
904 //#define CAVE_NOISE_SCALE 5.0
905 //#define CAVE_NOISE_SCALE 1.0
907 //#define CAVE_NOISE_THRESHOLD (2.5/CAVE_NOISE_SCALE)
908 #define CAVE_NOISE_THRESHOLD (1.5/CAVE_NOISE_SCALE)
910 NoiseParams get_cave_noise1_params(u64 seed)
912 /*return NoiseParams(NOISE_PERLIN_CONTOUR, seed+52534, 5, 0.7,
913 200, CAVE_NOISE_SCALE);*/
914 /*return NoiseParams(NOISE_PERLIN_CONTOUR, seed+52534, 4, 0.7,
915 100, CAVE_NOISE_SCALE);*/
916 /*return NoiseParams(NOISE_PERLIN_CONTOUR, seed+52534, 5, 0.6,
917 100, CAVE_NOISE_SCALE);*/
918 /*return NoiseParams(NOISE_PERLIN_CONTOUR, seed+52534, 5, 0.3,
919 100, CAVE_NOISE_SCALE);*/
920 return NoiseParams(NOISE_PERLIN_CONTOUR, seed+52534, 4, 0.5,
921 50, CAVE_NOISE_SCALE);
922 //return NoiseParams(NOISE_CONSTANT_ONE);
925 NoiseParams get_cave_noise2_params(u64 seed)
927 /*return NoiseParams(NOISE_PERLIN_CONTOUR_FLIP_YZ, seed+10325, 5, 0.7,
928 200, CAVE_NOISE_SCALE);*/
929 /*return NoiseParams(NOISE_PERLIN_CONTOUR_FLIP_YZ, seed+10325, 4, 0.7,
930 100, CAVE_NOISE_SCALE);*/
931 /*return NoiseParams(NOISE_PERLIN_CONTOUR_FLIP_YZ, seed+10325, 5, 0.3,
932 100, CAVE_NOISE_SCALE);*/
933 return NoiseParams(NOISE_PERLIN_CONTOUR_FLIP_YZ, seed+10325, 4, 0.5,
934 50, CAVE_NOISE_SCALE);
935 //return NoiseParams(NOISE_CONSTANT_ONE);
938 NoiseParams get_ground_noise1_params(u64 seed)
940 return NoiseParams(NOISE_PERLIN, seed+983240, 4,
944 NoiseParams get_ground_crumbleness_params(u64 seed)
946 return NoiseParams(NOISE_PERLIN, seed+34413, 3,
950 NoiseParams get_ground_wetness_params(u64 seed)
952 return NoiseParams(NOISE_PERLIN, seed+32474, 4,
956 bool is_cave(u64 seed, v3s16 p)
958 double d1 = noise3d_param(get_cave_noise1_params(seed), p.X,p.Y,p.Z);
959 double d2 = noise3d_param(get_cave_noise2_params(seed), p.X,p.Y,p.Z);
960 return d1*d2 > CAVE_NOISE_THRESHOLD;
964 Ground density noise shall be interpreted by using this.
966 TODO: No perlin noises here, they should be outsourced
968 NOTE: The speed of these actually isn't terrible
970 bool val_is_ground(double ground_noise1_val, v3s16 p, u64 seed)
972 //return ((double)p.Y < ground_noise1_val);
974 double f = 0.55 + noise2d_perlin(
975 0.5+(float)p.X/250, 0.5+(float)p.Z/250,
976 seed+920381, 3, 0.45);
981 double h = WATER_LEVEL + 10 * noise2d_perlin(
982 0.5+(float)p.X/250, 0.5+(float)p.Z/250,
986 return ((double)p.Y - h < ground_noise1_val * f);
990 Queries whether a position is ground or not.
992 bool is_ground(u64 seed, v3s16 p)
994 double val1 = noise3d_param(get_ground_noise1_params(seed), p.X,p.Y,p.Z);
995 return val_is_ground(val1, p, seed);
998 // Amount of trees per area in nodes
999 double tree_amount_2d(u64 seed, v2s16 p)
1001 /*double noise = noise2d_perlin(
1002 0.5+(float)p.X/250, 0.5+(float)p.Y/250,
1004 double noise = noise2d_perlin(
1005 0.5+(float)p.X/125, 0.5+(float)p.Y/125,
1007 double zeroval = -0.35;
1011 return 0.04 * (noise-zeroval) / (1.0-zeroval);
1015 double randomstone_amount_2d(u64 seed, v2s16 p)
1017 double noise = noise2d_perlin(
1018 0.5+(float)p.X/250, 0.5+(float)p.Y/250,
1019 seed+3829434, 5, 0.66);
1020 double zeroval = 0.1;
1024 return 0.01 * (noise-zeroval) / (1.0-zeroval);
1028 double largestone_amount_2d(u64 seed, v2s16 p)
1030 double noise = noise2d_perlin(
1031 0.5+(float)p.X/250, 0.5+(float)p.Y/250,
1032 seed+14143242, 5, 0.66);
1033 double zeroval = 0.3;
1037 return 0.005 * (noise-zeroval) / (1.0-zeroval);
1041 Incrementally find ground level from 3d noise
1043 s16 find_ground_level_from_noise(u64 seed, v2s16 p2d, s16 precision)
1045 // Start a bit fuzzy to make averaging lower precision values
1047 s16 level = myrand_range(-precision/2, precision/2);
1048 s16 dec[] = {31000, 100, 20, 4, 1, 0};
1050 for(i = 1; dec[i] != 0 && precision <= dec[i]; i++)
1052 // First find non-ground by going upwards
1053 // Don't stop in caves.
1055 s16 max = level+dec[i-1]*2;
1056 v3s16 p(p2d.X, level, p2d.Y);
1057 for(; p.Y < max; p.Y += dec[i])
1059 if(!is_ground(seed, p))
1066 // Then find ground by going downwards from there.
1067 // Go in caves, too, when precision is 1.
1069 s16 min = level-dec[i-1]*2;
1070 v3s16 p(p2d.X, level, p2d.Y);
1071 for(; p.Y>min; p.Y-=dec[i])
1073 bool ground = is_ground(seed, p);
1074 /*if(dec[i] == 1 && is_cave(seed, p))
1085 // This is more like the actual ground level
1086 level += dec[i-1]/2;
1091 double get_sector_average_ground_level(u64 seed, v2s16 sectorpos, double p=4);
1093 double get_sector_average_ground_level(u64 seed, v2s16 sectorpos, double p)
1095 v2s16 node_min = sectorpos*MAP_BLOCKSIZE;
1096 v2s16 node_max = (sectorpos+v2s16(1,1))*MAP_BLOCKSIZE-v2s16(1,1);
1098 a += find_ground_level_from_noise(seed,
1099 v2s16(node_min.X, node_min.Y), p);
1100 a += find_ground_level_from_noise(seed,
1101 v2s16(node_min.X, node_max.Y), p);
1102 a += find_ground_level_from_noise(seed,
1103 v2s16(node_max.X, node_max.Y), p);
1104 a += find_ground_level_from_noise(seed,
1105 v2s16(node_max.X, node_min.Y), p);
1106 a += find_ground_level_from_noise(seed,
1107 v2s16(node_min.X+MAP_BLOCKSIZE/2, node_min.Y+MAP_BLOCKSIZE/2), p);
1112 double get_sector_maximum_ground_level(u64 seed, v2s16 sectorpos, double p=4);
1114 double get_sector_maximum_ground_level(u64 seed, v2s16 sectorpos, double p)
1116 v2s16 node_min = sectorpos*MAP_BLOCKSIZE;
1117 v2s16 node_max = (sectorpos+v2s16(1,1))*MAP_BLOCKSIZE-v2s16(1,1);
1120 a = MYMAX(a, find_ground_level_from_noise(seed,
1121 v2s16(node_min.X, node_min.Y), p));
1122 a = MYMAX(a, find_ground_level_from_noise(seed,
1123 v2s16(node_min.X, node_max.Y), p));
1124 a = MYMAX(a, find_ground_level_from_noise(seed,
1125 v2s16(node_max.X, node_max.Y), p));
1126 a = MYMAX(a, find_ground_level_from_noise(seed,
1127 v2s16(node_min.X, node_min.Y), p));
1129 a = MYMAX(a, find_ground_level_from_noise(seed,
1130 v2s16(node_min.X+MAP_BLOCKSIZE/2, node_min.Y+MAP_BLOCKSIZE/2), p));
1131 // Side middle points
1132 a = MYMAX(a, find_ground_level_from_noise(seed,
1133 v2s16(node_min.X+MAP_BLOCKSIZE/2, node_min.Y), p));
1134 a = MYMAX(a, find_ground_level_from_noise(seed,
1135 v2s16(node_min.X+MAP_BLOCKSIZE/2, node_max.Y), p));
1136 a = MYMAX(a, find_ground_level_from_noise(seed,
1137 v2s16(node_min.X, node_min.Y+MAP_BLOCKSIZE/2), p));
1138 a = MYMAX(a, find_ground_level_from_noise(seed,
1139 v2s16(node_max.X, node_min.Y+MAP_BLOCKSIZE/2), p));
1143 double get_sector_minimum_ground_level(u64 seed, v2s16 sectorpos, double p=4);
1145 double get_sector_minimum_ground_level(u64 seed, v2s16 sectorpos, double p)
1147 v2s16 node_min = sectorpos*MAP_BLOCKSIZE;
1148 v2s16 node_max = (sectorpos+v2s16(1,1))*MAP_BLOCKSIZE-v2s16(1,1);
1151 a = MYMIN(a, find_ground_level_from_noise(seed,
1152 v2s16(node_min.X, node_min.Y), p));
1153 a = MYMIN(a, find_ground_level_from_noise(seed,
1154 v2s16(node_min.X, node_max.Y), p));
1155 a = MYMIN(a, find_ground_level_from_noise(seed,
1156 v2s16(node_max.X, node_max.Y), p));
1157 a = MYMIN(a, find_ground_level_from_noise(seed,
1158 v2s16(node_min.X, node_min.Y), p));
1160 a = MYMIN(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 = MYMIN(a, find_ground_level_from_noise(seed,
1164 v2s16(node_min.X+MAP_BLOCKSIZE/2, node_min.Y), p));
1165 a = MYMIN(a, find_ground_level_from_noise(seed,
1166 v2s16(node_min.X+MAP_BLOCKSIZE/2, node_max.Y), p));
1167 a = MYMIN(a, find_ground_level_from_noise(seed,
1168 v2s16(node_min.X, node_min.Y+MAP_BLOCKSIZE/2), p));
1169 a = MYMIN(a, find_ground_level_from_noise(seed,
1170 v2s16(node_max.X, node_min.Y+MAP_BLOCKSIZE/2), p));
1174 bool block_is_underground(u64 seed, v3s16 blockpos)
1176 s16 minimum_groundlevel = (s16)get_sector_minimum_ground_level(
1177 seed, v2s16(blockpos.X, blockpos.Z));
1179 if(blockpos.Y*MAP_BLOCKSIZE + MAP_BLOCKSIZE <= minimum_groundlevel)
1186 #define AVERAGE_MUD_AMOUNT 4
1188 double base_rock_level_2d(u64 seed, v2s16 p)
1190 // The base ground level
1191 double base = (double)WATER_LEVEL - (double)AVERAGE_MUD_AMOUNT
1192 + 20. * noise2d_perlin(
1193 0.5+(float)p.X/500., 0.5+(float)p.Y/500.,
1194 (seed>>32)+654879876, 6, 0.6);
1196 /*// A bit hillier one
1197 double base2 = WATER_LEVEL - 4.0 + 40. * noise2d_perlin(
1198 0.5+(float)p.X/250., 0.5+(float)p.Y/250.,
1199 (seed>>27)+90340, 6, 0.69);
1203 // Higher ground level
1204 double higher = (double)WATER_LEVEL + 25. + 35. * noise2d_perlin(
1205 0.5+(float)p.X/250., 0.5+(float)p.Y/250.,
1206 seed+85039, 5, 0.69);
1207 //higher = 30; // For debugging
1209 // Limit higher to at least base
1213 // Steepness factor of cliffs
1214 double b = 1.0 + 1.0 * noise2d_perlin(
1215 0.5+(float)p.X/250., 0.5+(float)p.Y/250.,
1217 b = rangelim(b, 0.0, 1000.0);
1220 b = rangelim(b, 3.0, 1000.0);
1221 //dstream<<"b="<<b<<std::endl;
1224 // Offset to more low
1225 double a_off = -0.2;
1226 // High/low selector
1227 /*double a = 0.5 + b * (a_off + noise2d_perlin(
1228 0.5+(float)p.X/500., 0.5+(float)p.Y/500.,
1229 seed-359, 6, 0.7));*/
1230 double a = (double)0.5 + b * (a_off + noise2d_perlin(
1231 0.5+(float)p.X/250., 0.5+(float)p.Y/250.,
1232 seed-359, 5, 0.60));
1234 a = rangelim(a, 0.0, 1.0);
1236 //dstream<<"a="<<a<<std::endl;
1238 double h = base*(1.0-a) + higher*a;
1245 double get_mud_add_amount(u64 seed, v2s16 p)
1247 return ((float)AVERAGE_MUD_AMOUNT + 3.0 * noise2d_perlin(
1248 0.5+(float)p.X/200, 0.5+(float)p.Y/200,
1249 seed+91013, 3, 0.55));
1253 bool get_have_sand(u64 seed, v2s16 p2d)
1255 // Determine whether to have sand here
1256 double sandnoise = noise2d_perlin(
1257 0.5+(float)p2d.X/500, 0.5+(float)p2d.Y/500,
1258 seed+59420, 3, 0.50);
1260 return (sandnoise > -0.15);
1264 Adds random objects to block, depending on the content of the block
1266 void add_random_objects(MapBlock *block)
1268 for(s16 z0=0; z0<MAP_BLOCKSIZE; z0++)
1269 for(s16 x0=0; x0<MAP_BLOCKSIZE; x0++)
1271 bool last_node_walkable = false;
1272 for(s16 y0=0; y0<MAP_BLOCKSIZE; y0++)
1275 MapNode n = block->getNodeNoEx(p);
1276 if(n.d == CONTENT_IGNORE)
1278 if(content_features(n.d).liquid_type != LIQUID_NONE)
1280 if(content_features(n.d).walkable)
1282 last_node_walkable = true;
1285 if(last_node_walkable)
1287 // If block contains light information
1288 if(content_features(n.d).param_type == CPT_LIGHT)
1290 if(n.getLight(LIGHTBANK_DAY) <= 3)
1292 if(myrand() % 300 == 0)
1294 v3f pos_f = intToFloat(p+block->getPosRelative(), BS);
1296 ServerActiveObject *obj = new RatSAO(NULL, 0, pos_f);
1297 std::string data = obj->getStaticData();
1298 StaticObject s_obj(obj->getType(),
1299 obj->getBasePosition(), data);
1301 block->m_static_objects.insert(0, s_obj);
1302 block->m_static_objects.insert(0, s_obj);
1303 block->m_static_objects.insert(0, s_obj);
1304 block->m_static_objects.insert(0, s_obj);
1305 block->m_static_objects.insert(0, s_obj);
1306 block->m_static_objects.insert(0, s_obj);
1309 if(myrand() % 1000 == 0)
1311 v3f pos_f = intToFloat(p+block->getPosRelative(), BS);
1313 ServerActiveObject *obj = new Oerkki1SAO(NULL,0,pos_f);
1314 std::string data = obj->getStaticData();
1315 StaticObject s_obj(obj->getType(),
1316 obj->getBasePosition(), data);
1318 block->m_static_objects.insert(0, s_obj);
1324 last_node_walkable = false;
1327 block->setChangedFlag();
1330 void make_block(BlockMakeData *data)
1334 dstream<<"makeBlock: no-op"<<std::endl;
1338 v3s16 blockpos = data->blockpos;
1340 /*dstream<<"makeBlock(): ("<<blockpos.X<<","<<blockpos.Y<<","
1341 <<blockpos.Z<<")"<<std::endl;*/
1343 ManualMapVoxelManipulator &vmanip = *(data->vmanip);
1344 v3s16 blockpos_min = blockpos - v3s16(1,1,1);
1345 v3s16 blockpos_max = blockpos + v3s16(1,1,1);
1346 // Area of center block
1347 v3s16 node_min = blockpos*MAP_BLOCKSIZE;
1348 v3s16 node_max = (blockpos+v3s16(1,1,1))*MAP_BLOCKSIZE-v3s16(1,1,1);
1349 // Full allocated area
1350 v3s16 full_node_min = (blockpos-1)*MAP_BLOCKSIZE;
1351 v3s16 full_node_max = (blockpos+2)*MAP_BLOCKSIZE-v3s16(1,1,1);
1353 double block_area_nodes = MAP_BLOCKSIZE*MAP_BLOCKSIZE;
1355 v2s16 p2d_center(node_min.X+MAP_BLOCKSIZE/2, node_min.Z+MAP_BLOCKSIZE/2);
1358 Get average ground level from noise
1361 s16 approx_groundlevel = (s16)get_sector_average_ground_level(
1362 data->seed, v2s16(blockpos.X, blockpos.Z));
1363 //dstream<<"approx_groundlevel="<<approx_groundlevel<<std::endl;
1365 s16 approx_ground_depth = approx_groundlevel - (node_min.Y+MAP_BLOCKSIZE/2);
1367 s16 minimum_groundlevel = (s16)get_sector_minimum_ground_level(
1368 data->seed, v2s16(blockpos.X, blockpos.Z));
1369 // Minimum amount of ground above the top of the central block
1370 s16 minimum_ground_depth = minimum_groundlevel - node_max.Y;
1372 s16 maximum_groundlevel = (s16)get_sector_maximum_ground_level(
1373 data->seed, v2s16(blockpos.X, blockpos.Z), 1);
1374 // Maximum amount of ground above the bottom of the central block
1375 s16 maximum_ground_depth = maximum_groundlevel - node_min.Y;
1379 Special case for high air or water: Just fill with air and water.
1381 if(maximum_ground_depth < -20)
1383 for(s16 x=node_min.X; x<=node_max.X; x++)
1384 for(s16 z=node_min.Z; z<=node_max.Z; z++)
1389 // Use fast index incrementing
1390 v3s16 em = vmanip.m_area.getExtent();
1391 u32 i = vmanip.m_area.index(v3s16(p2d.X, node_min.Y, p2d.Y));
1392 for(s16 y=node_min.Y; y<=node_max.Y; y++)
1394 // Only modify places that have no content
1395 if(vmanip.m_data[i].d == CONTENT_IGNORE)
1397 if(y <= WATER_LEVEL)
1398 vmanip.m_data[i] = MapNode(CONTENT_WATERSOURCE);
1400 vmanip.m_data[i] = MapNode(CONTENT_AIR);
1403 data->vmanip->m_area.add_y(em, i, 1);
1414 If block is deep underground, this is set to true and ground
1415 density noise is not generated, for speed optimization.
1417 bool all_is_ground_except_caves = (minimum_ground_depth > 40);
1420 Create a block-specific seed
1422 u32 blockseed = (u32)(data->seed%0x100000000) + full_node_min.Z*38134234
1423 + full_node_min.Y*42123 + full_node_min.X*23;
1429 //NoiseBuffer noisebuf1;
1430 //NoiseBuffer noisebuf2;
1431 NoiseBuffer noisebuf_cave;
1432 NoiseBuffer noisebuf_ground;
1433 NoiseBuffer noisebuf_ground_crumbleness;
1434 NoiseBuffer noisebuf_ground_wetness;
1436 v3f minpos_f(node_min.X, node_min.Y, node_min.Z);
1437 v3f maxpos_f(node_max.X, node_max.Y, node_max.Z);
1439 //TimeTaker timer("noisebuf.create");
1445 noisebuf_cave.create(get_cave_noise1_params(data->seed),
1446 minpos_f.X, minpos_f.Y, minpos_f.Z,
1447 maxpos_f.X, maxpos_f.Y, maxpos_f.Z,
1449 noisebuf_cave.multiply(get_cave_noise2_params(data->seed));
1457 v3f sl = v3f(4.0, 4.0, 4.0);
1462 if(all_is_ground_except_caves == false)
1463 //noisebuf_ground.create(data->seed+983240, 6, 0.60, false,
1464 noisebuf_ground.create(get_ground_noise1_params(data->seed),
1465 minpos_f.X, minpos_f.Y, minpos_f.Z,
1466 maxpos_f.X, maxpos_f.Y, maxpos_f.Z,
1470 Ground property noise
1472 sl = v3f(2.5, 2.5, 2.5);
1473 noisebuf_ground_crumbleness.create(
1474 get_ground_crumbleness_params(data->seed),
1475 minpos_f.X, minpos_f.Y, minpos_f.Z,
1476 maxpos_f.X, maxpos_f.Y+5, maxpos_f.Z,
1478 noisebuf_ground_wetness.create(
1479 get_ground_wetness_params(data->seed),
1480 minpos_f.X, minpos_f.Y, minpos_f.Z,
1481 maxpos_f.X, maxpos_f.Y+5, maxpos_f.Z,
1486 Make base ground level
1489 for(s16 x=node_min.X; x<=node_max.X; x++)
1490 for(s16 z=node_min.Z; z<=node_max.Z; z++)
1495 // Use fast index incrementing
1496 v3s16 em = vmanip.m_area.getExtent();
1497 u32 i = vmanip.m_area.index(v3s16(p2d.X, node_min.Y, p2d.Y));
1498 for(s16 y=node_min.Y; y<=node_max.Y; y++)
1500 // Only modify places that have no content
1501 if(vmanip.m_data[i].d == CONTENT_IGNORE)
1503 // First priority: make air and water.
1504 // This avoids caves inside water.
1505 if(all_is_ground_except_caves == false
1506 && val_is_ground(noisebuf_ground.get(x,y,z),
1507 v3s16(x,y,z), data->seed) == false)
1509 if(y <= WATER_LEVEL)
1510 vmanip.m_data[i] = MapNode(CONTENT_WATERSOURCE);
1512 vmanip.m_data[i] = MapNode(CONTENT_AIR);
1514 else if(noisebuf_cave.get(x,y,z) > CAVE_NOISE_THRESHOLD)
1515 vmanip.m_data[i] = MapNode(CONTENT_AIR);
1517 vmanip.m_data[i] = MapNode(CONTENT_STONE);
1520 data->vmanip->m_area.add_y(em, i, 1);
1530 PseudoRandom mineralrandom(blockseed);
1535 for(s16 i=0; i<approx_ground_depth/4; i++)
1537 if(mineralrandom.next()%50 == 0)
1539 s16 x = mineralrandom.range(node_min.X+1, node_max.X-1);
1540 s16 y = mineralrandom.range(node_min.Y+1, node_max.Y-1);
1541 s16 z = mineralrandom.range(node_min.Z+1, node_max.Z-1);
1542 for(u16 i=0; i<27; i++)
1544 v3s16 p = v3s16(x,y,z) + g_27dirs[i];
1545 u32 vi = vmanip.m_area.index(p);
1546 if(vmanip.m_data[vi].d == CONTENT_STONE)
1547 if(mineralrandom.next()%8 == 0)
1548 vmanip.m_data[vi] = MapNode(CONTENT_MESE);
1557 u16 a = mineralrandom.range(0,15);
1559 u16 amount = 20 * a/1000;
1560 for(s16 i=0; i<amount; i++)
1562 s16 x = mineralrandom.range(node_min.X+1, node_max.X-1);
1563 s16 y = mineralrandom.range(node_min.Y+1, node_max.Y-1);
1564 s16 z = mineralrandom.range(node_min.Z+1, node_max.Z-1);
1566 u8 base_content = CONTENT_STONE;
1567 MapNode new_content(CONTENT_IGNORE);
1570 if(noisebuf_ground_crumbleness.get(x,y+5,z) < -0.1)
1572 new_content = MapNode(CONTENT_STONE, MINERAL_COAL);
1576 if(noisebuf_ground_wetness.get(x,y+5,z) > 0.0)
1577 new_content = MapNode(CONTENT_STONE, MINERAL_IRON);
1578 /*if(noisebuf_ground_wetness.get(x,y,z) > 0.0)
1579 vmanip.m_data[i] = MapNode(CONTENT_MUD);
1581 vmanip.m_data[i] = MapNode(CONTENT_SAND);*/
1583 /*else if(noisebuf_ground_crumbleness.get(x,y,z) > 0.1)
1587 if(new_content.d != CONTENT_IGNORE)
1589 for(u16 i=0; i<27; i++)
1591 v3s16 p = v3s16(x,y,z) + g_27dirs[i];
1592 u32 vi = vmanip.m_area.index(p);
1593 if(vmanip.m_data[vi].d == base_content)
1595 if(mineralrandom.next()%sparseness == 0)
1596 vmanip.m_data[vi] = new_content;
1605 //for(s16 i=0; i < MYMAX(0, 50 - abs(node_min.Y+8 - (-30))); i++)
1606 //for(s16 i=0; i<50; i++)
1607 u16 coal_amount = 30;
1608 u16 coal_rareness = 60 / coal_amount;
1609 if(coal_rareness == 0)
1611 if(mineralrandom.next()%coal_rareness == 0)
1613 u16 a = mineralrandom.next() % 16;
1614 u16 amount = coal_amount * a*a*a / 1000;
1615 for(s16 i=0; i<amount; i++)
1617 s16 x = mineralrandom.range(node_min.X+1, node_max.X-1);
1618 s16 y = mineralrandom.range(node_min.Y+1, node_max.Y-1);
1619 s16 z = mineralrandom.range(node_min.Z+1, node_max.Z-1);
1620 for(u16 i=0; i<27; i++)
1622 v3s16 p = v3s16(x,y,z) + g_27dirs[i];
1623 u32 vi = vmanip.m_area.index(p);
1624 if(vmanip.m_data[vi].d == CONTENT_STONE)
1625 if(mineralrandom.next()%8 == 0)
1626 vmanip.m_data[vi] = MapNode(CONTENT_STONE, MINERAL_COAL);
1633 u16 iron_amount = 8;
1634 u16 iron_rareness = 60 / iron_amount;
1635 if(iron_rareness == 0)
1637 if(mineralrandom.next()%iron_rareness == 0)
1639 u16 a = mineralrandom.next() % 16;
1640 u16 amount = iron_amount * a*a*a / 1000;
1641 for(s16 i=0; i<amount; i++)
1643 s16 x = mineralrandom.range(node_min.X+1, node_max.X-1);
1644 s16 y = mineralrandom.range(node_min.Y+1, node_max.Y-1);
1645 s16 z = mineralrandom.range(node_min.Z+1, node_max.Z-1);
1646 for(u16 i=0; i<27; i++)
1648 v3s16 p = v3s16(x,y,z) + g_27dirs[i];
1649 u32 vi = vmanip.m_area.index(p);
1650 if(vmanip.m_data[vi].d == CONTENT_STONE)
1651 if(mineralrandom.next()%8 == 0)
1652 vmanip.m_data[vi] = MapNode(CONTENT_STONE, MINERAL_IRON);
1659 Add mud and sand and others underground (in place of stone)
1662 for(s16 x=node_min.X; x<=node_max.X; x++)
1663 for(s16 z=node_min.Z; z<=node_max.Z; z++)
1668 // Use fast index incrementing
1669 v3s16 em = vmanip.m_area.getExtent();
1670 u32 i = vmanip.m_area.index(v3s16(p2d.X, node_max.Y, p2d.Y));
1671 for(s16 y=node_max.Y; y>=node_min.Y; y--)
1673 if(vmanip.m_data[i].d == CONTENT_STONE)
1675 if(noisebuf_ground_crumbleness.get(x,y,z) > 1.3)
1677 if(noisebuf_ground_wetness.get(x,y,z) > 0.0)
1678 vmanip.m_data[i] = MapNode(CONTENT_MUD);
1680 vmanip.m_data[i] = MapNode(CONTENT_SAND);
1682 else if(noisebuf_ground_crumbleness.get(x,y,z) > 0.7)
1684 if(noisebuf_ground_wetness.get(x,y,z) < -0.6)
1685 vmanip.m_data[i] = MapNode(CONTENT_GRAVEL);
1689 data->vmanip->m_area.add_y(em, i, -1);
1698 //if(node_min.Y < approx_groundlevel)
1699 //if(myrand() % 3 == 0)
1700 //if(myrand() % 3 == 0 && node_min.Y < approx_groundlevel)
1701 //if(myrand() % 100 == 0 && node_min.Y < approx_groundlevel)
1702 //float dungeon_rarity = g_settings.getFloat("dungeon_rarity");
1703 float dungeon_rarity = 0.02;
1704 if(((noise3d(blockpos.X,blockpos.Y,blockpos.Z,data->seed)+1.0)/2.0)
1706 && node_min.Y < approx_groundlevel)
1708 // Dungeon generator doesn't modify places which have this set
1709 data->vmanip->clearFlag(VMANIP_FLAG_DUNGEON_INSIDE
1710 | VMANIP_FLAG_DUNGEON_PRESERVE);
1712 // Set all air and water to be untouchable to make dungeons open
1713 // to caves and open air
1714 for(s16 x=full_node_min.X; x<=full_node_max.X; x++)
1715 for(s16 z=full_node_min.Z; z<=full_node_max.Z; z++)
1720 // Use fast index incrementing
1721 v3s16 em = vmanip.m_area.getExtent();
1722 u32 i = vmanip.m_area.index(v3s16(p2d.X, full_node_max.Y, p2d.Y));
1723 for(s16 y=full_node_max.Y; y>=full_node_min.Y; y--)
1725 if(vmanip.m_data[i].d == CONTENT_AIR)
1726 vmanip.m_flags[i] |= VMANIP_FLAG_DUNGEON_PRESERVE;
1727 else if(vmanip.m_data[i].d == CONTENT_WATERSOURCE)
1728 vmanip.m_flags[i] |= VMANIP_FLAG_DUNGEON_PRESERVE;
1729 data->vmanip->m_area.add_y(em, i, -1);
1734 PseudoRandom random(blockseed+2);
1737 make_dungeon1(vmanip, random);
1739 // Convert some cobble to mossy cobble
1740 for(s16 x=full_node_min.X; x<=full_node_max.X; x++)
1741 for(s16 z=full_node_min.Z; z<=full_node_max.Z; z++)
1746 // Use fast index incrementing
1747 v3s16 em = vmanip.m_area.getExtent();
1748 u32 i = vmanip.m_area.index(v3s16(p2d.X, full_node_max.Y, p2d.Y));
1749 for(s16 y=full_node_max.Y; y>=full_node_min.Y; y--)
1751 // (noisebuf not used because it doesn't contain the
1753 double wetness = noise3d_param(
1754 get_ground_wetness_params(data->seed), x,y,z);
1755 double d = noise3d_perlin((float)x/2.5,
1756 (float)y/2.5,(float)z/2.5,
1758 if(vmanip.m_data[i].d == CONTENT_COBBLE)
1762 vmanip.m_data[i].d = CONTENT_MOSSYCOBBLE;
1765 /*else if(vmanip.m_flags[i] & VMANIP_FLAG_DUNGEON_INSIDE)
1768 vmanip.m_data[i].d = CONTENT_MUD;
1770 data->vmanip->m_area.add_y(em, i, -1);
1777 Add top and bottom side of water to transforming_liquid queue
1780 for(s16 x=node_min.X; x<=node_max.X; x++)
1781 for(s16 z=node_min.Z; z<=node_max.Z; z++)
1786 bool water_found = false;
1787 // Use fast index incrementing
1788 v3s16 em = vmanip.m_area.getExtent();
1789 u32 i = vmanip.m_area.index(v3s16(p2d.X, node_max.Y, p2d.Y));
1790 for(s16 y=node_max.Y; y>=node_min.Y; y--)
1792 if(water_found == false)
1794 if(vmanip.m_data[i].d == CONTENT_WATERSOURCE)
1796 v3s16 p = v3s16(p2d.X, y, p2d.Y);
1797 data->transforming_liquid.push_back(p);
1803 // This can be done because water_found can only
1804 // turn to true and end up here after going through
1806 if(vmanip.m_data[i+1].d != CONTENT_WATERSOURCE)
1808 v3s16 p = v3s16(p2d.X, y+1, p2d.Y);
1809 data->transforming_liquid.push_back(p);
1810 water_found = false;
1814 data->vmanip->m_area.add_y(em, i, -1);
1820 If close to ground level
1823 //if(abs(approx_ground_depth) < 30)
1824 if(minimum_ground_depth < 5 && maximum_ground_depth > -5)
1830 for(s16 x=node_min.X; x<=node_max.X; x++)
1831 for(s16 z=node_min.Z; z<=node_max.Z; z++)
1836 bool possibly_have_sand = get_have_sand(data->seed, p2d);
1837 bool have_sand = false;
1838 u32 current_depth = 0;
1839 bool air_detected = false;
1840 bool water_detected = false;
1841 bool have_clay = false;
1843 // Determine whether to have clay in the sand here
1844 double claynoise = noise2d_perlin(
1845 0.5+(float)p2d.X/500, 0.5+(float)p2d.Y/500,
1846 data->seed+4321, 6, 0.95);
1848 have_clay = have_sand && (claynoise > 1.25);
1850 // Use fast index incrementing
1851 s16 start_y = node_max.Y+2;
1852 v3s16 em = vmanip.m_area.getExtent();
1853 u32 i = vmanip.m_area.index(v3s16(p2d.X, start_y, p2d.Y));
1854 for(s16 y=start_y; y>=node_min.Y-3; y--)
1856 if(vmanip.m_data[i].d == CONTENT_WATERSOURCE)
1857 water_detected = true;
1858 if(vmanip.m_data[i].d == CONTENT_AIR)
1859 air_detected = true;
1861 if((vmanip.m_data[i].d == CONTENT_STONE
1862 || vmanip.m_data[i].d == CONTENT_GRASS
1863 || vmanip.m_data[i].d == CONTENT_MUD
1864 || vmanip.m_data[i].d == CONTENT_SAND
1865 || vmanip.m_data[i].d == CONTENT_GRAVEL
1866 ) && (air_detected || water_detected))
1868 if(current_depth == 0 && y <= WATER_LEVEL+2
1869 && possibly_have_sand)
1872 if(current_depth < 4)
1877 vmanip.m_data[i] = MapNode(CONTENT_CLAY);
1879 vmanip.m_data[i] = MapNode(CONTENT_SAND);
1882 else if(current_depth==0 && !water_detected
1883 && y >= WATER_LEVEL && air_detected)
1884 vmanip.m_data[i] = MapNode(CONTENT_GRASS);
1887 vmanip.m_data[i] = MapNode(CONTENT_MUD);
1891 if(vmanip.m_data[i].d == CONTENT_MUD
1892 || vmanip.m_data[i].d == CONTENT_GRASS)
1893 vmanip.m_data[i] = MapNode(CONTENT_STONE);
1898 if(current_depth >= 8)
1901 else if(current_depth != 0)
1904 data->vmanip->m_area.add_y(em, i, -1);
1914 u32 tree_count = block_area_nodes * tree_amount_2d(data->seed, p2d_center);
1915 PseudoRandom treerandom(blockseed);
1916 // Put trees in random places on part of division
1917 for(u32 i=0; i<tree_count; i++)
1919 s16 x = treerandom.range(node_min.X, node_max.X);
1920 s16 z = treerandom.range(node_min.Z, node_max.Z);
1921 //s16 y = find_ground_level(data->vmanip, v2s16(x,z));
1922 s16 y = find_ground_level_from_noise(data->seed, v2s16(x,z), 4);
1923 // Don't make a tree under water level
1926 // Make sure tree fits (only trees whose starting point is
1927 // at this block are added)
1928 if(y < node_min.Y || y > node_max.Y)
1931 Find exact ground level
1935 for(; p.Y >= y-6; p.Y--)
1937 u32 i = data->vmanip->m_area.index(p);
1938 MapNode *n = &data->vmanip->m_data[i];
1939 if(n->d != CONTENT_AIR && n->d != CONTENT_WATERSOURCE && n->d != CONTENT_IGNORE)
1945 // If not found, handle next one
1950 u32 i = data->vmanip->m_area.index(p);
1951 MapNode *n = &data->vmanip->m_data[i];
1953 if(n->d != CONTENT_MUD && n->d != CONTENT_GRASS && n->d != CONTENT_SAND)
1956 // Papyrus grows only on mud and in water
1957 if(n->d == CONTENT_MUD && y <= WATER_LEVEL)
1960 make_papyrus(vmanip, p);
1962 // Trees grow only on mud and grass, on land
1963 else if((n->d == CONTENT_MUD || n->d == CONTENT_GRASS) && y > WATER_LEVEL + 2)
1966 make_tree(vmanip, p);
1968 // Cactii grow only on sand, on land
1969 else if(n->d == CONTENT_SAND && y > WATER_LEVEL + 2)
1972 make_cactus(vmanip, p);
1979 Add some kind of random stones
1982 u32 random_stone_count = block_area_nodes *
1983 randomstone_amount_2d(data->seed, p2d_center);
1984 // Put in random places on part of division
1985 for(u32 i=0; i<random_stone_count; i++)
1987 s16 x = myrand_range(node_min.X, node_max.X);
1988 s16 z = myrand_range(node_min.Z, node_max.Z);
1989 s16 y = find_ground_level_from_noise(data->seed, v2s16(x,z), 1);
1990 // Don't add under water level
1991 /*if(y < WATER_LEVEL)
1993 // Don't add if doesn't belong to this block
1994 if(y < node_min.Y || y > node_max.Y)
1999 u32 i = data->vmanip->m_area.index(v3s16(p));
2000 MapNode *n = &data->vmanip->m_data[i];
2001 if(n->d != CONTENT_MUD && n->d != CONTENT_GRASS)
2004 // Will be placed one higher
2007 make_randomstone(data->vmanip, p);
2016 u32 large_stone_count = block_area_nodes *
2017 largestone_amount_2d(data->seed, p2d_center);
2018 //u32 large_stone_count = 1;
2019 // Put in random places on part of division
2020 for(u32 i=0; i<large_stone_count; i++)
2022 s16 x = myrand_range(node_min.X, node_max.X);
2023 s16 z = myrand_range(node_min.Z, node_max.Z);
2024 s16 y = find_ground_level_from_noise(data->seed, v2s16(x,z), 1);
2025 // Don't add under water level
2026 /*if(y < WATER_LEVEL)
2028 // Don't add if doesn't belong to this block
2029 if(y < node_min.Y || y > node_max.Y)
2034 u32 i = data->vmanip->m_area.index(v3s16(p));
2035 MapNode *n = &data->vmanip->m_data[i];
2036 if(n->d != CONTENT_MUD && n->d != CONTENT_GRASS)
2039 // Will be placed one lower
2042 make_largestone(data->vmanip, p);
2049 BlockMakeData::BlockMakeData():
2055 BlockMakeData::~BlockMakeData()
2060 }; // namespace mapgen