From ca94a1c3545e2d02fca155b2315c406d63ca8853 Mon Sep 17 00:00:00 2001 From: Elias Fleckenstein Date: Mon, 8 Mar 2021 14:40:57 +0100 Subject: [PATCH] Add groupcache and number providers; Add loottables (WIP) --- mods/CORE/mcl_groupcache/init.lua | 32 ++++++++ mods/CORE/mcl_groupcache/mod.conf | 3 + mods/CORE/mcl_loottables/api.lua | 118 +++++++++++++++++++++++++++ mods/CORE/mcl_loottables/entries.lua | 44 ++++++++++ mods/CORE/mcl_loottables/init.lua | 9 ++ mods/CORE/mcl_loottables/mod.conf | 4 + mods/CORE/mcl_numbers/api.lua | 15 ++++ mods/CORE/mcl_numbers/init.lua | 23 ++++++ mods/CORE/mcl_numbers/mod.conf | 4 + mods/CORE/mcl_util/init.lua | 22 +++++ 10 files changed, 274 insertions(+) create mode 100644 mods/CORE/mcl_groupcache/init.lua create mode 100644 mods/CORE/mcl_groupcache/mod.conf create mode 100644 mods/CORE/mcl_loottables/api.lua create mode 100644 mods/CORE/mcl_loottables/entries.lua create mode 100644 mods/CORE/mcl_loottables/init.lua create mode 100644 mods/CORE/mcl_loottables/mod.conf create mode 100644 mods/CORE/mcl_numbers/api.lua create mode 100644 mods/CORE/mcl_numbers/init.lua create mode 100644 mods/CORE/mcl_numbers/mod.conf diff --git a/mods/CORE/mcl_groupcache/init.lua b/mods/CORE/mcl_groupcache/init.lua new file mode 100644 index 0000000000..8d6a04e3c6 --- /dev/null +++ b/mods/CORE/mcl_groupcache/init.lua @@ -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 diff --git a/mods/CORE/mcl_groupcache/mod.conf b/mods/CORE/mcl_groupcache/mod.conf new file mode 100644 index 0000000000..e488d16774 --- /dev/null +++ b/mods/CORE/mcl_groupcache/mod.conf @@ -0,0 +1,3 @@ +name = mcl_groupcache +author = Fleckenstein +description = Keep track of items with certain groups diff --git a/mods/CORE/mcl_loottables/api.lua b/mods/CORE/mcl_loottables/api.lua new file mode 100644 index 0000000000..010434affd --- /dev/null +++ b/mods/CORE/mcl_loottables/api.lua @@ -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 diff --git a/mods/CORE/mcl_loottables/entries.lua b/mods/CORE/mcl_loottables/entries.lua new file mode 100644 index 0000000000..5a9b806449 --- /dev/null +++ b/mods/CORE/mcl_loottables/entries.lua @@ -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, +}) + diff --git a/mods/CORE/mcl_loottables/init.lua b/mods/CORE/mcl_loottables/init.lua new file mode 100644 index 0000000000..26ea1ff63a --- /dev/null +++ b/mods/CORE/mcl_loottables/init.lua @@ -0,0 +1,9 @@ +mcl_loottables = { + tables = {}, + entries = {}, +} + +local modpath = minetest.get_modpath("mcl_loottables") + +dofile(modpath .. "/api.lua") +dofile(modpath .. "/entries.lua") diff --git a/mods/CORE/mcl_loottables/mod.conf b/mods/CORE/mcl_loottables/mod.conf new file mode 100644 index 0000000000..668ba6bd21 --- /dev/null +++ b/mods/CORE/mcl_loottables/mod.conf @@ -0,0 +1,4 @@ +name = mcl_loot +author = Fleckenstein +description = Provides Minecraft-like loot table definitions +depends = mcl_util, mcl_predicates, mcl_item_modifiers diff --git a/mods/CORE/mcl_numbers/api.lua b/mods/CORE/mcl_numbers/api.lua new file mode 100644 index 0000000000..fcb8392edd --- /dev/null +++ b/mods/CORE/mcl_numbers/api.lua @@ -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 diff --git a/mods/CORE/mcl_numbers/init.lua b/mods/CORE/mcl_numbers/init.lua new file mode 100644 index 0000000000..d539edb92d --- /dev/null +++ b/mods/CORE/mcl_numbers/init.lua @@ -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) + diff --git a/mods/CORE/mcl_numbers/mod.conf b/mods/CORE/mcl_numbers/mod.conf new file mode 100644 index 0000000000..ad9949f5f5 --- /dev/null +++ b/mods/CORE/mcl_numbers/mod.conf @@ -0,0 +1,4 @@ +name = mcl_numbers +author = Fleckenstein +description = Minecraft-like number providers +depends = mcl_util diff --git a/mods/CORE/mcl_util/init.lua b/mods/CORE/mcl_util/init.lua index a43c3d5d0b..13432ed0cd 100644 --- a/mods/CORE/mcl_util/init.lua +++ b/mods/CORE/mcl_util/init.lua @@ -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