lua_inv/formspec_elements/dynamic_list.lua

222 lines
7.1 KiB
Lua

--[[
Complete and Total Lua-Only Inventory Rewrite
Copyright (C) 2021 Noodlemire
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 2.1 of the License, or (at your option) any later version.
This library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public
License along with this library; if not, write to the Free Software
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
--]]
function lua_inv.button_field_to_context(field)
local splits = field:split("__")
local il = splits[2]
if il ~= "context" and il ~= "current_player" then
local il_splits = il:split('_', false, 1)
if il_splits[1] == "nodemeta" then
local pos = il_splits[2]:split('_')
il = {k = "nodemeta", v = {tonumber(pos[1]), tonumber(pos[2]), tonumber(pos[3])}}
else
il = {type = il_splits[1], name = il_splits[2]}
end
end
return {
inv_location = il,
listname = splits[3],
index = splits[4],
}
end
function lua_inv.inventory_from_location(inv_location, player)
local inv = lua_inv.player_inventory[player:get_player_name()].inv
if inv_location == "current_player" and player then
inv = lua_inv.player_inventory[player:get_player_name()].inv
elseif type(inv_location) == "table" then
if inv_location.k == "player" then
if not lua_inv.player_inventory[inv_location.v] then
error("Error: Attempt to find the inventory of a non-existant player named \""..inv_location.v.."\"")
end
inv = lua_inv.player_inventory[inv_location.v].inv
elseif inv_location.k == "nodemeta" then
inv = lua_inv.fetch_node_inventory({
x = tonumber(inv_location.v[1]),
y = tonumber(inv_location.v[2]),
z = tonumber(inv_location.v[3])
})
elseif location.k == "detached" then
inv = lua_inv.get_detached_inventory[inv_location.v]
if not inv then
error("Error: Attempt to find non-existant inventory location \"detached:"..inv_lovation.v.."\"")
end
else
inv = nil
end
end
if not inv then
error("Error: Attempt to create unknown inventory type: "..dump(inv_location))
end
return inv
end
function lua_inv.dynamic_list(in_inv_location, in_listname, in_x, in_y, in_w, in_h, in_start_i)
return lua_inv.formspec_element(
"dynamic_list",
{
in_inv_location,
in_listname,
{in_x, in_y},
{in_w, in_h},
in_start_i,
},
function(self, player, formname, fields)
local meta, temp_meta = lua_inv.get_df_meta(player)
if not meta then
minetest.log("warning", "Warning: Attempt to form a closed formspec.")
return ""
end
if fields and not temp_meta:contains("dynamic_list_flag") then
temp_meta:set_string("dynamic_list_flag", "true")
for field in pairs(fields) do
if field:sub(1, 15) == "lua_inv_button_" then
if meta:contains("selection") then
if field == meta:get_string("selection") then
meta:remove("selection")
else
local stack_mode = meta:get("stack_mode") or "lua_inv_stack_mode_all"
local context_1 = lua_inv.button_field_to_context(meta:get_string("selection"))
local context_2 = lua_inv.button_field_to_context(field)
local inv_1 = lua_inv.inventory_from_location(context_1.inv_location, player)
local inv_2 = lua_inv.inventory_from_location(context_2.inv_location, player)
local stack_1 = inv_1:get_stack(context_1.listname, context_1.index)
local stack_2 = inv_2:get_stack(context_2.listname, context_2.index)
if stack_mode == "lua_inv_stack_mode_all" or stack_1:get_count() <= 1 then
if stack_1:is_similar(stack_2) and not (stack_1:is_full() or stack_2:is_full()) then
stack_2 = stack_2 + stack_1
else
inv_1:set_stack(context_1.listname, context_1.index, stack_2)
end
elseif stack_mode == "lua_inv_stack_mode_half" then
if stack_1:peek_item(math.ceil(stack_1:get_count()/2)):item_fits(stack_2) then
local half_stack = stack_1:take_item(math.ceil(stack_1:get_count()/2))
stack_2 = stack_2 + half_stack
stack_1 = stack_1 + half_stack
end
else
if stack_1:peek_item():item_fits(stack_2) then
local single_stack = stack_1:take_item(1)
stack_2 = stack_2 + single_stack
stack_1 = stack_1 + single_stack
end
end
if stack_1:is_empty() then
meta:remove("selection")
end
end
else
local con = lua_inv.button_field_to_context(field)
if not lua_inv.inventory_from_location(con.inv_location, player):get_stack(con.listname, con.index):is_empty() then
meta:set_string("selection", field)
end
end
break
end
end
end
local str = ""
local inv_location = self.args[1]
local listname = self.args[2]
local pos = self.args[3]
local size = self.args[4]
local start_i = (tonumber(self.args[5]) or 0)
local inv = lua_inv.inventory_from_location(inv_location, player)
for x = 1, size[1] do
for y = 1, size[2] do
local ind = start_i + x + (y - 1) * size[1]
local stack = inv:get_stack(listname, ind)
local slotname = '_'..listname.."__"..ind
if type(inv_location) == "table" then
if type(inv_location.v) == "table" then
slotname = '_'..inv_location.k..'_'..inv_location.v[1]..'_'..inv_location.v[2]..'_'..
inv_location.v[3]..'_'..slotname
else
slotname = '_'..inv_location.k..'_'..inv_location.v..'_'..slotname
end
else
slotname = '_'..inv_location..'_'..slotname
end
slotname = "lua_inv_button_"..slotname
str = str.."image_button["..(pos[1] + x - 1)..','..(pos[2] + y - 1)..";1,1;;"..slotname..";]"
if stack and not stack:is_empty() then
str = str.."tooltip["..slotname..';'..stack:get_description()..']'
local anim = stack:get_animation()
if anim then
str = str.."animated_image["..(pos[1] + x - 1)..','..(pos[2] + y - 1)..";1,1;"..stack:get_name()..";"
..stack:get_inventory_image()..";"..anim.frames..";"..anim.speed..";]"
elseif not stack:get_inventory_image(true) then
str = str.."item_image["..(pos[1] + x - 1)..','..(pos[2] + y - 1)..";1,1;"..stack:get_name().."]"
else
str = str.."image["..(pos[1] + x - 1)..','..(pos[2] + y - 1)..";1,1;"..stack:get_inventory_image()..']'
end
if stack:get_count() > 1 then
str = str.."label["..(pos[1] + x - 0.4)..','..(pos[2] + y - 0.5)..';'..stack:get_count()..']'
end
if stack:get_wear() > 0 then
str = str.."image["..(pos[1] + x - 0.95)..','..(pos[2] + y - 1.0625)..";0.875,1;"..stack:get_wear_visual()..']'
end
end
if meta:get_string("selection") == slotname then
str = str.."image["..(pos[1] + x - 1.0456)..','..(pos[2] + y - 1.0456)..";1.111,1.111;lua_inv_selected.png]"
end
end
end
return str
end
)
end