a-planet-alive/mods/gui/smart_inventory/libs/filter.lua

410 lines
9.7 KiB
Lua

local txt = smart_inventory.txt
--------------------------------------------------------------
-- Filter class
--------------------------------------------------------------
local filter_class = {}
local filter_class_mt = {__index = filter_class}
function filter_class:check_item_by_name(itemname)
if minetest.registered_items[itemname] then
return self:check_item_by_def(minetest.registered_items[itemname])
end
end
function filter_class:check_item_by_def(def)
error("check_item_by_def needs redefinition:"..debug.traceback())
end
function filter_class:_get_description(group)
if txt then
if txt[group.name] then
return txt[group.name].." ("..group.name..")"
elseif group.parent and group.parent.childs[group.name] and txt[group.parent.name] then
return txt[group.parent.name].." "..group.parent.childs[group.name].." ("..group.name..")"
else
return group.name
end
else
return group.name
end
end
filter_class.get_description = filter_class._get_description
function filter_class:_get_keyword(group)
return group.group_desc
end
filter_class.get_keyword = filter_class._get_keyword
function filter_class:is_valid(group)
return true
end
local filter = {}
filter.registered_filter = {}
function filter.get(name)
return filter.registered_filter[name]
end
function filter.register_filter(def)
assert(def.name, "filter needs a name")
assert(def.check_item_by_def, "filter function check_item_by_def required")
assert(not filter.registered_filter[def.name], "filter already exists")
setmetatable(def, filter_class_mt)
filter.registered_filter[def.name] = def
end
-- rename groups for beter consistency
filter.group_rename = {
customnode_default = "customnode",
}
-- group configurations per basename
-- true means is dimension
-- 1 means replace the base only ("food_choco_powder" => food:choco_powder")
filter.base_group_config = {
armor = true,
physics = true,
basecolor = true,
excolor = true,
color = true,
unicolor = true,
food = 1,
customnode = true,
}
-- hide this groups
filter.group_hide_config = {
armor_count = true,
not_in_creative_inventory = false,
}
-- value of this group will be recalculated to %
filter.group_wear_config = {
armor_use = true,
}
-- Ususally 1 means true for group values. This is an exceptions table for this rule
filter.group_with_value_1_config = {
oddly_breakable_by_hand = true,
}
--------------------------------------------------------------
-- Filter group
--------------------------------------------------------------
filter.register_filter({
name = "group",
check_item_by_def = function(self, def)
local ret = {}
for k_orig, v in pairs(def.groups) do
local k = filter.group_rename[k_orig] or k_orig
local mk, mv
-- Check group base
local basename
for z in k:gmatch("[^_]+") do
basename = z
break
end
local basegroup_config = filter.base_group_config[basename]
if basegroup_config == true then
mk = string.gsub(k, "_", ":")
elseif basegroup_config == 1 then
mk = string.gsub(k, "^"..basename.."_", basename..":")
else
mk = k
end
-- stack wear related value
if filter.group_wear_config[k] then
mv = tostring(math.floor(v / 65535 * 10000 + 0.5)/100).." %"
-- value-expandable groups
elseif v ~= 1 or k == filter.group_with_value_1_config[k] then
mv = v
else
mv = true
end
if v ~= 0 and mk and not filter.group_hide_config[k] then
ret[mk] = mv
end
end
return ret
end,
})
filter.register_filter({
name = "type",
check_item_by_def = function(self, def)
return self.name..":"..def.type
end,
get_keyword = function(self, group)
if group.name ~= self.name then
return group.parent.childs[group.name]
end
end
})
filter.register_filter({
name = "mod",
check_item_by_def = function(self, def)
if def.mod_origin then
return self.name..":"..def.mod_origin
end
end,
get_keyword = function(self, group)
if group.name ~= self.name then
return group.parent.childs[group.name]
end
end
})
filter.register_filter({
name = "translucent",
check_item_by_def = function(self, def)
if def.sunlight_propagates ~= 0 then
return def.sunlight_propagates
end
end,
})
filter.register_filter({
name = "light",
check_item_by_def = function(self, def)
if def.light_source ~= 0 then
return def.light_source
end
end,
})
filter.register_filter({
name = "metainv",
check_item_by_def = function(self, def)
if def.allow_metadata_inventory_move or
def.allow_metadata_inventory_take or
def.allow_metadata_inventory_put or
def.on_metadata_inventory_move or
def.on_metadata_inventory_take or
def.on_metadata_inventory_put then
return true
end
end,
})
--[[ does it sense to filter them? I cannot define the human readable groups for them
filter.register_filter({
name = "drawtype",
check_item_by_def = function(self, def)
if def.drawtype ~= "normal" then
return def.drawtype
end
end,
})
]]
local shaped_groups = {}
local shaped_list = minetest.setting_get("smart_inventory_shaped_groups") or "carpet,door,fence,stair,slab,wall,micro,panel,slope"
if shaped_list then
for z in shaped_list:gmatch("[^,]+") do
shaped_groups[z] = true
end
end
filter.register_filter({
name = "shape",
check_item_by_def = function(self, def)
local door_groups
if shaped_groups["door"] then
local door_filter = filter.get("door")
door_groups = door_filter:check_item_by_def(def)
if door_groups and door_groups.door then
return true
end
end
for k, v in pairs(def.groups) do
if k ~= "door" and shaped_groups[k] then
return true
end
end
end,
})
--[[ disabled since debug.getupvalue is not usable to secure environment
filter.register_filter({
name = "food",
check_item_by_def = function(self, def)
if def.on_use then
local name,change=debug.getupvalue(def.on_use, 1)
if name~=nil and name=="hp_change" and change > 0 then
return tostring(change)
end
end
end,
})
filter.register_filter({
name = "toxic",
check_item_by_def = function(self, def)
if def.on_use then
local name,change=debug.getupvalue(def.on_use, 1)
if name~=nil and name=="hp_change" and change < 0 then
return tostring(change)
end
end
end,
})
]]
filter.register_filter({
name = "tool",
check_item_by_def = function(self, def)
if not def.tool_capabilities then
return
end
local rettab = {}
for k, v in pairs(def.tool_capabilities) do
if type(v) ~= "table" and v ~= 0 then
rettab["tool:"..k] = v
end
end
if def.tool_capabilities.damage_groups then
for k, v in pairs(def.tool_capabilities.damage_groups) do
if v ~= 0 then
rettab["damage:"..k] = v
end
end
end
--[[ disabled, I cannot find right human readable interpretation for this
if def.tool_capabilities.groupcaps then
for groupcap, gdef in pairs(def.tool_capabilities.groupcaps) do
for k, v in pairs(gdef) do
if type(v) ~= "table" then
rettab["groupcaps:"..groupcap..":"..k] = v
end
end
end
end
]]
return rettab
end,
get_keyword = function(self, group)
if group.name == "tool" or group.name == "damage" then
return nil
else
return self:_get_keyword(group)
end
end
})
filter.register_filter({
name = "armor",
check_item_by_def = function(self, def)
return def.armor_groups
end,
})
filter.register_filter({
name = 'clothing_cape',
check_item_by_def = function(self, def)
if def.groups.cape then
return 'clothing'
end
end
})
-- Burn times
filter.register_filter({
name = "fuel",
check_item_by_def = function(self, def)
local burntime = minetest.get_craft_result({method="fuel",width=1,items={def.name}}).time
if burntime > 0 then
return "fuel:"..burntime
end
end
})
-- Group assignment done in cache framework internally
filter.register_filter({
name = "recipetype",
check_item_by_def = function(self, def) end,
get_keyword = function(self, group)
if group.name ~= self.name then
return group.parent.childs[group.name]
end
end
})
-- Group assignment done in cache framework internally
filter.register_filter({
name = "ingredient",
check_item_by_def = function(self, def) end,
get_description = function(self, group)
local itemname = group.name:sub(12)
if txt and txt["ingredient"] and
minetest.registered_items[itemname] and minetest.registered_items[itemname].description then
return txt["ingredient"] .." "..minetest.registered_items[itemname].description.." ("..group.name..")"
else
return group.name
end
end,
get_keyword = function(self, group)
-- not searchable by ingedient
return nil
end,
is_valid = function(self, groupname)
local itemname = groupname:sub(12)
if itemname ~= "" and minetest.registered_items[itemname] then
return true
end
end
})
local door_groups
local function fill_door_groups()
door_groups = {}
for _, extend_def in pairs(minetest.registered_items) do
local base_def
if extend_def.groups and extend_def.groups.door then
if extend_def.door then
base_def = minetest.registered_items[extend_def.door.name]
elseif extend_def.drop and type(extend_def.drop) == "string" then
base_def = minetest.registered_items[extend_def.drop]
end
end
if base_def then
door_groups[base_def.name] = extend_def
door_groups[extend_def.name] = false
end
end
end
filter.register_filter({
name = "door",
check_item_by_def = function(self, def)
if not door_groups then
fill_door_groups()
end
if not door_groups[def.name] then
return
end
local group_filter = filter.get("group")
local ret = group_filter:check_item_by_def(door_groups[def.name])
if ret then
ret["not_in_creative_inventory"] = nil
return ret
end
end
})
----------------
return filter