Aaron Suen 47d0b68dba Unify dungeon API RNG
Avoid having to have each dungeon generation method manage its
own RNG, which should save a lot of time on RNG seeding.
2021-09-27 08:04:09 -04:00

98 lines
2.9 KiB
Lua

-- LUALOCALS < ---------------------------------------------------------
local ItemStack, io, ipairs, math, minetest, nodecore, pairs, tonumber
= ItemStack, io, ipairs, math, minetest, nodecore, pairs, tonumber
local io_open, math_floor, math_log
= io.open, math.floor, math.log
-- LUALOCALS > ---------------------------------------------------------
nodecore.amcoremod()
local loottable = {}
do
local ltcsv = io_open(minetest.get_modpath(minetest.get_current_modname())
.. "/loot.csv", "r")
local cols = ltcsv:read("*l"):split(",")
while true do
local str = ltcsv:read("*l")
if not str then break end
local data = str:split(",")
local row = {}
for i, k in ipairs(cols) do
row[k] = tonumber(data[i]) or data[i]
end
loottable[#loottable + 1] = row
end
end
local function lootstack(pos, rng)
local loot = nodecore.pickrand(loottable,
function(t) return pos.y <= t.depth and t.prob or 0 end,
rng)
local def = minetest.registered_items[loot.item]
if not def then return end
local stack = ItemStack(loot.item)
if def.type == "tool" then
stack:set_wear(rng(20000, 50000))
elseif def.stack_max > 1 then
local qty = math_floor(nodecore.exporand(loot.qty / 10, rng))
if qty < 1 then qty = 1 elseif qty > def.stack_max then qty = def.stack_max end
stack:set_count(qty)
end
return stack
end
local cobbles = {["nc_terrain:cobble"] = true}
local cobblist = {}
minetest.after(0, function()
for k, v in pairs(minetest.registered_nodes) do
if v.groups and v.groups.dungeon_mapgen then
cobbles[k] = true
end
end
for k in pairs(cobbles) do
cobblist[#cobblist + 1] = k
end
end)
local function addloot(pos, height, rng)
if rng(1, 5) == 1 and #nodecore.find_nodes_around(pos, cobblist, {1, 0, 1}) > 0 then
local max = nodecore.exporand(2, rng)
if max < 1 then max = 1 elseif max > height then max = height end
for _ = 1, max do
minetest.set_node(pos, {name = "nc_woodwork:shelf"})
nodecore.stack_set(pos, lootstack(pos, rng))
pos.y = pos.y + 1
end
return
end
minetest.set_node(pos, {name = "nc_items:stack"})
nodecore.stack_set(pos, lootstack(pos, rng))
nodecore.stack_node_sounds_except[minetest.hash_node_position(pos)] = true
end
nodecore.register_dungeongen({
label = "dungeon loot",
priority = 100,
func = function(pos, _, rng)
local above = {x = pos.x, y = pos.y + 1, z = pos.z}
if minetest.get_node(above).name ~= "air" then return end
local prob = 0.1
if pos.y < -128 then
prob = prob * math_log(pos.y / -64) / math_log(2)
end
if rng() > prob then return end
for dy = 2, 8 do
local p = {x = pos.x, y = pos.y + dy, z = pos.z}
local nn = minetest.get_node(p).name
if cobbles[nn] then
return #nodecore.find_nodes_around(pos,
{"air"}, {1, 0, 1}) > 0
or addloot(above, dy - 2, rng)
end
if nn ~= "air" then return end
end
if pos.y > -64 then return end
addloot(above, 8, rng)
end
})