Dungeons: Generalise use, add capabilities, various modifications 4249/head
authorparamat <mat.gregory@virginmedia.com>
Sun, 12 Jun 2016 02:11:26 +0000 (03:11 +0100)
committerparamat <mat.gregory@virginmedia.com>
Fri, 17 Jun 2016 03:42:42 +0000 (04:42 +0100)
- Generalise node names to c_wall and c_alt_wall
- Remove 'mossratio' and instead disable alt_wall loop if
  c_alt_wall == CONTENT_IGNORE
- Use one generalised 3D noise for alternative wall nodes and in
  mgv6 create moss distribution similar to the previous

- Rename rarity noise to density noise and enable the option of multiple
  dungeons per chunk determined by the value. Recreate previous distribution
- Add parameters for min and max rooms per dungeon
- Add dungeon y limits

- Integrate river water properly

Generalisation is needed now that we have sandstone and desert stone
dungeons by default and can choose any node for alternative structure.
The current code is based around cobble dungeons with mossycobble
alternative nodes, the 2 noises controlling the alternative nodes
are based on wetness.

Enabling multiple dungeons per chunk with definable number of rooms
allows the option of very dense and complex underground structures
that could interconnect to create megastructures.
Y limits are added to be consistent with other mapgen elements, and
enable locaton of dungeon or megastructure realms as part of our
'stacked realms' philosophy.

src/dungeongen.cpp
src/dungeongen.h
src/mapgen.cpp
src/mapgen_v6.cpp

index 6be7e908636508be2ab2582965df9926d458cc0a..78573da04c4adb36a1130e4b88b009741da9502e 100644 (file)
@@ -30,9 +30,8 @@ with this program; if not, write to the Free Software Foundation, Inc.,
 
 //#define DGEN_USE_TORCHES
 
-NoiseParams nparams_dungeon_rarity(0.0, 1.0, v3f(500.0, 500.0, 500.0), 0, 2, 0.8, 2.0);
-NoiseParams nparams_dungeon_wetness(0.0, 1.0, v3f(40.0, 40.0, 40.0), 32474, 4, 1.1, 2.0);
-NoiseParams nparams_dungeon_density(0.0, 1.0, v3f(2.5, 2.5, 2.5), 0, 2, 1.4, 2.0);
+NoiseParams nparams_dungeon_density(0.9, 0.5, v3f(500.0, 500.0, 500.0), 0, 2, 0.8, 2.0);
+NoiseParams nparams_dungeon_alt_wall(-0.4, 1.0, v3f(40.0, 40.0, 40.0), 32474, 6, 1.1, 2.0);
 
 
 ///////////////////////////////////////////////////////////////////////////////
@@ -55,26 +54,27 @@ DungeonGen::DungeonGen(INodeDefManager *ndef,
        } else {
                dp.seed = 0;
 
-               dp.c_water  = ndef->getId("mapgen_water_source");
-               dp.c_cobble = ndef->getId("mapgen_cobble");
-               dp.c_moss   = ndef->getId("mapgen_mossycobble");
-               dp.c_stair  = ndef->getId("mapgen_stair_cobble");
+               dp.c_water       = ndef->getId("mapgen_water_source");
+               dp.c_river_water = ndef->getId("mapgen_river_water_source");
+               dp.c_wall        = ndef->getId("mapgen_cobble");
+               dp.c_alt_wall    = ndef->getId("mapgen_mossycobble");
+               dp.c_stair       = ndef->getId("mapgen_stair_cobble");
+
+               if (dp.c_river_water == CONTENT_IGNORE)
+                       dp.c_river_water = ndef->getId("mapgen_water_source");
 
                dp.diagonal_dirs = false;
-               dp.mossratio     = 3.0;
                dp.holesize      = v3s16(1, 2, 1);
                dp.roomsize      = v3s16(0, 0, 0);
+               dp.rooms_min     = 2;
+               dp.rooms_max     = 16;
+               dp.y_min         = -MAX_MAP_GENERATION_LIMIT;
+               dp.y_max         = MAX_MAP_GENERATION_LIMIT;
                dp.notifytype    = GENNOTIFY_DUNGEON;
 
-               dp.np_rarity  = nparams_dungeon_rarity;
-               dp.np_wetness = nparams_dungeon_wetness;
-               dp.np_density = nparams_dungeon_density;
+               dp.np_density  = nparams_dungeon_density;
+               dp.np_alt_wall = nparams_dungeon_alt_wall;
        }
-
-       // For mapgens using river water
-       dp.c_river_water = ndef->getId("mapgen_river_water_source");
-       if (dp.c_river_water == CONTENT_IGNORE)
-               dp.c_river_water = ndef->getId("mapgen_water_source");
 }
 
 
@@ -83,7 +83,11 @@ void DungeonGen::generate(MMVManip *vm, u32 bseed, v3s16 nmin, v3s16 nmax)
        assert(vm);
 
        //TimeTaker t("gen dungeons");
-       if (NoisePerlin3D(&dp.np_rarity, nmin.X, nmin.Y, nmin.Z, dp.seed) < 0.2)
+       if (nmin.Y < dp.y_min || nmax.Y > dp.y_max)
+               return;
+
+       float nval_density = NoisePerlin3D(&dp.np_density, nmin.X, nmin.Y, nmin.Z, dp.seed);
+       if (nval_density < 1.0f)
                return;
 
        this->vm = vm;
@@ -107,23 +111,23 @@ void DungeonGen::generate(MMVManip *vm, u32 bseed, v3s16 nmin, v3s16 nmax)
                }
        }
 
-       // Add it
-       makeDungeon(v3s16(1, 1, 1) * MAP_BLOCKSIZE);
+       // Add them
+       for (u32 i = 0; i < floor(nval_density); i++)
+               makeDungeon(v3s16(1, 1, 1) * MAP_BLOCKSIZE);
 
-       // Convert some cobble to mossy cobble
-       if (dp.mossratio != 0.0) {
-               for (s16 z = nmin.Z; z <= nmax.Z; z++)
-               for (s16 y = nmin.Y; y <= nmax.Y; y++) {
-                       u32 i = vm->m_area.index(nmin.X, y, z);
-                       for (s16 x = nmin.X; x <= nmax.X; x++) {
-                               if (vm->m_data[i].getContent() == dp.c_cobble) {
-                                       float wetness = NoisePerlin3D(&dp.np_wetness, x, y, z, dp.seed);
-                                       float density = NoisePerlin3D(&dp.np_density, x, y, z, blockseed);
-                                       if (density < wetness / dp.mossratio)
-                                               vm->m_data[i].setContent(dp.c_moss);
-                               }
-                               i++;
+       // Optionally convert some structure to alternative structure
+       if (dp.c_alt_wall == CONTENT_IGNORE)
+               return;
+
+       for (s16 z = nmin.Z; z <= nmax.Z; z++)
+       for (s16 y = nmin.Y; y <= nmax.Y; y++) {
+               u32 i = vm->m_area.index(nmin.X, y, z);
+               for (s16 x = nmin.X; x <= nmax.X; x++) {
+                       if (vm->m_data[i].getContent() == dp.c_wall) {
+                               if (NoisePerlin3D(&dp.np_alt_wall, x, y, z, blockseed) > 0.0f)
+                                       vm->m_data[i].setContent(dp.c_alt_wall);
                        }
+                       i++;
                }
        }
 
@@ -189,7 +193,7 @@ void DungeonGen::makeDungeon(v3s16 start_padding)
        */
        v3s16 last_room_center = roomplace + v3s16(roomsize.X / 2, 1, roomsize.Z / 2);
 
-       u32 room_count = random.range(2, 16);
+       u32 room_count = random.range(dp.rooms_min, dp.rooms_max);
        for (u32 i = 0; i < room_count; i++) {
                // Make a room to the determined place
                makeRoom(roomsize, roomplace);
@@ -265,7 +269,7 @@ void DungeonGen::makeDungeon(v3s16 start_padding)
 
 void DungeonGen::makeRoom(v3s16 roomsize, v3s16 roomplace)
 {
-       MapNode n_cobble(dp.c_cobble);
+       MapNode n_wall(dp.c_wall);
        MapNode n_air(CONTENT_AIR);
 
        // Make +-X walls
@@ -278,7 +282,7 @@ void DungeonGen::makeRoom(v3s16 roomsize, v3s16 roomplace)
                        u32 vi = vm->m_area.index(p);
                        if (vm->m_flags[vi] & VMANIP_FLAG_DUNGEON_UNTOUCHABLE)
                                continue;
-                       vm->m_data[vi] = n_cobble;
+                       vm->m_data[vi] = n_wall;
                }
                {
                        v3s16 p = roomplace + v3s16(roomsize.X - 1, y, z);
@@ -287,7 +291,7 @@ void DungeonGen::makeRoom(v3s16 roomsize, v3s16 roomplace)
                        u32 vi = vm->m_area.index(p);
                        if (vm->m_flags[vi] & VMANIP_FLAG_DUNGEON_UNTOUCHABLE)
                                continue;
-                       vm->m_data[vi] = n_cobble;
+                       vm->m_data[vi] = n_wall;
                }
        }
 
@@ -301,7 +305,7 @@ void DungeonGen::makeRoom(v3s16 roomsize, v3s16 roomplace)
                        u32 vi = vm->m_area.index(p);
                        if (vm->m_flags[vi] & VMANIP_FLAG_DUNGEON_UNTOUCHABLE)
                                continue;
-                       vm->m_data[vi] = n_cobble;
+                       vm->m_data[vi] = n_wall;
                }
                {
                        v3s16 p = roomplace + v3s16(x, y, roomsize.Z - 1);
@@ -310,7 +314,7 @@ void DungeonGen::makeRoom(v3s16 roomsize, v3s16 roomplace)
                        u32 vi = vm->m_area.index(p);
                        if (vm->m_flags[vi] & VMANIP_FLAG_DUNGEON_UNTOUCHABLE)
                                continue;
-                       vm->m_data[vi] = n_cobble;
+                       vm->m_data[vi] = n_wall;
                }
        }
 
@@ -324,7 +328,7 @@ void DungeonGen::makeRoom(v3s16 roomsize, v3s16 roomplace)
                        u32 vi = vm->m_area.index(p);
                        if (vm->m_flags[vi] & VMANIP_FLAG_DUNGEON_UNTOUCHABLE)
                                continue;
-                       vm->m_data[vi] = n_cobble;
+                       vm->m_data[vi] = n_wall;
                }
                {
                        v3s16 p = roomplace + v3s16(x,roomsize. Y - 1, z);
@@ -333,7 +337,7 @@ void DungeonGen::makeRoom(v3s16 roomsize, v3s16 roomplace)
                        u32 vi = vm->m_area.index(p);
                        if (vm->m_flags[vi] & VMANIP_FLAG_DUNGEON_UNTOUCHABLE)
                                continue;
-                       vm->m_data[vi] = n_cobble;
+                       vm->m_data[vi] = n_wall;
                }
        }
 
@@ -417,7 +421,7 @@ void DungeonGen::makeCorridor(v3s16 doorplace, v3s16 doordir,
                                makeFill(p + v3s16(-1, -1, -1),
                                        dp.holesize + v3s16(2, 3, 2),
                                        VMANIP_FLAG_DUNGEON_UNTOUCHABLE,
-                                       MapNode(dp.c_cobble),
+                                       MapNode(dp.c_wall),
                                        0);
                                makeHole(p);
                                makeHole(p - dir);
@@ -435,18 +439,18 @@ void DungeonGen::makeCorridor(v3s16 doorplace, v3s16 doordir,
                                        int facedir = dir_to_facedir(dir * make_stairs);
 
                                        u32 vi = vm->m_area.index(p.X - dir.X, p.Y - 1, p.Z - dir.Z);
-                                       if (vm->m_data[vi].getContent() == dp.c_cobble)
+                                       if (vm->m_data[vi].getContent() == dp.c_wall)
                                                vm->m_data[vi] = MapNode(dp.c_stair, 0, facedir);
 
                                        vi = vm->m_area.index(p.X, p.Y, p.Z);
-                                       if (vm->m_data[vi].getContent() == dp.c_cobble)
+                                       if (vm->m_data[vi].getContent() == dp.c_wall)
                                                vm->m_data[vi] = MapNode(dp.c_stair, 0, facedir);
                                }
                        } else {
                                makeFill(p + v3s16(-1, -1, -1),
                                        dp.holesize + v3s16(2, 2, 2),
                                        VMANIP_FLAG_DUNGEON_UNTOUCHABLE,
-                                       MapNode(dp.c_cobble),
+                                       MapNode(dp.c_wall),
                                        0);
                                makeHole(p);
                        }
@@ -488,8 +492,8 @@ bool DungeonGen::findPlaceForDoor(v3s16 &result_place, v3s16 &result_dir)
                        randomizeDir();
                        continue;
                }
-               if (vm->getNodeNoExNoEmerge(p).getContent() == dp.c_cobble &&
-                               vm->getNodeNoExNoEmerge(p1).getContent() == dp.c_cobble) {
+               if (vm->getNodeNoExNoEmerge(p).getContent() == dp.c_wall &&
+                               vm->getNodeNoExNoEmerge(p1).getContent() == dp.c_wall) {
                        // Found wall, this is a good place!
                        result_place = p;
                        result_dir = m_dir;
@@ -502,7 +506,7 @@ bool DungeonGen::findPlaceForDoor(v3s16 &result_place, v3s16 &result_dir)
                */
                // Jump one up if the actual space is there
                if (vm->getNodeNoExNoEmerge(p +
-                               v3s16(0, 0, 0)).getContent() == dp.c_cobble &&
+                               v3s16(0, 0, 0)).getContent() == dp.c_wall &&
                                vm->getNodeNoExNoEmerge(p +
                                v3s16(0, 1, 0)).getContent() == CONTENT_AIR &&
                                vm->getNodeNoExNoEmerge(p +
@@ -510,7 +514,7 @@ bool DungeonGen::findPlaceForDoor(v3s16 &result_place, v3s16 &result_dir)
                        p += v3s16(0,1,0);
                // Jump one down if the actual space is there
                if (vm->getNodeNoExNoEmerge(p +
-                               v3s16(0, 1, 0)).getContent() == dp.c_cobble &&
+                               v3s16(0, 1, 0)).getContent() == dp.c_wall &&
                                vm->getNodeNoExNoEmerge(p +
                                v3s16(0, 0, 0)).getContent() == CONTENT_AIR &&
                                vm->getNodeNoExNoEmerge(p +
index 8986274834e2f6adc55c12095c10ff04a030f2cb..30786b9f3b0e2b2a60d2e0103addb66a92080af8 100644 (file)
@@ -43,19 +43,21 @@ struct DungeonParams {
 
        content_t c_water;
        content_t c_river_water;
-       content_t c_cobble;
-       content_t c_moss;
+       content_t c_wall;
+       content_t c_alt_wall;
        content_t c_stair;
 
-       GenNotifyType notifytype;
        bool diagonal_dirs;
-       float mossratio;
        v3s16 holesize;
        v3s16 roomsize;
+       u16 rooms_min;
+       u16 rooms_max;
+       s16 y_min;
+       s16 y_max;
+       GenNotifyType notifytype;
 
-       NoiseParams np_rarity;
-       NoiseParams np_wetness;
        NoiseParams np_density;
+       NoiseParams np_alt_wall;
 };
 
 class DungeonGen {
@@ -99,8 +101,7 @@ public:
        }
 };
 
-extern NoiseParams nparams_dungeon_rarity;
-extern NoiseParams nparams_dungeon_wetness;
 extern NoiseParams nparams_dungeon_density;
+extern NoiseParams nparams_dungeon_alt_wall;
 
 #endif
index 576fb219af5328c340cd9d18ef229b52e54e3cc8..1e0e3aa44232286e4061b9ad2eec5ceec9e0e771 100644 (file)
@@ -738,44 +738,44 @@ void MapgenBasic::generateDungeons(s16 max_stone_y, MgStoneType stone_type)
 
        DungeonParams dp;
 
-       dp.seed = seed;
-
-       dp.np_rarity  = nparams_dungeon_rarity;
-       dp.np_density = nparams_dungeon_density;
-       dp.np_wetness = nparams_dungeon_wetness;
-       dp.c_water    = c_water_source;
+       dp.seed          = seed;
+       dp.c_water       = c_water_source;
+       dp.c_river_water = c_river_water_source;
+       dp.rooms_min     = 2;
+       dp.rooms_max     = 16;
+       dp.y_min         = -MAX_MAP_GENERATION_LIMIT;
+       dp.y_max         = MAX_MAP_GENERATION_LIMIT;
+       dp.np_density    = nparams_dungeon_density;
+       dp.np_alt_wall   = nparams_dungeon_alt_wall;
 
        switch (stone_type) {
        default:
        case MGSTONE_STONE:
-               dp.c_cobble = c_cobble;
-               dp.c_moss   = c_mossycobble;
-               dp.c_stair  = c_stair_cobble;
+               dp.c_wall     = c_cobble;
+               dp.c_alt_wall = c_mossycobble;
+               dp.c_stair    = c_stair_cobble;
 
                dp.diagonal_dirs = false;
-               dp.mossratio     = 3.0;
                dp.holesize      = v3s16(1, 2, 1);
                dp.roomsize      = v3s16(0, 0, 0);
                dp.notifytype    = GENNOTIFY_DUNGEON;
                break;
        case MGSTONE_DESERT_STONE:
-               dp.c_cobble = c_desert_stone;
-               dp.c_moss   = c_desert_stone;
-               dp.c_stair  = c_desert_stone;
+               dp.c_wall     = c_desert_stone;
+               dp.c_alt_wall = CONTENT_IGNORE;
+               dp.c_stair    = c_desert_stone;
 
                dp.diagonal_dirs = true;
-               dp.mossratio     = 0.0;
                dp.holesize      = v3s16(2, 3, 2);
                dp.roomsize      = v3s16(2, 5, 2);
                dp.notifytype    = GENNOTIFY_TEMPLE;
                break;
        case MGSTONE_SANDSTONE:
-               dp.c_cobble = c_sandstonebrick;
-               dp.c_moss   = c_sandstonebrick;
-               dp.c_stair  = c_sandstonebrick;
+               dp.c_wall     = c_sandstonebrick;
+               dp.c_alt_wall = CONTENT_IGNORE;
+               dp.c_stair    = c_sandstonebrick;
 
                dp.diagonal_dirs = false;
-               dp.mossratio     = 0.0;
                dp.holesize      = v3s16(2, 2, 2);
                dp.roomsize      = v3s16(2, 0, 2);
                dp.notifytype    = GENNOTIFY_DUNGEON;
index 103120b6a1c2d4ed5fe6e078c36fb31397ae6940..caa64827ecb64d685fa966ac48972c85df870575 100644 (file)
@@ -560,28 +560,30 @@ void MapgenV6::makeChunk(BlockMakeData *data)
                DungeonParams dp;
 
                dp.seed = seed;
+               dp.c_water       = c_water_source;
+               dp.c_river_water = c_water_source;
+               dp.rooms_min     = 2;
+               dp.rooms_max     = 16;
+               dp.y_min         = -MAX_MAP_GENERATION_LIMIT;
+               dp.y_max         = MAX_MAP_GENERATION_LIMIT;
+               dp.np_density    = NoiseParams(0.9, 0.5, v3f(500.0, 500.0, 500.0), 0, 2, 0.8, 2.0);
+               dp.np_alt_wall   = NoiseParams(-0.4, 1.0, v3f(40.0, 40.0, 40.0), 32474, 6, 1.1, 2.0);
 
-               dp.np_rarity  = nparams_dungeon_rarity;
-               dp.np_density = nparams_dungeon_density;
-               dp.np_wetness = nparams_dungeon_wetness;
-               dp.c_water    = c_water_source;
                if (getBiome(0, v2s16(node_min.X, node_min.Z)) == BT_DESERT) {
-                       dp.c_cobble = c_desert_stone;
-                       dp.c_moss   = c_desert_stone;
-                       dp.c_stair  = c_desert_stone;
+                       dp.c_wall     = c_desert_stone;
+                       dp.c_alt_wall = CONTENT_IGNORE;
+                       dp.c_stair    = c_desert_stone;
 
                        dp.diagonal_dirs = true;
-                       dp.mossratio     = 0.0;
                        dp.holesize      = v3s16(2, 3, 2);
                        dp.roomsize      = v3s16(2, 5, 2);
                        dp.notifytype    = GENNOTIFY_TEMPLE;
                } else {
-                       dp.c_cobble = c_cobble;
-                       dp.c_moss   = c_mossycobble;
-                       dp.c_stair  = c_stair_cobble;
+                       dp.c_wall     = c_cobble;
+                       dp.c_alt_wall = c_mossycobble;
+                       dp.c_stair    = c_stair_cobble;
 
                        dp.diagonal_dirs = false;
-                       dp.mossratio     = 3.0;
                        dp.holesize      = v3s16(1, 2, 1);
                        dp.roomsize      = v3s16(0, 0, 0);
                        dp.notifytype    = GENNOTIFY_DUNGEON;