Ore: Add puff ore type
authorkwolekr <kwolekr@minetest.net>
Wed, 16 Sep 2015 01:28:16 +0000 (21:28 -0400)
committerkwolekr <kwolekr@minetest.net>
Thu, 17 Sep 2015 07:04:50 +0000 (03:04 -0400)
doc/lua_api.txt
src/mg_ore.cpp
src/mg_ore.h
src/script/lua_api/l_mapgen.cpp

index ae414406dbd568f6a3ac333e832b8c9c2dc778c9..af48c64f68b5efccc8daad45fc2a43e1acb28fcb 100644 (file)
@@ -714,8 +714,8 @@ a non-equal distribution of ore.
 
 ### `sheet`
 Creates a sheet of ore in a blob shape according to the 2D perlin noise
-described by `noise_params`. This is essentially an improved version of
-the so-called "stratus" ore seen in some unofficial mods.
+described by `noise_params` and `noise_threshold`. This is essentially an
+improved version of the so-called "stratus" ore seen in some unofficial mods.
 
 This sheet consists of vertical columns of uniform randomly distributed height,
 varying between the inclusive range `column_height_min` and `column_height_max`.
@@ -731,12 +731,23 @@ the default is 0.5.
 
 The ore parameters `clust_scarcity` and `clust_num_ores` are ignored for this ore type.
 
+### `puff`
+Creates a sheet of ore in a cloud-like puff shape.
+
+As with the `sheet` ore type, the size and shape of puffs are described by
+`noise_params` and `noise_threshold` and are placed at random vertical positions
+within the currently generated chunk.
+
+The vertical top and bottom displacement of each puff are determined by the noise
+parameters `np_puff_top` and `np_puff_bottom`, respectively.
+
+
 ### `blob`
 Creates a deformed sphere of ore according to 3d perlin noise described by
 `noise_params`.  The maximum size of the blob is `clust_size`, and
 `clust_scarcity` has the same meaning as with the `scatter` type.
 
-### `vein
+### `vein`
 Creates veins of ore varying in density by according to the intersection of two
 instances of 3d perlin noise with diffferent seeds, both described by
 `noise_params`.  `random_factor` varies the influence random chance has on
@@ -771,6 +782,17 @@ Also produce this same ore between the height range of `-y_max` and `-y_min`.
 
 Useful for having ore in sky realms without having to duplicate ore entries.
 
+### `puff_cliffs`
+If set, puff ore generation will not taper down large differences in displacement
+when approaching the edge of a puff.  This flag has no effect for ore types other
+than `puff`.
+
+### `puff_additive_composition`
+By default, when noise described by `np_puff_top` or `np_puff_bottom` results in a
+negative displacement, the sub-column at that point is not generated.  With this
+attribute set, puff ore generation will instead generate the absolute difference in
+noise displacement values.  This flag has no effect for ore types other than `puff`.
+
 Decoration types
 ----------------
 The varying types of decorations that can be placed.
index f5d312ba273353474ea41c0acf754ccc3298e7ca..28be816f50c18c53ab8a5535c5f51ff49a79515d 100644 (file)
@@ -25,8 +25,10 @@ with this program; if not, write to the Free Software Foundation, Inc.,
 #include "log.h"
 
 FlagDesc flagdesc_ore[] = {
-       {"absheight", OREFLAG_ABSHEIGHT},
-       {NULL,        0}
+       {"absheight",                 OREFLAG_ABSHEIGHT},
+       {"puff_cliffs",               OREFLAG_PUFF_CLIFFS},
+       {"puff_additive_composition", OREFLAG_PUFF_ADDITIVE},
+       {NULL,                        0}
 };
 
 
@@ -220,6 +222,94 @@ void OreSheet::generate(MMVManip *vm, int mapseed, u32 blockseed,
 
 ///////////////////////////////////////////////////////////////////////////////
 
+OrePuff::OrePuff() :
+       Ore()
+{
+       noise_puff_top    = NULL;
+       noise_puff_bottom = NULL;
+}
+
+
+OrePuff::~OrePuff()
+{
+       delete noise_puff_top;
+       delete noise_puff_bottom;
+}
+
+
+void OrePuff::generate(MMVManip *vm, int mapseed, u32 blockseed,
+       v3s16 nmin, v3s16 nmax, u8 *biomemap)
+{
+       PseudoRandom pr(blockseed + 4234);
+       MapNode n_ore(c_ore, 0, ore_param2);
+
+       int y_start = pr.range(nmin.Y, nmax.Y);
+
+       if (!noise) {
+               int sx = nmax.X - nmin.X + 1;
+               int sz = nmax.Z - nmin.Z + 1;
+               noise = new Noise(&np, 0, sx, sz);
+               noise_puff_top = new Noise(&np_puff_top, 0, sx, sz);
+               noise_puff_bottom = new Noise(&np_puff_bottom, 0, sx, sz);
+       }
+
+       noise->seed = mapseed + y_start;
+       noise->perlinMap2D(nmin.X, nmin.Z);
+       bool noise_generated = false;
+
+       size_t index = 0;
+       for (int z = nmin.Z; z <= nmax.Z; z++)
+       for (int x = nmin.X; x <= nmax.X; x++, index++) {
+               float noiseval = noise->result[index];
+               if (noiseval < nthresh)
+                       continue;
+
+               if (biomemap && !biomes.empty()) {
+                       std::set<u8>::iterator it = biomes.find(biomemap[index]);
+                       if (it == biomes.end())
+                               continue;
+               }
+
+               if (!noise_generated) {
+                       noise_generated = true;
+                       noise_puff_top->perlinMap2D(nmin.X, nmin.Z);
+                       noise_puff_bottom->perlinMap2D(nmin.X, nmin.Z);
+               }
+
+               float ntop    = noise_puff_top->result[index];
+               float nbottom = noise_puff_bottom->result[index];
+
+               if (!(flags & OREFLAG_PUFF_CLIFFS)) {
+                       float ndiff = noiseval - nthresh;
+                       if (ndiff < 1.0f) {
+                               ntop *= ndiff;
+                               nbottom *= ndiff;
+                       }
+               }
+
+               int ymid = y_start;
+               int y0 = ymid - nbottom;
+               int y1 = ymid + ntop;
+
+               if ((flags & OREFLAG_PUFF_ADDITIVE) && (y0 > y1))
+                       SWAP(int, y0, y1);
+
+               for (int y = y0; y <= y1; y++) {
+                       u32 i = vm->m_area.index(x, y, z);
+                       if (!vm->m_area.contains(i))
+                               continue;
+                       if (!CONTAINS(c_wherein, vm->m_data[i].getContent()))
+                               continue;
+
+                       vm->m_data[i] = n_ore;
+               }
+       }
+}
+
+
+///////////////////////////////////////////////////////////////////////////////
+
+
 void OreBlob::generate(MMVManip *vm, int mapseed, u32 blockseed,
        v3s16 nmin, v3s16 nmax, u8 *biomemap)
 {
@@ -285,7 +375,8 @@ void OreBlob::generate(MMVManip *vm, int mapseed, u32 blockseed,
 
 ///////////////////////////////////////////////////////////////////////////////
 
-OreVein::OreVein()
+OreVein::OreVein() :
+       Ore()
 {
        noise2 = NULL;
 }
index db204437ebf5cc0c3d0bec0022e2cf20f6908516..8ffb8fca0da4766e43b449b0695eac2fa58a653d 100644 (file)
@@ -30,17 +30,18 @@ class MMVManip;
 
 /////////////////// Ore generation flags
 
-// Use absolute value of height to determine ore placement
-#define OREFLAG_ABSHEIGHT 0x01
-#define OREFLAG_USE_NOISE 0x08
+#define OREFLAG_ABSHEIGHT     0x01
+#define OREFLAG_PUFF_CLIFFS   0x02
+#define OREFLAG_PUFF_ADDITIVE 0x04
+#define OREFLAG_USE_NOISE     0x08
 
 #define ORE_RANGE_ACTUAL 1
 #define ORE_RANGE_MIRROR 2
 
-
 enum OreType {
        ORE_SCATTER,
        ORE_SHEET,
+       ORE_PUFF,
        ORE_BLOB,
        ORE_VEIN,
 };
@@ -95,6 +96,22 @@ public:
                v3s16 nmin, v3s16 nmax, u8 *biomemap);
 };
 
+class OrePuff : public Ore {
+public:
+       static const bool NEEDS_NOISE = true;
+
+       NoiseParams np_puff_top;
+       NoiseParams np_puff_bottom;
+       Noise *noise_puff_top;
+       Noise *noise_puff_bottom;
+
+       OrePuff();
+       virtual ~OrePuff();
+
+       virtual void generate(MMVManip *vm, int mapseed, u32 blockseed,
+               v3s16 nmin, v3s16 nmax, u8 *biomemap);
+};
+
 class OreBlob : public Ore {
 public:
        static const bool NEEDS_NOISE = true;
@@ -134,6 +151,8 @@ public:
                        return new OreScatter;
                case ORE_SHEET:
                        return new OreSheet;
+               case ORE_PUFF:
+                       return new OrePuff;
                case ORE_BLOB:
                        return new OreBlob;
                case ORE_VEIN:
index 9050816bbcfa76277fe2585ff50b050e6f151f2a..dcb611f4758d482cbeb9664ba9f6a3b314c7f2e7 100644 (file)
@@ -70,6 +70,7 @@ struct EnumString ModApiMapgen::es_OreType[] =
 {
        {ORE_SCATTER, "scatter"},
        {ORE_SHEET,   "sheet"},
+       {ORE_PUFF,    "puff"},
        {ORE_BLOB,    "blob"},
        {ORE_VEIN,    "vein"},
        {0, NULL},
@@ -880,7 +881,7 @@ int ModApiMapgen::l_register_ore(lua_State *L)
                                "ore_type", es_OreType, ORE_SCATTER);
        Ore *ore = oremgr->create(oretype);
        if (!ore) {
-               errorstream << "register_ore: ore_type " << oretype << " not implemented";
+               errorstream << "register_ore: ore_type " << oretype << " not implemented\n";
                return 0;
        }
 
@@ -938,20 +939,42 @@ int ModApiMapgen::l_register_ore(lua_State *L)
        lua_pop(L, 1);
 
        //// Get type-specific parameters
-       if (oretype == ORE_SHEET) {
-               OreSheet *oresheet = (OreSheet *)ore;
-
-               oresheet->column_height_min = getintfield_default(L, index,
-                       "column_height_min", 1);
-               oresheet->column_height_max = getintfield_default(L, index,
-                       "column_height_max", ore->clust_size);
-               oresheet->column_midpoint_factor = getfloatfield_default(L, index,
-                       "column_midpoint_factor", 0.5f);
-       } else if (oretype == ORE_VEIN) {
-               OreVein *orevein = (OreVein *)ore;
-
-               orevein->random_factor = getfloatfield_default(L, index,
-                       "random_factor", 1.f);
+       switch (oretype) {
+               case ORE_SHEET: {
+                       OreSheet *oresheet = (OreSheet *)ore;
+
+                       oresheet->column_height_min = getintfield_default(L, index,
+                               "column_height_min", 1);
+                       oresheet->column_height_max = getintfield_default(L, index,
+                               "column_height_max", ore->clust_size);
+                       oresheet->column_midpoint_factor = getfloatfield_default(L, index,
+                               "column_midpoint_factor", 0.5f);
+
+                       break;
+               }
+               case ORE_PUFF: {
+                       OrePuff *orepuff = (OrePuff *)ore;
+
+                       lua_getfield(L, index, "np_puff_top");
+                       read_noiseparams(L, -1, &orepuff->np_puff_top);
+                       lua_pop(L, 1);
+
+                       lua_getfield(L, index, "np_puff_bottom");
+                       read_noiseparams(L, -1, &orepuff->np_puff_bottom);
+                       lua_pop(L, 1);
+
+                       break;
+               }
+               case ORE_VEIN: {
+                       OreVein *orevein = (OreVein *)ore;
+
+                       orevein->random_factor = getfloatfield_default(L, index,
+                               "random_factor", 1.f);
+
+                       break;
+               }
+               default:
+                       break;
        }
 
        ObjDefHandle handle = oremgr->add(ore);