]> git.lizzy.rs Git - minetest.git/blobdiff - src/mapgen/mg_decoration.cpp
Add chat HUD flag (#13189)
[minetest.git] / src / mapgen / mg_decoration.cpp
index dd621db111e04e779fb7a49ff1ef5f90c67b0325..369f7b4a0299fdd35bdd23445a11b8fba2d8fae7 100644 (file)
@@ -67,6 +67,13 @@ size_t DecorationManager::placeAllDecos(Mapgen *mg, u32 blockseed,
        return nplaced;
 }
 
+DecorationManager *DecorationManager::clone() const
+{
+       auto mgr = new DecorationManager();
+       ObjDefManager::cloneTo(mgr);
+       return mgr;
+}
+
 
 ///////////////////////////////////////////////////////////////////////////////
 
@@ -110,7 +117,7 @@ bool Decoration::canPlaceDecoration(MMVManip *vm, v3s16 p)
                v3s16( 1, 1, -1)
        };
 
-       // Check these 16 neighbouring nodes for enough spawnby nodes
+       // Check these 16 neighboring nodes for enough spawnby nodes
        for (size_t i = 0; i != ARRLEN(dirs); i++) {
                u32 index = vm->m_area.index(p + dirs[i]);
                if (!vm->m_area.contains(index))
@@ -155,23 +162,43 @@ size_t Decoration::placeDeco(Mapgen *mg, u32 blockseed, v3s16 nmin, v3s16 nmax)
                        nmin.Z + sidelen + sidelen * z0 - 1
                );
 
+               bool cover = false;
                // Amount of decorations
                float nval = (flags & DECO_USE_NOISE) ?
                        NoisePerlin2D(&np, p2d_center.X, p2d_center.Y, mapseed) :
                        fill_ratio;
                u32 deco_count = 0;
-               float deco_count_f = (float)area * nval;
-               if (deco_count_f >= 1.f) {
-                       deco_count = deco_count_f;
-               } else if (deco_count_f > 0.f) {
-                       // For low density decorations calculate a chance for 1 decoration
-                       if (ps.range(1000) <= deco_count_f * 1000.f)
-                               deco_count = 1;
+
+               if (nval >= 10.0f) {
+                       // Complete coverage. Disable random placement to avoid
+                       // redundant multiple placements at one position.
+                       cover = true;
+                       deco_count = area;
+               } else {
+                       float deco_count_f = (float)area * nval;
+                       if (deco_count_f >= 1.0f) {
+                               deco_count = deco_count_f;
+                       } else if (deco_count_f > 0.0f) {
+                               // For very low density calculate a chance for 1 decoration
+                               if (ps.range(1000) <= deco_count_f * 1000.0f)
+                                       deco_count = 1;
+                       }
                }
 
+               s16 x = p2d_min.X - 1;
+               s16 z = p2d_min.Y;
+
                for (u32 i = 0; i < deco_count; i++) {
-                       s16 x = ps.range(p2d_min.X, p2d_max.X);
-                       s16 z = ps.range(p2d_min.Y, p2d_max.Y);
+                       if (!cover) {
+                               x = ps.range(p2d_min.X, p2d_max.X);
+                               z = ps.range(p2d_min.Y, p2d_max.Y);
+                       } else {
+                               x++;
+                               if (x == p2d_max.X + 1) {
+                                       z++;
+                                       x = p2d_min.X;
+                               }
+                       }
                        int mapindex = carea_size * (z - nmin.Z) + (x - nmin.X);
 
                        if ((flags & DECO_ALL_FLOORS) ||
@@ -179,8 +206,7 @@ size_t Decoration::placeDeco(Mapgen *mg, u32 blockseed, v3s16 nmin, v3s16 nmax)
                                // All-surfaces decorations
                                // Check biome of column
                                if (mg->biomemap && !biomes.empty()) {
-                                       std::unordered_set<u8>::const_iterator iter =
-                                               biomes.find(mg->biomemap[mapindex]);
+                                       auto iter = biomes.find(mg->biomemap[mapindex]);
                                        if (iter == biomes.end())
                                                continue;
                                }
@@ -232,8 +258,7 @@ size_t Decoration::placeDeco(Mapgen *mg, u32 blockseed, v3s16 nmin, v3s16 nmax)
                                        continue;
 
                                if (mg->biomemap && !biomes.empty()) {
-                                       std::unordered_set<u8>::const_iterator iter =
-                                               biomes.find(mg->biomemap[mapindex]);
+                                       auto iter = biomes.find(mg->biomemap[mapindex]);
                                        if (iter == biomes.end())
                                                continue;
                                }
@@ -249,9 +274,42 @@ size_t Decoration::placeDeco(Mapgen *mg, u32 blockseed, v3s16 nmin, v3s16 nmax)
 }
 
 
+void Decoration::cloneTo(Decoration *def) const
+{
+       ObjDef::cloneTo(def);
+       def->flags = flags;
+       def->mapseed = mapseed;
+       def->c_place_on = c_place_on;
+       def->sidelen = sidelen;
+       def->y_min = y_min;
+       def->y_max = y_max;
+       def->fill_ratio = fill_ratio;
+       def->np = np;
+       def->c_spawnby = c_spawnby;
+       def->nspawnby = nspawnby;
+       def->place_offset_y = place_offset_y;
+       def->biomes = biomes;
+}
+
+
 ///////////////////////////////////////////////////////////////////////////////
 
 
+ObjDef *DecoSimple::clone() const
+{
+       auto def = new DecoSimple();
+       Decoration::cloneTo(def);
+
+       def->c_decos = c_decos;
+       def->deco_height = deco_height;
+       def->deco_height_max = deco_height_max;
+       def->deco_param2 = deco_param2;
+       def->deco_param2_max = deco_param2_max;
+
+       return def;
+}
+
+
 void DecoSimple::resolveNodeNames()
 {
        Decoration::resolveNodeNames();
@@ -331,6 +389,31 @@ size_t DecoSimple::generate(MMVManip *vm, PcgRandom *pr, v3s16 p, bool ceiling)
 ///////////////////////////////////////////////////////////////////////////////
 
 
+DecoSchematic::~DecoSchematic()
+{
+       if (was_cloned)
+               delete schematic;
+}
+
+
+ObjDef *DecoSchematic::clone() const
+{
+       auto def = new DecoSchematic();
+       Decoration::cloneTo(def);
+       NodeResolver::cloneTo(def);
+
+       def->rotation = rotation;
+       /* FIXME: We do not own this schematic, yet we only have a pointer to it
+        * and not a handle. We are left with no option but to clone it ourselves.
+        * This is a waste of memory and should be replaced with an alternative
+        * approach sometime. */
+       def->schematic = dynamic_cast<Schematic*>(schematic->clone());
+       def->was_cloned = true;
+
+       return def;
+}
+
+
 size_t DecoSchematic::generate(MMVManip *vm, PcgRandom *pr, v3s16 p, bool ceiling)
 {
        // Schematic could have been unloaded but not the decoration
@@ -360,13 +443,22 @@ size_t DecoSchematic::generate(MMVManip *vm, PcgRandom *pr, v3s16 p, bool ceilin
        if (p.Y < vm->m_area.MinEdge.Y)
                return 0;
 
-       if (flags & DECO_PLACE_CENTER_X)
-               p.X -= (schematic->size.X - 1) / 2;
-       if (flags & DECO_PLACE_CENTER_Z)
-               p.Z -= (schematic->size.Z - 1) / 2;
-
        Rotation rot = (rotation == ROTATE_RAND) ?
                (Rotation)pr->range(ROTATE_0, ROTATE_270) : rotation;
+
+       if (flags & DECO_PLACE_CENTER_X) {
+               if (rot == ROTATE_0 || rot == ROTATE_180)
+                       p.X -= (schematic->size.X - 1) / 2;
+               else
+                       p.Z -= (schematic->size.X - 1) / 2;
+       }
+       if (flags & DECO_PLACE_CENTER_Z) {
+               if (rot == ROTATE_0 || rot == ROTATE_180)
+                       p.Z -= (schematic->size.Z - 1) / 2;
+               else
+                       p.X -= (schematic->size.Z - 1) / 2;
+       }
+
        bool force_placement = (flags & DECO_FORCE_PLACEMENT);
 
        schematic->blitToVManip(vm, p, rot, force_placement);