305 lines
9.3 KiB
Lua
305 lines
9.3 KiB
Lua
-- TODO: aliases?
|
|
|
|
local custom_crafts = {}
|
|
|
|
local function get_drops(item, def)
|
|
local normalDrops = {}
|
|
local randomDrops = {}
|
|
|
|
if type(def.drop) == "table" then
|
|
-- Handle complex drops. This is the method used by Unified Inventory.
|
|
local maxStart = true
|
|
local itemsLeft = def.drop.max_items
|
|
local dropTables = def.drop.items or {}
|
|
|
|
local dStack, dName, dCount
|
|
|
|
for _, dropTable in ipairs(dropTables) do
|
|
if itemsLeft and itemsLeft <= 0 then
|
|
break
|
|
end
|
|
|
|
for _, dropItem in ipairs(dropTable.items) do
|
|
dStack = ItemStack(dropItem)
|
|
dName = dStack:get_name()
|
|
dCount = dStack:get_count()
|
|
|
|
if dCount > 0 and dName ~= item then
|
|
if #dropTable.items == 1 and dropTable.rarity == 1
|
|
and maxStart then
|
|
normalDrops[dName] = (normalDrops[dName] or 0) + dCount
|
|
|
|
if itemsLeft then
|
|
itemsLeft = itemsLeft - 1
|
|
if itemsLeft <= 0 then
|
|
break
|
|
end
|
|
end
|
|
else
|
|
if itemsLeft then
|
|
maxStart = false
|
|
end
|
|
|
|
randomDrops[dName] = (randomDrops[dName] or 0) + dCount
|
|
end
|
|
end
|
|
end
|
|
end
|
|
else
|
|
-- Handle simple, one-item drops.
|
|
local dStack = ItemStack(def.drop)
|
|
|
|
if not dStack:is_empty() and dStack:get_name() ~= item then
|
|
normalDrops[dStack:get_name()] = dStack:get_count()
|
|
end
|
|
end
|
|
|
|
return normalDrops, randomDrops
|
|
end
|
|
|
|
local function build_group_stereotypes_list()
|
|
-- Remember: Some group stereotypes are already registered
|
|
local startTime = minetest.get_us_time()
|
|
local usedMultiGroups = {}
|
|
|
|
for _, recipes in pairs(cg.crafts) do
|
|
for _, recipe in ipairs(recipes) do
|
|
for _, item in ipairs(recipe.items) do
|
|
if item:sub(1, 6) == "group:" then
|
|
local groupsString = item:sub(7)
|
|
local groupsTable = groupsString:split(",")
|
|
if #groupsTable > 1 then
|
|
usedMultiGroups[groupsString] = groupsTable
|
|
end
|
|
end
|
|
end
|
|
end
|
|
end
|
|
|
|
for _, item in ipairs(cg.items_all.list) do
|
|
local groups = minetest.registered_items[item].groups
|
|
|
|
for group, _ in pairs(groups) do
|
|
if cg.group_stereotypes[group] == nil then
|
|
cg.group_stereotypes[group] = item
|
|
end
|
|
end
|
|
|
|
for clusterString, clusterTable in pairs(usedMultiGroups) do
|
|
if cg.group_stereotypes[clusterString] == nil then
|
|
local match = true
|
|
for _, group in ipairs(clusterTable) do
|
|
if not groups[group] then
|
|
match = false
|
|
break
|
|
end
|
|
end
|
|
if match then
|
|
cg.group_stereotypes[clusterString] = item
|
|
end
|
|
end
|
|
end
|
|
end
|
|
|
|
minetest.log("info", string.format("[cg_plus] Finished building group stereotype list in %.3f s.",
|
|
(minetest.get_us_time() - startTime) / 1000000))
|
|
end
|
|
|
|
function cg.build_item_list()
|
|
local startTime = minetest.get_us_time()
|
|
cg.items_all.list = {}
|
|
|
|
for item, def in pairs(minetest.registered_items) do
|
|
if def.description and def.description ~= ""
|
|
and minetest.get_item_group(item, "not_in_creative_inventory") == 0
|
|
and minetest.get_item_group(item, "not_in_craft_guide") == 0 then
|
|
table.insert(cg.items_all.list, item)
|
|
cg.crafts[item] = minetest.get_all_craft_recipes(item) or {}
|
|
table.insert_all(cg.crafts[item], custom_crafts[item] or {})
|
|
end
|
|
end
|
|
|
|
local def, fuel, decremented
|
|
|
|
for _, item in ipairs(cg.items_all.list) do
|
|
def = minetest.registered_items[item]
|
|
|
|
fuel, decremented = minetest.get_craft_result({
|
|
method = "fuel",
|
|
width = 0,
|
|
items = {ItemStack(item)}
|
|
})
|
|
|
|
if fuel.time > 0 then
|
|
table.insert(cg.crafts[item], {
|
|
method = "fuel",
|
|
items = {item},
|
|
output = decremented.items[1]:to_string(),
|
|
time = fuel.time,
|
|
})
|
|
end
|
|
|
|
if def.drop then
|
|
local normalDrops, randomDrops = get_drops(item, def)
|
|
|
|
for dItem, dCount in pairs(normalDrops) do
|
|
if cg.crafts[dItem] then
|
|
table.insert(cg.crafts[dItem], {
|
|
method = "digging",
|
|
width = 0,
|
|
items = {item},
|
|
output = ItemStack({
|
|
name = dItem,
|
|
count = dCount
|
|
}):to_string()
|
|
})
|
|
end
|
|
end
|
|
|
|
for dItem, dCount in pairs(randomDrops) do
|
|
if cg.crafts[dItem] then
|
|
table.insert(cg.crafts[dItem], {
|
|
method = "digging_chance",
|
|
width = 0,
|
|
items = {item},
|
|
output = ItemStack({
|
|
name = dItem,
|
|
count = dCount
|
|
}):to_string()
|
|
})
|
|
end
|
|
end
|
|
end
|
|
end
|
|
|
|
table.sort(cg.items_all.list)
|
|
cg.items_all.num_pages = math.ceil(#cg.items_all.list / cg.PAGE_ITEMS)
|
|
|
|
minetest.log("info",
|
|
string.format(
|
|
"[cg_plus] Finished building item list in %.3f s.",
|
|
(minetest.get_us_time() - startTime) / 1000000
|
|
)
|
|
)
|
|
|
|
build_group_stereotypes_list()
|
|
end
|
|
|
|
function cg.filter_items(player, filter)
|
|
local playerName = player:get_player_name()
|
|
local playerData = cg.player_data[playerName]
|
|
|
|
if not filter or filter == "" then
|
|
playerData.items = nil
|
|
return
|
|
end
|
|
|
|
playerData.items = {list = {}}
|
|
|
|
filter = filter:lower()
|
|
local groupFilter = string.sub(filter, 1, 6) == "group:" and filter:sub(7)
|
|
|
|
if groupFilter and cg.GROUP_SEARCH then
|
|
-- Search by group
|
|
local groups = string.split(groupFilter, ",")
|
|
local isInGroups
|
|
|
|
for _, item in ipairs(cg.items_all.list) do
|
|
isInGroups = true
|
|
|
|
for idx = 1, math.min(#groups, cg.GROUP_SEARCH_MAX) do
|
|
if minetest.get_item_group(item, groups[idx]) == 0 then
|
|
isInGroups = false
|
|
break
|
|
end
|
|
end
|
|
|
|
if isInGroups then
|
|
table.insert(playerData.items.list, item)
|
|
end
|
|
end
|
|
else
|
|
-- Regular search
|
|
local langCode = playerData.lang_code
|
|
|
|
for _, item in ipairs(cg.items_all.list) do
|
|
if item:lower():find(filter, 1, true)
|
|
or minetest.get_translated_string(langCode,
|
|
minetest.registered_items[item].description)
|
|
:lower():find(filter, 1, true) then
|
|
table.insert(playerData.items.list, item)
|
|
end
|
|
end
|
|
end
|
|
|
|
playerData.items.num_pages =
|
|
math.ceil(#cg.get_item_list(player).list / cg.PAGE_ITEMS)
|
|
end
|
|
|
|
function cg.parse_craft(craft)
|
|
local method
|
|
if craft.method == "normal" and craft.width == 0 then -- Special rules for shapeless recipes
|
|
method = "shapeless"
|
|
else
|
|
method = craft.method
|
|
end
|
|
|
|
local template = cg.craft_methods[method] or {}
|
|
|
|
local gridSize = (template.get_grid_size and template.get_grid_size(craft)) or {x = 3, y = 3}
|
|
local width = craft.width or 0
|
|
local items = {}
|
|
|
|
if width == 0 then
|
|
-- Shapeless recipes
|
|
items = craft.items
|
|
else
|
|
-- The craft's width is not always the same as the grid size, so items need to be shifted around.
|
|
for i, item in pairs(craft.items) do
|
|
items[i + (gridSize.x - width) * math.floor((i - 1) / width)] = item
|
|
end
|
|
end
|
|
|
|
return {
|
|
method = method,
|
|
infotext = (template.get_infotext and template.get_infotext(craft)) or "",
|
|
grid_size = gridSize,
|
|
width = width,
|
|
items = items,
|
|
output = craft.output or "",
|
|
}
|
|
end
|
|
|
|
function cg.get_item_list(player)
|
|
return cg.player_data[player:get_player_name()].items or cg.items_all
|
|
end
|
|
|
|
function cg.register_crafting_method(name, def)
|
|
cg.craft_methods[name] = def
|
|
end
|
|
|
|
function cg.register_craft(recipe, assign_to)
|
|
local item = ItemStack(assign_to or recipe.output):get_name() -- Removes quantity, etc. from itemstring
|
|
custom_crafts[item] = custom_crafts[item] or {}
|
|
table.insert(custom_crafts[item], recipe)
|
|
end
|
|
|
|
function cg.register_group_stereotype(group, item)
|
|
cg.group_stereotypes[group] = item
|
|
end
|
|
|
|
minetest.register_on_mods_loaded(cg.build_item_list)
|
|
|
|
minetest.register_on_joinplayer(function(player)
|
|
local playerName = player:get_player_name()
|
|
local langCode = minetest.get_player_information(playerName).lang_code
|
|
|
|
cg.player_data[playerName] = {
|
|
lang_code = langCode
|
|
}
|
|
end)
|
|
|
|
minetest.register_on_leaveplayer(function(player, timed_out)
|
|
cg.player_data[player:get_player_name()] = nil
|
|
end)
|