Instantly share code, notes, and snippets.

# Pilcrow182/prototype_roguelike_mapgen.lua Last active Apr 22, 2017

What would you like to do?
 math.randomseed(os.time()) roguelike = { init_map = function(width, height, wall_probability) local map, x, y = {}, 0, 0 -- Fill map with random splatter. It will be smoothed by roguelike.next_gen() for row = 1, height do map[row] = {} for column = 1, width do map[row][column] = math.floor(math.random() + wall_probability / 100) end end -- Paint a big X after random splatter to ensure the map is mostly connected. -- this is faster than any flood-fill function I could come up with, but we -- *may* generate small isolated sections since we're not checking connectivity. local max_offset = math.max(width, height) for offset = 1, max_offset do x = math.floor((height * offset / max_offset) + 0.5) y = math.floor((width * offset / max_offset) + 0.5) for xc = math.max(1, x-1), math.min(height, x+1) do for yc = math.max(1, y-1), math.min(width, y+1) do map[xc][yc] = 0 map[xc][width+1-yc] = 0 end end end return map end, get_neighbors = function(map, x, y, radius) local neighbor_count, add_num = 0, 0 for xn = x - radius, x + radius do for yn = y - radius, y + radius do if map[xn] and map[xn][yn] then add_num = map[xn][yn] else add_num = 0 end neighbor_count = neighbor_count + add_num end end return neighbor_count end, next_gen = function(map, near_threshold, far_threshold) local new = {} for row = 1, #map do new[row] = {} for column = 1, #map[1] do local neighbors_near = roguelike.get_neighbors(map, row, column, 1) local neighbors_far = roguelike.get_neighbors(map, row, column, 2) if neighbors_near >= near_threshold or neighbors_far <= far_threshold then new[row][column] = 1 else new[row][column] = 0 end end end return new end, make_map = function(width, height, wall_probability) local map = roguelike.init_map(width, height, wall_probability) for g = 1, 4 do map = roguelike.next_gen(map, 5, 2) end for g = 1, 3 do map = roguelike.next_gen(map, 5, 0) end for g = 1, 2 do map = roguelike.next_gen(map, 7, 0) end return map end, print_map = function(data) local line, char = "", "" for row = 1, #data do line = "" for column = 1, #data[1] do if data[row][column] == 1 then char = "#" else char = "." end line = line .. char end print(line) end end, } local test_map = roguelike.make_map(70, 50, 20) if minetest then -- this check is here so we can still debug using the cli lua interpreter minetest.register_node("roguelike:stone", { description = "Roguelike Stone", tiles = {"default_stone.png"}, is_ground_content = false, groups = {cracky = 3, stone = 1}, }) minetest.register_node("roguelike:air", { description = "Glowing Air (roguelike)", drawtype = "airlike", inventory_image = "air.png", wield_image = "air.png", paramtype = "light", light_source = 14, is_ground_content = false, air_equivalent = true, floodable = true, pointable = false, sunlight_propagates = true, walkable = false, diggable = false, buildable_to = true, groups = {not_in_creative_inventory = 1}, }) roguelike.place_map = function(data, pos) minetest.chat_send_all("Making map at pos " .. minetest.pos_to_string(pos)) local line, char, node_name = "", "", "" for row = 0, #data+1 do for column = 0, #data[1]+1 do if data[row] and data[row][column] then if data[row][column] == 1 then node_name = "roguelike:stone" else node_name = "roguelike:air" end minetest.set_node({x = pos.x + row, y = pos.y - 1, z = pos.z + column}, {name="roguelike:stone"}) -- floor for height = 0, 2 do minetest.set_node({x = pos.x + row, y = pos.y + height, z = pos.z + column}, {name=node_name}) -- walls end minetest.set_node({x = pos.x + row, y = pos.y + 3, z = pos.z + column}, {name="roguelike:stone"}) -- ceiling else for height = -1, 3 do minetest.set_node({x = pos.x + row, y = pos.y + height, z = pos.z + column}, {name="roguelike:stone"}) -- outer walls end end end end end minetest.register_chatcommand("test", { params = "", description = "create a procedually generated roguelike map (using Cellular Automata)", func = function(name, param) local player = minetest.get_player_by_name(name) local pos = player:getpos() pos = {x = math.floor(pos.x - 2.5), y = math.floor(pos.y - 4.5), z = math.floor(pos.z - 2.5)} roguelike.place_map(test_map, pos) pos = player:getpos() pos = {x = math.floor(pos.x + 0.5), y = math.floor(pos.y - 4.5), z = math.floor(pos.z + 0.5)} for xoff = -1, 1 do for zoff = -1, 1 do for yoff = 0, 2 do minetest.set_node({x = pos.x + xoff, y = pos.y + yoff, z = pos.z + zoff}, {name="roguelike:air"}) end for yoff = 3, 4 do minetest.set_node({x = pos.x + xoff, y = pos.y + yoff, z = pos.z + zoff}, {name="roguelike:stone"}) end end end for yoff = 0, 4 do minetest.set_node({x = pos.x, y = pos.y + yoff, z = pos.z}, {name="default:ladder", param2 = 5}) minetest.set_node({x = pos.x, y = pos.y + yoff, z = pos.z - 1}, {name="roguelike:stone"}) end end, }) end roguelike.print_map(test_map)