Last active
March 9, 2022 00:51
-
-
Save Pilcrow182/6566668e96e74de6d6dbbcf318ddabc1 to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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) |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment