-- Copyright 2015 Eduardo MezĂȘncio --------------- -- Constants -- --------------- local modname = "em_dungeon_gen" local terminal_rarity = 1 local roomsize = 6 local halfrs = math.floor(roomsize / 2) local wallarea = (roomsize + 1) * (roomsize - 1) local pit_floors_min, pit_floors_max = 4, 8 local pit_layer_size = pit_floors_max * roomsize ---------------------- -- Helper Functions -- ---------------------- local function chance(num, den) return (math.random(den) <= num) end --------------- -- Materials -- --------------- minetest.register_node("em_dungeon_gen:wall", { drawtype = "glasslike", tiles = {"em_dungeon_gen_wall.png"}, is_ground_content = false, sounds = default.node_sound_stone_defaults(), paramtype = "light", sunlight_propagates = true, is_ground_content = false, light_source = 0,--default.LIGHT_MAX, }) local c_air = minetest.get_content_id("air") local c_cobble = minetest.get_content_id("em_dungeon_gen:wall") local c_mossycobble = minetest.get_content_id("em_dungeon_gen:wall") local c_torch = minetest.get_content_id("air") local c_bar_ns = minetest.get_content_id("terminal:terminal") local c_door = "air" --a --local c_bar_ew = minetest.get_content_id("default:glass") local function c_wall() if chance(1,2) then return c_cobble else return c_mossycobble end end local schematic_stairs = minetest.get_modpath(modname).."/schems/stairs.mts" ------------------ -- Change Spawn -- ------------------ local spawn_x, spawn_y, spawn_z = halfrs, 1, halfrs minetest.register_on_newplayer(function(player) player:setpos({x = spawn_x, y = spawn_y, z = spawn_z}) end) minetest.register_on_respawnplayer(function(player) player:setpos({x = spawn_x, y = spawn_y, z = spawn_z}) return true end) ------------------------- -- Map Generation Init -- ------------------------- local mapseed minetest.register_on_mapgen_init(function(mgparams) -- if mgparams.mgname ~= "singlenode" then -- minetest.set_mapgen_params({mgname="singlenode"}) -- end mapseed = minetest.get_mapgen_params().seed end) -------------------- -- Map Generation -- -------------------- minetest.register_on_generated(function(minp, maxp, blockseed) -- just for now, so that you can take a look from above :) if minp.y < 20000 then return end local vm, emin, emax = minetest.get_mapgen_object("voxelmanip") local va = VoxelArea:new{MinEdge=emin, MaxEdge=emax} local data = vm:get_data() local x_step = va:index(1,0,0) - va:index(0,0,0) local y_step = va:index(0,1,0) - va:index(0,0,0) local z_step = va:index(0,0,1) - va:index(0,0,0) ------------------- -- Floor/Ceiling -- ------------------- math.randomseed(minp.x + minp.y^2 + minp.z^3) for y = minp.y, maxp.y do if y % roomsize == 0 then for z = minp.z, maxp.z do local index = va:index(minp.x, y, z) for x = minp.x, maxp.x do data[index] = c_wall() index = index + x_step end end end end -- I'm subtracting roomsize at the end here so that each chunk also -- 'generates' one room outside of it. The reason is to build correctly -- things that are in the block borders local minx, miny, minz = minp.x, minp.y, minp.z if minx % roomsize ~= 0 then minx = minx - (minx % roomsize) - roomsize end if miny % roomsize ~= 0 then miny = miny - (miny % roomsize) - roomsize end if minz % roomsize ~= 0 then minz = minz - (minz % roomsize) - roomsize end ------------------------------ -- Walls, Doors and Torches -- ------------------------------ local doors, next_door = {}, 1 local stairs, next_stairs = {}, 1 local function place_stuff(x, y, z, ns) ----------- -- Walls -- ----------- if chance(3,4) then local xval, zval, step local rect = {b = math.max(minp.y, y + 1), t = math.min(maxp.y, y + roomsize - 1)} if ns then rect.l = math.max(minp.x, x) rect.r = math.min(maxp.x, x + roomsize) xval = rect.l zval = z step = x_step else rect.l = math.max(minp.z, z) rect.r = math.min(maxp.z, z + roomsize) xval = x zval = rect.l step = z_step end local wallnodes = 0 for yval = rect.b, rect.t do local index = va:index(xval, yval, zval) for x_or_z = rect.l, rect.r do data[index] = c_wall() wallnodes = wallnodes + 1 index = index + step end end -- This will hopefully ensure that the random number -- generator is always in the same "position" after -- generating the wall while wallnodes < wallarea do math.random() wallnodes = wallnodes + 1 end ----------- -- Doors -- ----------- if chance(1,2) then local coord = {x = x, y = y + 2, z = z} if ns then coord.x = coord.x + halfrs else coord.z = coord.z + halfrs end -- Portal -- if va:contains(coord.x, coord.y, coord.z) then data[va:index(coord.x, coord.y, coord.z)] = c_air end coord.y = coord.y - 1 if va:contains(coord.x, coord.y, coord.z) then data[va:index(coord.x, coord.y, coord.z)] = c_air end -- Door (generated later) -- if chance(1,2) then doors[next_door] = {x=coord.x, y=coord.y, z=coord.z, ns=ns} next_door = next_door + 1 end else if chance(1,2) then local c_bar local coord = {x = x, y = y + 2, z = z} --[[if math.random(1,terminal_rarity) == 1 then c_bar = c_bar_ns else c_bar = c_bar_ew end--]] c_bar = c_bar_ns -- Window -- if va:contains(coord.x, coord.y, coord.z) then data[va:index(coord.x, coord.y, coord.z)] = c_bar end end end end end for y=miny, maxp.y, roomsize do for z=minz, maxp.z, roomsize do for x=minx, maxp.x, roomsize do math.randomseed(x + y^2 + z^3) -- Stairs (generated later) if chance(1, 128) then stairs[next_stairs] = {x = x, y = y, z = z, dir = math.random(0,3)} next_stairs = next_stairs + 1 else place_stuff(x, y, z, true) -- along the x axis place_stuff(x, y, z, false) -- along the z axix ------------- -- Torches -- ------------- if chance(1,8) then local coord = {x = x + halfrs, y = y + roomsize - 1, z = z + halfrs} if va:contains(coord.x, coord.y, coord.z) then data[va:index(coord.x, coord.y, coord.z)] = c_torch end end end end end end ---------- -- Pits -- ---------- local block_depth = maxp.y - minp.y + 1 local pit_layers = math.ceil(block_depth / pit_layer_size) + 2 local first_pit_layer = minp.y - (minp.y % pit_layer_size) - pit_layer_size local y = first_pit_layer for layer_count = 1, pit_layers do for z=minz, maxp.z, roomsize do for x=minx, maxp.x, roomsize do math.randomseed(x + y^2 + z^3) if chance(1, 128) then local start = math.random(1, pit_floors_max) local size = math.random(pit_floors_min, pit_floors_max) local yy = y + start * roomsize for floor_count = 1, size do -- Remove torches if va:contains(x + halfrs, yy - 1, z + halfrs) then data[va:index(x + halfrs, yy - 1, z + halfrs)] = c_air end if yy > maxp.y then break end if yy >= minp.y then for zz = math.max(minp.z, z + 1), math.min(maxp.x, z + roomsize - 1) do local startx = math.max(minp.x, x + 1) local index = va:index(startx, yy, zz) for xx = startx, math.min(maxp.x, x + roomsize - 1) do data[index] = c_air index = index + x_step end end end yy = yy + roomsize end end end end y = y + pit_layer_size end vm:set_data(data) vm:set_lighting({day=0, night=0}) vm:calc_lighting() vm:write_to_map(data) ----------------- -- Place Doors -- ----------------- for current_door_index, current_door in pairs(doors) do local door_dir if current_door.ns then door_dir = minetest.dir_to_facedir({x = 0, y = 0, z = 1}) else door_dir = minetest.dir_to_facedir({x = 1, y = 0, z = 0}) end local door_pos = {x = current_door.x, y = current_door.y, z = current_door.z} minetest.set_node(door_pos, {name = c_door, param2 = door_dir}) --door_pos.y = door_pos.y + 1 --minetest.set_node(door_pos, {name = "doors:door_wood_t_1", -- param2 = door_dir}) end ------------------ -- Place Stairs -- ------------------ for unused, s in pairs(stairs) do minetest.place_schematic({x = s.x, y = s.y + 1, z = s.z}, schematic_stairs, s.dir * 90, {}, true) if chance(7,8) then minetest.set_node({x = s.x + halfrs, y = s.y + 2 * roomsize - 1, z = s.z + halfrs}, {name = "air"}) end end end)