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
|
return colorstr, hex
|
||||||
end
|
end
|
||||||
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