Add groupcache and number providers; Add loottables (WIP)
parent
6e6809f360
commit
ca94a1c354
|
@ -0,0 +1,32 @@
|
|||
mcl_groupcache = {
|
||||
cache = {},
|
||||
}
|
||||
|
||||
local function check_insert(item, group, cache)
|
||||
if minetest.get_item_group(item, group) ~= 0 then
|
||||
table.insert(cache, item)
|
||||
end
|
||||
end
|
||||
|
||||
local old_register_item = minetest.register_item
|
||||
|
||||
function minetest.register_item(name, def)
|
||||
old_register_item(name, def)
|
||||
for group, cache in pairs(mcl_groupcache.cache) do
|
||||
check_insert(item, group, cache)
|
||||
end
|
||||
end
|
||||
|
||||
function mcl_groupcache.init_cache(group)
|
||||
local cache = {}
|
||||
for item in pairs(minetest.registered_items) do
|
||||
check_insert(item, group, cache)
|
||||
end
|
||||
return cache
|
||||
end
|
||||
|
||||
function mcl_groupcache.get_items_in_group(group)
|
||||
local cache = mcl_groupcache.cache[group] or mcl_groupcache.init_cache(group)
|
||||
mcl_groupcache.cache[group] = cache
|
||||
return cache
|
||||
end
|
|
@ -0,0 +1,3 @@
|
|||
name = mcl_groupcache
|
||||
author = Fleckenstein
|
||||
description = Keep track of items with certain groups
|
|
@ -0,0 +1,118 @@
|
|||
mcl_loottables.register_entry = mcl_util.registration_function(mcl_loottables.entries)
|
||||
mcl_loottables.register_table = mcl_util.registration_function(mcl_loottables.tables, function(name, def)
|
||||
local function set_parents(parent)
|
||||
for _, child in ipairs(parent.children or parent.entries or parent.pools or {}) do
|
||||
child.parent = parent
|
||||
set_parents(child)
|
||||
end
|
||||
end
|
||||
set_parents(def)
|
||||
end)
|
||||
|
||||
|
||||
function mcl_loottables.get_table(def)
|
||||
local t = type(def)
|
||||
if t == "nil" then
|
||||
return {}
|
||||
elseif t == "string" then
|
||||
return assert(mcl_loottables.tables[def])
|
||||
elseif t == "table" then
|
||||
return def
|
||||
else
|
||||
error("invalid loottable type: " .. t)
|
||||
end
|
||||
end
|
||||
|
||||
function mcl_loottables.get_entry_type(entry)
|
||||
return assert(mcl_loottables.entries[entry.type])
|
||||
end
|
||||
|
||||
function mcl_loottables.get_candidates(entries, data, func)
|
||||
local candidates = {}
|
||||
local functions = {}
|
||||
for _, entry in ipairs(entries) do
|
||||
local success = mcl_predicates.do_predicates(entry.conditions, data)
|
||||
|
||||
if success then
|
||||
local children = entry.children
|
||||
|
||||
if children then
|
||||
table.insert_all(candidates, mcl_loottables.get_candidates(children, data, mcl_loottables.get_entry_type(entry).preprocess))
|
||||
else
|
||||
table.insert(candidates, entry)
|
||||
end
|
||||
end
|
||||
|
||||
if func and func(success, data) then
|
||||
break
|
||||
end
|
||||
end
|
||||
return candidates
|
||||
end
|
||||
|
||||
function mcl_loottables.do_item_modifiers(itemstack, node, data)
|
||||
if node then
|
||||
mcl_functions.do_item_modifiers(itemstack, node.functions, data)
|
||||
mcl_loottables.do_item_modifiers(itemstack, node.parent, data)
|
||||
end
|
||||
end
|
||||
|
||||
function mcl_loottables.do_pools(pools, functions, data)
|
||||
local luck = data.luck or 0
|
||||
local stacks = {}
|
||||
for _, pool in ipairs(pools or {}) do
|
||||
if mcl_conditions.do_conditions(pool.conditions, data) do
|
||||
local rolls = mcl_loottables.get_number(pool.rolls, data) + mcl_loottables.get_number(pool.bonus_rolls, data) * luck
|
||||
for i = 1, rolls do
|
||||
local candidates = mcl_loottables.get_candidates(pool.entries, data)
|
||||
|
||||
if #candidates > 0 then
|
||||
local total_weight = 0
|
||||
local weights = {}
|
||||
for _, candidate in ipairs(candidates)
|
||||
total_weight = total_weight + math.floor((candidate.weight or 1) + (candidate.quality or 0) * luck)
|
||||
table.insert(weights, total_weight)
|
||||
end
|
||||
|
||||
local selected
|
||||
local rnd = mcl_util.rand(data.pr, 0, weight - 1)
|
||||
for i, w in ipairs(weights) do
|
||||
if rnd < w then
|
||||
selected = candidates[i]
|
||||
break
|
||||
end
|
||||
end
|
||||
|
||||
local func = mcl_loottables.get_entry_type(entry).process
|
||||
local stacks = func(selected, data)
|
||||
|
||||
for _, stack in ipairs(stacks) do
|
||||
mcl_loottables.do_item_modifiers(stack, selected, data)
|
||||
end
|
||||
table.insert_all(stacks, stack)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
return stacks
|
||||
end
|
||||
|
||||
function mcl_loottables.get_loot(def, data)
|
||||
def = mcl_loottables.get_table(def)
|
||||
return mcl_loottables.do_pools(def.pools)
|
||||
end
|
||||
|
||||
function mcl_loottables.drop_loot(def, data)
|
||||
local loot = mcl_loottables.get_loot(def)
|
||||
local old_loot = table.copy(loot)
|
||||
for _, stack in ipairs(old_loot) do
|
||||
local max_stack = stack:get_stack_max()
|
||||
while max_stack < stack:get_count() do
|
||||
table.insert(loot, stack:take_items(max_stack))
|
||||
end
|
||||
end
|
||||
return loot
|
||||
end
|
||||
|
||||
function mcl_loottables.fill_chest(def, data)
|
||||
end
|
|
@ -0,0 +1,44 @@
|
|||
mcl_loottables.register_entry("mcl_loottables:alternatives", {
|
||||
preprocess = function(success, data)
|
||||
return success
|
||||
end,
|
||||
})
|
||||
|
||||
mcl_loottables.register_entry("mcl_loottables:group", {
|
||||
preprocess = function(success, data)
|
||||
return false
|
||||
end,
|
||||
})
|
||||
|
||||
mcl_loottables.register_entry("mcl_loottables:sequence", {
|
||||
preprocess = function(success, data)
|
||||
return not success
|
||||
end,
|
||||
})
|
||||
|
||||
mcl_loottables.register_entry("mcl_loottables:tag", function(entry, data)
|
||||
local stacks = mcl_groupcache.get_items_in_group(entry.name)
|
||||
if entry.expand then
|
||||
stacks = {stacks[pr:next(1, #stacks)]}
|
||||
end
|
||||
return stacks
|
||||
end)
|
||||
|
||||
mcl_loottables.register_entry("mcl_loottables:loot_table", {
|
||||
process = function(entry, data)
|
||||
return mcl_loottables.get_loot(entry.name, data)
|
||||
end,
|
||||
})
|
||||
|
||||
mcl_loottables.register_entry("mcl_loottables:empty", {
|
||||
process = function(entry, data)
|
||||
return {}
|
||||
end,
|
||||
})
|
||||
|
||||
mcl_loottables.register_entry("mcl_loottables:item", {
|
||||
process = function(entry, data)
|
||||
return {item = ItemStack(entry.name)}
|
||||
end,
|
||||
})
|
||||
|
|
@ -0,0 +1,9 @@
|
|||
mcl_loottables = {
|
||||
tables = {},
|
||||
entries = {},
|
||||
}
|
||||
|
||||
local modpath = minetest.get_modpath("mcl_loottables")
|
||||
|
||||
dofile(modpath .. "/api.lua")
|
||||
dofile(modpath .. "/entries.lua")
|
|
@ -0,0 +1,4 @@
|
|||
name = mcl_loot
|
||||
author = Fleckenstein
|
||||
description = Provides Minecraft-like loot table definitions
|
||||
depends = mcl_util, mcl_predicates, mcl_item_modifiers
|
|
@ -0,0 +1,15 @@
|
|||
mcl_numbers.register_provider = mcl_util.registration_function(mcl_numbers.providers)
|
||||
|
||||
function mcl_numbers.get_number(provider, data)
|
||||
local t = type(provider)
|
||||
if t == "nil" then
|
||||
return 0
|
||||
elseif t == "number" then
|
||||
return provider
|
||||
elseif t == "table" then
|
||||
local func = assert(mcl_numbers.providers[data.type])
|
||||
return assert(tonumber(func(provider, data)))
|
||||
else
|
||||
error("invalid number type: " .. t)
|
||||
end
|
||||
end
|
|
@ -0,0 +1,23 @@
|
|||
mcl_numbers = {
|
||||
providers = {},
|
||||
}
|
||||
|
||||
mcl_numbers.register_provider("mcl_numbers:constant", function(provider)
|
||||
return provider.value
|
||||
end)
|
||||
|
||||
mcl_numbers.register_provider("mcl_numbers:uniform", function(provider, data)
|
||||
return mcl_util.rand(data.pr, mcl_numbers.get_number(provider.min), mcl_numbers.get_number(provider.max))
|
||||
end)
|
||||
|
||||
mcl_numbers.register_provider("mcl_numbers:binomial", function(provider, data)
|
||||
local n = mcl_numbers.get_number(provider.n)
|
||||
local num = 0
|
||||
for i = 1, n do
|
||||
if mcl_util.rand_bool(mcl_numbers.get_number(provider.p), data.pr) then
|
||||
num = num + 1
|
||||
end
|
||||
end
|
||||
return num
|
||||
end)
|
||||
|
|
@ -0,0 +1,4 @@
|
|||
name = mcl_numbers
|
||||
author = Fleckenstein
|
||||
description = Minecraft-like number providers
|
||||
depends = mcl_util
|
|
@ -418,3 +418,25 @@ function mcl_util.get_color(colorstr)
|
|||
return colorstr, hex
|
||||
end
|
||||
end
|
||||
|
||||
function mcl_util.registration_function(tbl, func)
|
||||
return function(name, def)
|
||||
if func then
|
||||
local res = func(name, def)
|
||||
if res == false then
|
||||
return
|
||||
elseif res ~= nil then
|
||||
def = res
|
||||
end
|
||||
end
|
||||
tbl[name] = def
|
||||
end
|
||||
end
|
||||
|
||||
function mcl_util.rand(pr, ...)
|
||||
return pr and pr:next(...) or math.random(...)
|
||||
end
|
||||
|
||||
function mcl_util.rand_bool(probability, pr)
|
||||
return mcl_util.rand(pr, 0, 32767) < probability * 32768
|
||||
end
|
||||
|
|
Loading…
Reference in New Issue