forked from VoxeLibre/VoxeLibre
Add predicates
This commit is contained in:
parent
34c31cac1f
commit
67dd48b06c
|
@ -11,25 +11,25 @@ end)
|
||||||
|
|
||||||
|
|
||||||
function mcl_loottables.get_table(def)
|
function mcl_loottables.get_table(def)
|
||||||
local t = type(def)
|
return mcl_util.switch_type(def, {
|
||||||
if t == "nil" then
|
["nil"] = function()
|
||||||
return {}
|
return {}
|
||||||
elseif t == "string" then
|
end,
|
||||||
return assert(mcl_loottables.tables[def])
|
["string"] = function()
|
||||||
elseif t == "table" then
|
return mcl_loottables.tables[def], "table"
|
||||||
|
end,
|
||||||
|
["table"] = function()
|
||||||
return def
|
return def
|
||||||
else
|
end,
|
||||||
error("invalid loottable type: " .. t)
|
}, "loot table")
|
||||||
end
|
|
||||||
end
|
end
|
||||||
|
|
||||||
function mcl_loottables.get_entry_type(entry)
|
function mcl_loottables.get_entry_type(entry)
|
||||||
return assert(mcl_loottables.entries[entry.type])
|
return mcl_loottables.entries[entry.type]
|
||||||
end
|
end
|
||||||
|
|
||||||
function mcl_loottables.get_candidates(entries, data, func)
|
function mcl_loottables.get_candidates(entries, data, func)
|
||||||
local candidates = {}
|
local candidates = {}
|
||||||
local functions = {}
|
|
||||||
for _, entry in ipairs(entries) do
|
for _, entry in ipairs(entries) do
|
||||||
local success = mcl_predicates.do_predicates(entry.conditions, data)
|
local success = mcl_predicates.do_predicates(entry.conditions, data)
|
||||||
|
|
||||||
|
@ -87,7 +87,7 @@ function mcl_loottables.do_pools(pools, functions, data)
|
||||||
local stacks = func(selected, data)
|
local stacks = func(selected, data)
|
||||||
|
|
||||||
for _, stack in ipairs(stacks) do
|
for _, stack in ipairs(stacks) do
|
||||||
mcl_loottables.do_item_modifiers(stack, selected, data)
|
mcl_item_modifiers.do_item_modifiers(stack, selected, data)
|
||||||
end
|
end
|
||||||
table.insert_all(stacks, stack)
|
table.insert_all(stacks, stack)
|
||||||
end
|
end
|
||||||
|
@ -103,7 +103,7 @@ function mcl_loottables.get_loot(def, data)
|
||||||
end
|
end
|
||||||
|
|
||||||
function mcl_loottables.drop_loot(def, data)
|
function mcl_loottables.drop_loot(def, data)
|
||||||
local loot = mcl_loottables.get_loot(def)
|
local loot = mcl_loottables.get_loot(def, data)
|
||||||
local old_loot = table.copy(loot)
|
local old_loot = table.copy(loot)
|
||||||
for _, stack in ipairs(old_loot) do
|
for _, stack in ipairs(old_loot) do
|
||||||
local max_stack = stack:get_stack_max()
|
local max_stack = stack:get_stack_max()
|
||||||
|
@ -115,4 +115,5 @@ function mcl_loottables.drop_loot(def, data)
|
||||||
end
|
end
|
||||||
|
|
||||||
function mcl_loottables.fill_chest(def, data)
|
function mcl_loottables.fill_chest(def, data)
|
||||||
|
local loot = mcl_loottables.get_loot(def, data)
|
||||||
end
|
end
|
||||||
|
|
|
@ -1,15 +1,27 @@
|
||||||
mcl_numbers.register_provider = mcl_util.registration_function(mcl_numbers.providers)
|
mcl_numbers.register_provider = mcl_util.registration_function(mcl_numbers.providers)
|
||||||
|
|
||||||
function mcl_numbers.get_number(provider, data)
|
function mcl_numbers.get_number(provider, data)
|
||||||
local t = type(provider)
|
return mcl_util.switch_type(provider, {
|
||||||
if t == "nil" then
|
["number"] = function()
|
||||||
return 0
|
|
||||||
elseif t == "number" then
|
|
||||||
return provider
|
return provider
|
||||||
elseif t == "table" then
|
end,
|
||||||
local func = assert(mcl_numbers.providers[data.type])
|
["table"] = function()
|
||||||
return assert(tonumber(func(provider, data)))
|
local func = mcl_numbers.providers[data.type]
|
||||||
else
|
return func(provider, data)
|
||||||
error("invalid number type: " .. t)
|
end,
|
||||||
|
}, "number provider")
|
||||||
end
|
end
|
||||||
|
|
||||||
|
function mcl_numbers.check_bounds(actual, expected, data)
|
||||||
|
return mcl_util.switch_type(actual, {
|
||||||
|
["nil"] = function()
|
||||||
|
return true
|
||||||
|
end,
|
||||||
|
["number"] = function()
|
||||||
|
return actual == expected
|
||||||
|
end,
|
||||||
|
["table"] = function()
|
||||||
|
return actual <= mcl_numbers.get_number(expected.max, data) and actual >= mcl_numbers.get_number(expected.min, data)
|
||||||
|
end,
|
||||||
|
}, "range")
|
||||||
end
|
end
|
||||||
|
|
|
@ -7,14 +7,14 @@ mcl_numbers.register_provider("mcl_numbers:constant", function(provider)
|
||||||
end)
|
end)
|
||||||
|
|
||||||
mcl_numbers.register_provider("mcl_numbers:uniform", function(provider, data)
|
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))
|
return mcl_util.rand(data.pr, mcl_numbers.get_number(provider.min, data), mcl_numbers.get_number(provider.max, data))
|
||||||
end)
|
end)
|
||||||
|
|
||||||
mcl_numbers.register_provider("mcl_numbers:binomial", function(provider, data)
|
mcl_numbers.register_provider("mcl_numbers:binomial", function(provider, data)
|
||||||
local n = mcl_numbers.get_number(provider.n)
|
local n = mcl_numbers.get_number(provider.n, data)
|
||||||
local num = 0
|
local num = 0
|
||||||
for i = 1, n do
|
for i = 1, n do
|
||||||
if mcl_util.rand_bool(mcl_numbers.get_number(provider.p), data.pr) then
|
if mcl_util.rand_bool(mcl_numbers.get_number(provider.p, data), data.pr) then
|
||||||
num = num + 1
|
num = num + 1
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
|
@ -0,0 +1,84 @@
|
||||||
|
mcl_predicates.register_predicate = mcl_util.registration_function(mcl_predicates.predicates)
|
||||||
|
|
||||||
|
function mcl_predicates.get_predicate(id)
|
||||||
|
return mcl_util.switch_type(id, {
|
||||||
|
["function"] = function(v)
|
||||||
|
return v,
|
||||||
|
end,
|
||||||
|
["string"] = function(v)
|
||||||
|
return mcl_predicates.predicates[v]
|
||||||
|
end,
|
||||||
|
}, "predicate")
|
||||||
|
end
|
||||||
|
|
||||||
|
function mcl_predicates.do_predicates(predicates, data, or_mode)
|
||||||
|
or_mode = or_mode or false
|
||||||
|
for _, def in ipairs() do
|
||||||
|
local func = mcl_predicates.get_predicate(def.condition)
|
||||||
|
local failure = func and not func(def, data) or false
|
||||||
|
if or_mode ~= failure then
|
||||||
|
return or_mode
|
||||||
|
end
|
||||||
|
end
|
||||||
|
return not or_mode or #predicates == 0
|
||||||
|
end
|
||||||
|
|
||||||
|
function mcl_predicates.match_block(location, block, properties)
|
||||||
|
local node = minetest.get_node(location)
|
||||||
|
if node.name ~= block then
|
||||||
|
return false
|
||||||
|
end
|
||||||
|
if properties then
|
||||||
|
local meta = minetest.get_meta(location)
|
||||||
|
for k, v in pairs(properties) do
|
||||||
|
if meta:get_string(k) ~= v then
|
||||||
|
return false
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
return true
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
|
function mcl_predicates.match_tool(itemstack, predicate)
|
||||||
|
itemstack = itemstack or ItemStack()
|
||||||
|
|
||||||
|
local itemname = itemstack:get_name()
|
||||||
|
|
||||||
|
local expected_name = predicate.item
|
||||||
|
|
||||||
|
if expected_name and itemname ~= expected_name then
|
||||||
|
return false
|
||||||
|
end
|
||||||
|
|
||||||
|
local tag = predicate.tag
|
||||||
|
|
||||||
|
if tag and minetest.get_item_group(itemname, predicate) == 0 then
|
||||||
|
return false
|
||||||
|
end
|
||||||
|
|
||||||
|
if not mcl_numbers.check_bounds(itemstack:get_count(), predicate.count, data) then
|
||||||
|
return false
|
||||||
|
end
|
||||||
|
|
||||||
|
-- ToDo: Durability, needs research, needs abstraction ?
|
||||||
|
-- ToDo: potions, "nbt" aka metadata
|
||||||
|
|
||||||
|
local enchantments, stored_enchantments = predicate.enchantments, predicate.stored_enchantments
|
||||||
|
|
||||||
|
if enchantments and stored_enchantments then
|
||||||
|
enchantments = table.copy(enchantments)
|
||||||
|
table.insert_all(enchantments, stored_enchantments)
|
||||||
|
elseif stored_enchantments then
|
||||||
|
enchantments = stored_enchantments
|
||||||
|
end
|
||||||
|
if enchantments then
|
||||||
|
local actual_enchantments = mcl_enchanting.get_enchantments(itemstack)
|
||||||
|
for _, def in ipairs(actual_enchantments) do
|
||||||
|
local level = actual_enchantments[def.enchantment]
|
||||||
|
if not mcl_numbers.check_bounds(level, def.levels or {min = 1, max = math.huge}, data) then
|
||||||
|
return false
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
|
@ -0,0 +1,110 @@
|
||||||
|
mcl_predicates = {
|
||||||
|
predicates = {},
|
||||||
|
}
|
||||||
|
|
||||||
|
local modpath = minetest.get_modpath("mcl_predicates")
|
||||||
|
|
||||||
|
dofile(modpath .. "/api.lua")
|
||||||
|
|
||||||
|
mcl_predicates.register_predicate("alternative", function(predicate, data)
|
||||||
|
return mcl_predicates.do_predicates(predicate.terms, data, true)
|
||||||
|
end)
|
||||||
|
|
||||||
|
mcl_predicates.register_predicate("block_state_property", function(predicate, data)
|
||||||
|
return mcl_predicates.match_block(predicate.block, predicate.properties, data.location)
|
||||||
|
end)
|
||||||
|
|
||||||
|
mcl_predicates.register_predicate("damage_source_properties", function(predicate, data)
|
||||||
|
-- ToDo: damage source abstraction
|
||||||
|
return nil
|
||||||
|
end)
|
||||||
|
|
||||||
|
mcl_predicates.register_predicate("entity_properties", function(predicate, data)
|
||||||
|
local entity = predicate.entity
|
||||||
|
if not entity or (entity ~= "this" and entity ~= "killer" and entity ~= "killer_player") then
|
||||||
|
return false
|
||||||
|
end
|
||||||
|
|
||||||
|
local ref = data[entity]
|
||||||
|
if not ref then
|
||||||
|
return false
|
||||||
|
end
|
||||||
|
|
||||||
|
-- ToDo: entity / player abstraction
|
||||||
|
return nil
|
||||||
|
end)
|
||||||
|
|
||||||
|
mcl_predicates.register_predicate("entity_scores", function(predicate, data)
|
||||||
|
-- ToDo: scoreboards
|
||||||
|
return nil
|
||||||
|
end)
|
||||||
|
|
||||||
|
mcl_predicates.register_predicate("inverted", function(predicate, data)
|
||||||
|
return not mcl_predicates.do_predicates({predicate.term}, data)
|
||||||
|
end)
|
||||||
|
|
||||||
|
mcl_predicates.register_predicate("killed_by_player", function(predicate, data)
|
||||||
|
return not predicate.inverse ~= not data.killer_player
|
||||||
|
end)
|
||||||
|
|
||||||
|
mcl_predicates.register_predicate("location_check", function(predicate, data)
|
||||||
|
local location = vector.new(data.location)
|
||||||
|
|
||||||
|
location.x = location.x + (data.offsetX or 0)
|
||||||
|
location.y = location.y + (data.offsetY or 0)
|
||||||
|
location.z = location.z + (data.offsetZ or 0)
|
||||||
|
|
||||||
|
-- ToDo, needs abstraction?
|
||||||
|
return nil
|
||||||
|
end)
|
||||||
|
|
||||||
|
mcl_predicates.register_predicate("match_tool", function(predicate, data)
|
||||||
|
return mcl_predicates.match_tool(data.tool, predicate.predicate)
|
||||||
|
end)
|
||||||
|
|
||||||
|
mcl_predicates.register_predicate("random_chance", function(predicate, data)
|
||||||
|
return mcl_util.rand_bool(predicate.chance, data.pr)
|
||||||
|
end)
|
||||||
|
|
||||||
|
mcl_predicates.register_predicate("random_chance_with_looting", function(predicate, data)
|
||||||
|
local chance = predicate.chance -- + (looting_level * looting_multiplier)
|
||||||
|
|
||||||
|
-- ToDo: entity / player abstraction
|
||||||
|
return mcl_util.rand_bool(chance, data.pr)
|
||||||
|
end)
|
||||||
|
|
||||||
|
mcl_predicates.register_predicate("reference", function(predicate, data)
|
||||||
|
-- ToDo: needs research
|
||||||
|
return nil
|
||||||
|
end)
|
||||||
|
|
||||||
|
mcl_predicates.register_predicate("survives_explosion", function(predicate, data)
|
||||||
|
return mcl_util.rand_bool(data.drop_chance or 1, data.pr)
|
||||||
|
end)
|
||||||
|
|
||||||
|
mcl_predicates.register_predicate("table_bonus", function(predicate, data)
|
||||||
|
-- ToDo: entity / player abstraction
|
||||||
|
return nil
|
||||||
|
end)
|
||||||
|
|
||||||
|
mcl_predicates.register_predicate("time_check", function(predicate, data)
|
||||||
|
-- ToDo: needs research
|
||||||
|
return nil
|
||||||
|
end)
|
||||||
|
|
||||||
|
mcl_predicates.register_predicate("weather_check", function(predicate, data)
|
||||||
|
local weather = mcl_weather.get_weather()
|
||||||
|
|
||||||
|
if predicate.thundering then
|
||||||
|
return weather == "thunder"
|
||||||
|
elseif predicate.raining then
|
||||||
|
return weather == "rain"
|
||||||
|
else
|
||||||
|
return true
|
||||||
|
end
|
||||||
|
end)
|
||||||
|
|
||||||
|
mcl_predicates.register_predicate("value_check", function(predicate, data)
|
||||||
|
local value = mcl_numbers.get_number(predicate.value, data)
|
||||||
|
return mcl_numbers.check_in_bounds(value, predicate.range, data)
|
||||||
|
end)
|
|
@ -0,0 +1,4 @@
|
||||||
|
name = mcl_predicates
|
||||||
|
author = Fleckenstein
|
||||||
|
description = Provides MC-like predicates
|
||||||
|
depends = mcl_util, mcl_number
|
|
@ -438,5 +438,52 @@ function mcl_util.rand(pr, ...)
|
||||||
end
|
end
|
||||||
|
|
||||||
function mcl_util.rand_bool(probability, pr)
|
function mcl_util.rand_bool(probability, pr)
|
||||||
|
if probability >= 1 then
|
||||||
|
return true
|
||||||
|
elseif probability <= 0 then
|
||||||
|
return false
|
||||||
|
else
|
||||||
return mcl_util.rand(pr, 0, 32767) < probability * 32768
|
return mcl_util.rand(pr, 0, 32767) < probability * 32768
|
||||||
end
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
function mcl_util.switch_type(value, funcs, name)
|
||||||
|
local t = type(value)
|
||||||
|
local func = funcs[func] or funcs["default"]
|
||||||
|
if func then
|
||||||
|
return func(value, ...)
|
||||||
|
else
|
||||||
|
error("invalid " .. (name and name .. " " or "") .. "type: " .. t)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
--[[
|
||||||
|
function mcl_util.assert_type(value, expected_type, allow_nil)
|
||||||
|
local actual_type = type(value)
|
||||||
|
local errmsg = value .. " is not a " .. expected_type
|
||||||
|
|
||||||
|
if expected_type == "itemstack" then
|
||||||
|
return mcl_util.switch_type(value, {
|
||||||
|
["nil"] = function()
|
||||||
|
assert(allow_nil, errmsg)
|
||||||
|
end,
|
||||||
|
["string"] = ItemStack,
|
||||||
|
["table"] = ItemStack,
|
||||||
|
["userdata"] = function()
|
||||||
|
assert(value.get_name, errmsg)
|
||||||
|
return value
|
||||||
|
end,
|
||||||
|
}, "ItemStack")
|
||||||
|
end
|
||||||
|
|
||||||
|
if expected_type == "vector" then
|
||||||
|
assert(actual_type == "table", errmsg)
|
||||||
|
assert(value.x, errmsg)
|
||||||
|
assert(value.y, errmsg)
|
||||||
|
assert(value.z, errmsg)
|
||||||
|
else
|
||||||
|
assert((allow_nil and value == nil) or (actual_type == expected_type), errmsg)
|
||||||
|
end
|
||||||
|
return value
|
||||||
|
end
|
||||||
|
]]--
|
||||||
|
|
Loading…
Reference in New Issue