tuned lava/universal damage code
[oweals/minetest.git] / src / mapgen.cpp
index d4143b6d6a93199594591f4d86b5693269c5f915..4285378a09e55c2708f6ac01d2dfe8888613f361 100644 (file)
@@ -85,7 +85,7 @@ static void make_tree(VoxelManipulator &vmanip, v3s16 p0)
        MapNode treenode(CONTENT_TREE);
        MapNode leavesnode(CONTENT_LEAVES);
 
-       s16 trunk_h = myrand_range(3, 6);
+       s16 trunk_h = myrand_range(4, 5);
        v3s16 p1 = p0;
        for(s16 ii=0; ii<trunk_h; ii++)
        {
@@ -97,7 +97,7 @@ static void make_tree(VoxelManipulator &vmanip, v3s16 p0)
        // p1 is now the last piece of the trunk
        p1.Y -= 1;
 
-       VoxelArea leaves_a(v3s16(-2,-2,-2), v3s16(2,2,2));
+       VoxelArea leaves_a(v3s16(-2,-1,-2), v3s16(2,2,2));
        //SharedPtr<u8> leaves_d(new u8[leaves_a.getVolume()]);
        Buffer<u8> leaves_d(leaves_a.getVolume());
        for(s32 i=0; i<leaves_a.getVolume(); i++)
@@ -152,6 +152,120 @@ static void make_tree(VoxelManipulator &vmanip, v3s16 p0)
        }
 }
 
+static void make_jungletree(VoxelManipulator &vmanip, v3s16 p0)
+{
+       MapNode treenode(CONTENT_JUNGLETREE);
+       MapNode leavesnode(CONTENT_LEAVES);
+
+       for(s16 x=-1; x<=1; x++)
+       for(s16 z=-1; z<=1; z++)
+       {
+               if(myrand_range(0, 2) == 0)
+                       continue;
+               v3s16 p1 = p0 + v3s16(x,0,z);
+               v3s16 p2 = p0 + v3s16(x,-1,z);
+               if(vmanip.m_area.contains(p2)
+                               && vmanip.m_data[vmanip.m_area.index(p2)] == CONTENT_AIR)
+                       vmanip.m_data[vmanip.m_area.index(p2)] = treenode;
+               else if(vmanip.m_area.contains(p1))
+                       vmanip.m_data[vmanip.m_area.index(p1)] = treenode;
+       }
+
+       s16 trunk_h = myrand_range(8, 12);
+       v3s16 p1 = p0;
+       for(s16 ii=0; ii<trunk_h; ii++)
+       {
+               if(vmanip.m_area.contains(p1))
+                       vmanip.m_data[vmanip.m_area.index(p1)] = treenode;
+               p1.Y++;
+       }
+
+       // p1 is now the last piece of the trunk
+       p1.Y -= 1;
+
+       VoxelArea leaves_a(v3s16(-3,-2,-3), v3s16(3,2,3));
+       //SharedPtr<u8> leaves_d(new u8[leaves_a.getVolume()]);
+       Buffer<u8> leaves_d(leaves_a.getVolume());
+       for(s32 i=0; i<leaves_a.getVolume(); i++)
+               leaves_d[i] = 0;
+
+       // Force leaves at near the end of the trunk
+       {
+               s16 d = 1;
+               for(s16 z=-d; z<=d; z++)
+               for(s16 y=-d; y<=d; y++)
+               for(s16 x=-d; x<=d; x++)
+               {
+                       leaves_d[leaves_a.index(v3s16(x,y,z))] = 1;
+               }
+       }
+
+       // Add leaves randomly
+       for(u32 iii=0; iii<30; iii++)
+       {
+               s16 d = 1;
+
+               v3s16 p(
+                       myrand_range(leaves_a.MinEdge.X, leaves_a.MaxEdge.X-d),
+                       myrand_range(leaves_a.MinEdge.Y, leaves_a.MaxEdge.Y-d),
+                       myrand_range(leaves_a.MinEdge.Z, leaves_a.MaxEdge.Z-d)
+               );
+
+               for(s16 z=0; z<=d; z++)
+               for(s16 y=0; y<=d; y++)
+               for(s16 x=0; x<=d; x++)
+               {
+                       leaves_d[leaves_a.index(p+v3s16(x,y,z))] = 1;
+               }
+       }
+
+       // Blit leaves to vmanip
+       for(s16 z=leaves_a.MinEdge.Z; z<=leaves_a.MaxEdge.Z; z++)
+       for(s16 y=leaves_a.MinEdge.Y; y<=leaves_a.MaxEdge.Y; y++)
+       for(s16 x=leaves_a.MinEdge.X; x<=leaves_a.MaxEdge.X; x++)
+       {
+               v3s16 p(x,y,z);
+               p += p1;
+               if(vmanip.m_area.contains(p) == false)
+                       continue;
+               u32 vi = vmanip.m_area.index(p);
+               if(vmanip.m_data[vi].getContent() != CONTENT_AIR
+                               && vmanip.m_data[vi].getContent() != CONTENT_IGNORE)
+                       continue;
+               u32 i = leaves_a.index(x,y,z);
+               if(leaves_d[i] == 1)
+                       vmanip.m_data[vi] = leavesnode;
+       }
+}
+
+void make_papyrus(VoxelManipulator &vmanip, v3s16 p0)
+{
+       MapNode papyrusnode(CONTENT_PAPYRUS);
+
+       s16 trunk_h = myrand_range(2, 3);
+       v3s16 p1 = p0;
+       for(s16 ii=0; ii<trunk_h; ii++)
+       {
+               if(vmanip.m_area.contains(p1))
+                       vmanip.m_data[vmanip.m_area.index(p1)] = papyrusnode;
+               p1.Y++;
+       }
+}
+
+void make_cactus(VoxelManipulator &vmanip, v3s16 p0)
+{
+       MapNode cactusnode(CONTENT_CACTUS);
+
+       s16 trunk_h = 3;
+       v3s16 p1 = p0;
+       for(s16 ii=0; ii<trunk_h; ii++)
+       {
+               if(vmanip.m_area.contains(p1))
+                       vmanip.m_data[vmanip.m_area.index(p1)] = cactusnode;
+               p1.Y++;
+       }
+}
+
 #if 0
 static void make_randomstone(VoxelManipulator &vmanip, v3s16 p0)
 {
@@ -862,6 +976,40 @@ static void make_dungeon1(VoxelManipulator &vmanip, PseudoRandom &random)
        }
 }
 
+static void make_nc(VoxelManipulator &vmanip, PseudoRandom &random)
+{
+       v3s16 dir;
+       u8 facedir_i = 0;
+       s32 r = random.range(0, 3);
+       if(r == 0){
+               dir = v3s16( 1, 0, 0);
+               facedir_i = 3;
+       }
+       if(r == 1){
+               dir = v3s16(-1, 0, 0);
+               facedir_i = 1;
+       }
+       if(r == 2){
+               dir = v3s16( 0, 0, 1);
+               facedir_i = 2;
+       }
+       if(r == 3){
+               dir = v3s16( 0, 0,-1);
+               facedir_i = 0;
+       }
+       v3s16 p = vmanip.m_area.MinEdge + v3s16(
+                       16+random.range(0,15),
+                       16+random.range(0,15),
+                       16+random.range(0,15));
+       vmanip.m_data[vmanip.m_area.index(p)] = MapNode(CONTENT_NC, facedir_i);
+       u32 length = random.range(3,15);
+       for(u32 j=0; j<length; j++)
+       {
+               p -= dir;
+               vmanip.m_data[vmanip.m_area.index(p)] = MapNode(CONTENT_NC_RB);
+       }
+}
+
 /*
        Noise functions. Make sure seed is mangled differently in each one.
 */
@@ -909,8 +1057,8 @@ NoiseParams get_cave_noise2_params(u64 seed)
 
 NoiseParams get_ground_noise1_params(u64 seed)
 {
-       return NoiseParams(NOISE_PERLIN, seed+983240, 5,
-                       0.60, 100.0, 30.0);
+       return NoiseParams(NOISE_PERLIN, seed+983240, 4,
+                       0.55, 80.0, 40.0);
 }
 
 NoiseParams get_ground_crumbleness_params(u64 seed)
@@ -945,7 +1093,7 @@ bool val_is_ground(double ground_noise1_val, v3s16 p, u64 seed)
 
        double f = 0.55 + noise2d_perlin(
                        0.5+(float)p.X/250, 0.5+(float)p.Z/250,
-                       seed+920381, 3, 0.5);
+                       seed+920381, 3, 0.45);
        if(f < 0.01)
                f = 0.01;
        else if(f >= 1.0)
@@ -976,13 +1124,26 @@ double tree_amount_2d(u64 seed, v2s16 p)
        double noise = noise2d_perlin(
                        0.5+(float)p.X/125, 0.5+(float)p.Y/125,
                        seed+2, 4, 0.66);
-       double zeroval = -0.35;
+       double zeroval = -0.39;
        if(noise < zeroval)
                return 0;
        else
                return 0.04 * (noise-zeroval) / (1.0-zeroval);
 }
 
+double surface_humidity_2d(u64 seed, v2s16 p)
+{
+       double noise = noise2d_perlin(
+                       0.5+(float)p.X/500, 0.5+(float)p.Y/500,
+                       seed+72384, 4, 0.66);
+       noise = (noise + 1.0)/2.0;
+       if(noise < 0.0)
+               noise = 0.0;
+       if(noise > 1.0)
+               noise = 1.0;
+       return noise;
+}
+
 #if 0
 double randomstone_amount_2d(u64 seed, v2s16 p)
 {
@@ -1345,7 +1506,8 @@ void make_block(BlockMakeData *data)
                        data->seed, v2s16(blockpos.X, blockpos.Z), 1);
        // Maximum amount of ground above the bottom of the central block
        s16 maximum_ground_depth = maximum_groundlevel - node_min.Y;
-       
+
+       #if 0
        /*
                Special case for high air or water: Just fill with air and water.
        */
@@ -1379,6 +1541,7 @@ void make_block(BlockMakeData *data)
                // We're done
                return;
        }
+       #endif
 
        /*
                If block is deep underground, this is set to true and ground
@@ -1389,7 +1552,7 @@ void make_block(BlockMakeData *data)
        /*
                Create a block-specific seed
        */
-       u32 blockseed = (u32)(data->seed%0x100000000) + full_node_min.Z*38134234
+       u32 blockseed = (u32)(data->seed%0x100000000ULL) + full_node_min.Z*38134234
                        + full_node_min.Y*42123 + full_node_min.X*23;
        
        /*
@@ -1654,6 +1817,16 @@ void make_block(BlockMakeData *data)
                                                if(noisebuf_ground_wetness.get(x,y,z) < -0.6)
                                                        vmanip.m_data[i] = MapNode(CONTENT_GRAVEL);
                                        }
+                                       else if(noisebuf_ground_crumbleness.get(x,y,z) <
+                                                       -2.3 + MYMIN(0.1 * sqrt(MYMAX(0, -y)), 1.5))
+                                       {
+                                               vmanip.m_data[i] = MapNode(CONTENT_LAVASOURCE);
+                                               for(s16 x1=-1; x1<=1; x1++)
+                                               for(s16 y1=-1; y1<=1; y1++)
+                                               for(s16 z1=-1; z1<=1; z1++)
+                                                       data->transforming_liquid.push_back(
+                                                                       v3s16(p2d.X+x1, y+y1, p2d.Y+z1));
+                                       }
                                }
 
                                data->vmanip->m_area.add_y(em, i, -1);
@@ -1742,6 +1915,17 @@ void make_block(BlockMakeData *data)
                        }
                }
        }
+
+       /*
+               Add NC
+       */
+       {
+               PseudoRandom ncrandom(blockseed+9324342);
+               if(ncrandom.range(0, 1000) == 0 && blockpos.Y <= -3)
+               {
+                       make_nc(vmanip, ncrandom);
+               }
+       }
        
        /*
                Add top and bottom side of water to transforming_liquid queue
@@ -1808,6 +1992,8 @@ void make_block(BlockMakeData *data)
                                u32 current_depth = 0;
                                bool air_detected = false;
                                bool water_detected = false;
+                               bool have_clay = false;
+
                                // Use fast index incrementing
                                s16 start_y = node_max.Y+2;
                                v3s16 em = vmanip.m_area.getExtent();
@@ -1834,7 +2020,19 @@ void make_block(BlockMakeData *data)
                                                {
                                                        if(have_sand)
                                                        {
-                                                               vmanip.m_data[i] = MapNode(CONTENT_SAND);
+                                                               // Determine whether to have clay in the sand here
+                                                               double claynoise = noise2d_perlin(
+                                                                               0.5+(float)p2d.X/500, 0.5+(float)p2d.Y/500,
+                                                                               data->seed+4321, 6, 0.95) + 0.5;
+                               
+                                                               have_clay = (y <= WATER_LEVEL) && (y >= WATER_LEVEL-2) && (
+                                                                       ((claynoise > 0) && (claynoise < 0.04) && (current_depth == 0)) ||
+                                                                       ((claynoise > 0) && (claynoise < 0.12) && (current_depth == 1))
+                                                                       );
+                                                               if (have_clay)
+                                                                       vmanip.m_data[i] = MapNode(CONTENT_CLAY);
+                                                               else
+                                                                       vmanip.m_data[i] = MapNode(CONTENT_SAND);
                                                        }
                                                        #if 1
                                                        else if(current_depth==0 && !water_detected
@@ -1865,11 +2063,19 @@ void make_block(BlockMakeData *data)
                }
 
                /*
-                       Add trees
+                       Calculate some stuff
                */
                
+               float surface_humidity = surface_humidity_2d(data->seed, p2d_center);
+               bool is_jungle = surface_humidity > 0.75;
                // Amount of trees
                u32 tree_count = block_area_nodes * tree_amount_2d(data->seed, p2d_center);
+               if(is_jungle)
+                       tree_count *= 5;
+
+               /*
+                       Add trees
+               */
                PseudoRandom treerandom(blockseed);
                // Put trees in random places on part of division
                for(u32 i=0; i<tree_count; i++)
@@ -1894,7 +2100,7 @@ void make_block(BlockMakeData *data)
                        {
                                u32 i = data->vmanip->m_area.index(p);
                                MapNode *n = &data->vmanip->m_data[i];
-                               if(n->getContent() != CONTENT_AIR && n->getContent() != CONTENT_IGNORE)
+                               if(n->getContent() != CONTENT_AIR && n->getContent() != CONTENT_WATERSOURCE && n->getContent() != CONTENT_IGNORE)
                                {
                                        found = true;
                                        break;
@@ -1903,19 +2109,85 @@ void make_block(BlockMakeData *data)
                        // If not found, handle next one
                        if(found == false)
                                continue;
-                       /*
-                               Trees grow only on mud and grass
-                       */
+
                        {
                                u32 i = data->vmanip->m_area.index(p);
                                MapNode *n = &data->vmanip->m_data[i];
-                               if(n->getContent() != CONTENT_MUD && n->getContent() != CONTENT_GRASS)
+
+                               if(n->getContent() != CONTENT_MUD && n->getContent() != CONTENT_GRASS && n->getContent() != CONTENT_SAND)
+                                               continue;
+
+                               // Papyrus grows only on mud and in water
+                               if(n->getContent() == CONTENT_MUD && y <= WATER_LEVEL)
+                               {
+                                       p.Y++;
+                                       make_papyrus(vmanip, p);
+                               }
+                               // Trees grow only on mud and grass, on land
+                               else if((n->getContent() == CONTENT_MUD || n->getContent() == CONTENT_GRASS) && y > WATER_LEVEL + 2)
+                               {
+                                       p.Y++;
+                                       //if(surface_humidity_2d(data->seed, v2s16(x, y)) < 0.5)
+                                       if(is_jungle == false)
+                                               make_tree(vmanip, p);
+                                       else
+                                               make_jungletree(vmanip, p);
+                               }
+                               // Cactii grow only on sand, on land
+                               else if(n->getContent() == CONTENT_SAND && y > WATER_LEVEL + 2)
+                               {
+                                       p.Y++;
+                                       make_cactus(vmanip, p);
+                               }
+                       }
+               }
+
+               /*
+                       Add jungle grass
+               */
+               if(is_jungle)
+               {
+                       PseudoRandom grassrandom(blockseed);
+                       for(u32 i=0; i<surface_humidity*5*tree_count; i++)
+                       {
+                               s16 x = grassrandom.range(node_min.X, node_max.X);
+                               s16 z = grassrandom.range(node_min.Z, node_max.Z);
+                               s16 y = find_ground_level_from_noise(data->seed, v2s16(x,z), 4);
+                               if(y < WATER_LEVEL)
                                        continue;
+                               if(y < node_min.Y || y > node_max.Y)
+                                       continue;
+                               /*
+                                       Find exact ground level
+                               */
+                               v3s16 p(x,y+6,z);
+                               bool found = false;
+                               for(; p.Y >= y-6; p.Y--)
+                               {
+                                       u32 i = data->vmanip->m_area.index(p);
+                                       MapNode *n = &data->vmanip->m_data[i];
+                                       if(content_features(*n).is_ground_content
+                                                       || n->getContent() == CONTENT_JUNGLETREE)
+                                       {
+                                               found = true;
+                                               break;
+                                       }
+                               }
+                               // If not found, handle next one
+                               if(found == false)
+                                       continue;
+                               p.Y++;
+                               if(vmanip.m_area.contains(p) == false)
+                                       continue;
+                               if(vmanip.m_data[vmanip.m_area.index(p)].getContent() != CONTENT_AIR)
+                                       continue;
+                               /*p.Y--;
+                               if(vmanip.m_area.contains(p))
+                                       vmanip.m_data[vmanip.m_area.index(p)] = CONTENT_MUD;
+                               p.Y++;*/
+                               if(vmanip.m_area.contains(p))
+                                       vmanip.m_data[vmanip.m_area.index(p)] = CONTENT_JUNGLEGRASS;
                        }
-                       // Tree will be placed one higher
-                       p.Y++;
-                       // Make a tree
-                       make_tree(vmanip, p);
                }
 
 #if 0