local max_depth = 31000 -- All arrays in the maze functions are zero-based. local floor_noise_1 = {offset = 0, scale = 1, seed = 1587, spread = {x = 30, y = 30, z = 30}, octaves = 3, persist = 1, lacunarity = 2} function table.shuffle(self) local j local t = self for i = #t, 1, -1 do j = math.random(0, i) t[i], t[j] = t[j], t[i] end end function unionfind(max) local u = { _parent = {}, _rank = {} } for i = 0, max-1 do u._parent[i] = i u._rank[i] = 0 end u.find = function(self, i) local p = self._parent[i] if i == p then return i end self._parent[i] = self:find(p) return self._parent[i] end u.union = function(self, i, j) i = i or 0 j = j or 0 local root1 = self:find(i) local root2 = self:find(j) if root1 == root2 then return end if self._rank[root1] > self._rank[root2] then self._parent[root2] = root1 elseif self._rank[root2] > self._rank[root1] then self._parent[root1] = root2 else self._parent[root2] = root1 self._rank[root1] = self._rank[root1] + 1 end end return u end -- Now back to the actual fortress code... fun_caves.fortress = function(minp, maxp, data, area, node) -- hungry maze -- chests (w traps) -- step traps (math based) -- hidden doors/downs -- hot/ice floors -- torches -- local level = math.min(6, math.ceil(maxp.y / math.floor(max_depth / -6))) local n = 16 local walls = {} local inner_floor = node['fun_caves:dungeon_floor_1'] local outer_wall = node['fun_caves:dungeon_wall_2'] local inner_wall = node['fun_caves:dungeon_wall_1'] local treasure_count = 0 local csize = vector.add(vector.subtract(maxp, minp), 1) local floor_1 = minetest.get_perlin_map(floor_noise_1, {x=csize.x, y=csize.z}):get2dMap_flat({x=minp.x, y=minp.z}) for y2 = 0, n-1 do local floor_type = math.random(20) --for y2 = 0, 0 do -- walls is zero-based. for i = 0, 2 * n * n - 1 do walls[i] = i end table.shuffle(walls) local dox, doz = math.random(0, n-1), math.random(0, n-1) for z = minp.z, maxp.z do for y = minp.y + y2 * 5, minp.y + y2 * 5 + 4 do local ivm = area:index(minp.x, y, z) for x = minp.x, maxp.x do if x == minp.x or z == minp.z or x == maxp.x or z == maxp.z then data[ivm] = outer_wall elseif (y - minp.y) % 5 == 0 then if math.floor((z - minp.z) / 5) == doz and math.floor((x - minp.x) / 5) == dox and (z - minp.z) % 5 ~= 0 and (x - minp.x) % 5 ~= 0 and y ~= minp.y then data[ivm] = node["air"] else data[ivm] = inner_floor end elseif (z - minp.z) % 5 == 0 or (x - minp.x) % 5 == 0 then if y2 == 0 and math.random(3000) == 1 then treasure_count = treasure_count + 1 data[ivm] = node['fun_caves:coffer'] elseif floor_type == 1 and level > 3 then data[ivm] = node['fun_caves:dungeon_wall_invisible'] elseif floor_type == 1 then data[ivm] = node['fun_caves:dungeon_wall_transparent'] elseif floor_type ~= 3 then data[ivm] = inner_wall end else data[ivm] = node["air"] end ivm = ivm + 1 end end end local set = unionfind(n * n) -- Remove walls in a continuous path. if floor_type ~= 3 then for m = 0, #walls do local c = walls[m] local a = math.floor(c / 2) local i = a % n local j = math.floor(a / n) local u = c % 2 == 0 and 1 or 0 local v = c % 2 == 1 and 1 or 0 local b = a + u + n * v if i < n - u and j < n - v and set:find(a) ~= set:find(b) then set:union(a, b) local x = (i + u) * 5 + minp.x local y = minp.y + y2 * 5 local z = (j + v) * 5 + minp.z for z1 = z + (1-v), z + (1-v) * 4 do for y1 = y + 1, y + 4 do local ivm = area:index(x + (1-u), y1, z1) for x1 = x + (1-u), x + (1-u) * 4 do if x1 < maxp.x and z1 < maxp.z and x1 > minp.x and z1 > minp.z then data[ivm] = node["air"] end ivm = ivm + 1 end end end end end end local index = 0 for z = minp.z + 1, maxp.z - 1 do for x = minp.x + 1, maxp.x - 1 do index = index + 1 local ivm = area:index(x, minp.y + y2 * 5, z) if floor_type == 2 then if data[ivm] ~= node['air'] and data[ivm + area.ystride] == node['air'] then if level > 3 then data[ivm + area.ystride] = node['default:lava_source'] else data[ivm + area.ystride] = node['fun_caves:hot_cobble'] end end elseif floor_type == 3 then if data[ivm] ~= node['air'] then for i = 1, math.min(4, math.floor(4 * math.abs(floor_1[index]))) do data[ivm + area.ystride * i] = node['default:dirt'] end end elseif floor_type == 4 then for i = 1, 4 do if data[ivm + area.ystride * i] == node['air'] then data[ivm + area.ystride * i] = node['default:water_source'] end end end end end end end