SX c035e3b484 Natural sorting for chests (#135)
* Natural sorting for chests

* Fix sorting of separated tools/items containing infotext, reduce overhead of original stack collector

Co-authored-by: SX <50966843+S-S-X@users.noreply.github.com>
2020-12-03 15:48:07 +02:00

256 lines
9.4 KiB
Lua

local S = rawget(_G, "intllib") and intllib.Getter() or function(s) return s end
--local S = minetest.get_translator("technic_chests")
local has_pipeworks = minetest.get_modpath("pipeworks")
local function get_pipeworks_fs(x, y, meta)
-- Use a container to reposition the pipeworks button.
return "container["..x..","..(y - 4.3).."]"..
pipeworks.fs_helpers.cycling_button(
meta,
pipeworks.button_base,
"splitstacks",
{
pipeworks.button_off,
pipeworks.button_on
}
)..pipeworks.button_label.."container_end[]"
end
local function get_color_fs(x, y, meta)
local fs = ""
for a = 0, 3 do
for b = 0, 3 do
fs = fs.."image_button["..(x + b * 0.73)..","..(y + 0.1 + a * 0.79)..";0.8,0.8;"..
"technic_colorbutton"..(a * 4 + b)..".png;color_button"..(a * 4 + b + 1)..";]"
end
end
local selected = meta:get_int("color")
local color
if technic.chests.colors[selected] then
color = technic.chests.colors[selected][2]
else
color = S("None")
end
return fs.."label["..(x + 0.1)..","..(y + 3.4)..";"..S("Selected Color: %s"):format(color).."]"
end
local function get_quickmove_fs(x, y)
return "button["..x..","..y..";3,1;existing_to_chest;"..S("Move existing to Chest").."]"..
"label["..(x + 0.1)..","..(y + 1.15)..";"..S("Move specific")..":\n("..S("Drop to move")..")]"..
"list[context;quickmove;"..(x + 1.8)..","..(y + 1.15)..";1,1]"..
"button["..x..","..(y + 2.3)..";3,1;all_to_chest;"..S("Move all to Chest").."]"..
"button["..x..","..(y + 3.2)..";3,1;all_to_inv;"..S("Move all to Inventory").."]"
end
local function get_digilines_fs(x, y, meta)
local channel = minetest.formspec_escape(meta:get_string("channel"))
local put = meta:get_int("send_put") == 1 and "true" or "false"
local take = meta:get_int("send_take") == 1 and "true" or "false"
local inject = meta:get_int("send_inject") == 1 and "true" or "false"
local pull = meta:get_int("send_pull") == 1 and "true" or "false"
local overflow = meta:get_int("send_overflow") == 1 and "true" or "false"
return "field["..(x + 0.3)..","..(y + 0.5)..";3,1;channel;Digiline Channel:;"..channel.."]"..
"button["..(x + 0.5)..","..(y + 1.1)..";2,1;save_channel;Save Channel]"..
"checkbox["..(x + 0.1)..","..(y + 1.8)..";send_put;"..S("Send player put messages")..";"..put.."]"..
"checkbox["..(x + 0.1)..","..(y + 2.2)..";send_take;"..S("Send player take messages")..";"..take.."]"..
"checkbox["..(x + 0.1)..","..(y + 2.6)..";send_inject;"..S("Send tube inject messages")..";"..inject.."]"..
"checkbox["..(x + 0.1)..","..(y + 3.0)..";send_pull;"..S("Send tube pull messages")..";"..pull.."]"..
"checkbox["..(x + 0.1)..","..(y + 3.4)..";send_overflow;"..S("Send overflow messages")..";"..overflow.."]"
end
local function get_infotext_fs(editing, meta)
local infotext = minetest.formspec_escape(meta:get_string("infotext"))
if editing then
return "image_button[0,0.1;0.8,0.8;technic_checkmark_icon.png;save_infotext;]"..
"field[1,0.3;4,1;infotext;;"..infotext.."]"
else
return "image_button[0,0.1;0.8,0.8;technic_pencil_icon.png;edit_infotext;]"..
"label[1,0;"..infotext.."]"
end
end
local function get_autosort_fs(x, meta)
if meta:get_int("autosort") == 1 then
return "button["..x..",0;2,1;autosort;"..S("Auto-sort is On").."]"
else
return "button["..x..",0;2,1;autosort;"..S("Auto-sort is Off").."]"
end
end
local function get_sort_fs(x, meta)
local mode = meta:get_int("sort_mode")
local fs = "button["..(x + 2)..",0;1,1;sort;"..S("Sort").."]"
if mode == 1 then
return fs.."button["..x..",0;2,1;sort_mode;"..S("Sort by Quantity").."]"
elseif mode == 2 then
return fs.."button["..x..",0;2,1;sort_mode;"..S("Sort by Type").."]"
elseif mode == 3 then
return fs.."button["..x..",0;2,1;sort_mode;"..S("Sort by Wear").."]"
elseif mode == 4 then
return fs.."button["..x..",0;2,1;sort_mode;"..S("Natural sort").."]"
else
return fs.."button["..x..",0;2,1;sort_mode;"..S("Sort by Item").."]"
end
end
function technic.chests.get_formspec(data)
local formspec = {}
local top_width = (data.infotext and 6 or 0) + (data.autosort and 2 or 0) + (data.sort and 3 or 0)
local bottom_width = (data.quickmove and 3 or 0) + ((data.color or data.digilines) and 3 or 0) + 8
local width = math.max(top_width, bottom_width, data.width)
local padding = (width - bottom_width) / 2
if data.quickmove and (data.color or data.digilines) then
padding = (width - bottom_width) / 4
elseif data.quickmove or data.color or data.digilines then
padding = (width - bottom_width) / 3
end
local player_inv_left = padding
if data.quickmove then
player_inv_left = padding + 3 + padding
end
local player_inv_top = data.height + (has_pipeworks and 1.6 or 1.3)
local height = data.height + (has_pipeworks and 5.4 or 5.1)
local chest_inv_left = (width - data.width) / 2
formspec.base =
"size["..width..","..height.."]"..
"list[context;main;"..chest_inv_left..",1;"..data.width..","..data.height..";]"..
"list[current_player;main;"..player_inv_left..","..player_inv_top..";8,4;]"..
"listring[context;main]"..
"listring[current_player;main]"..
default.get_hotbar_bg(player_inv_left, player_inv_top)
if data.quickmove then
formspec.base = formspec.base..get_quickmove_fs(padding, data.height + 1.2)
end
formspec.padding = padding
formspec.width = width
return formspec
end
function technic.chests.update_formspec(pos, data, edit_infotext)
local formspec = data.formspec.base
local meta = minetest.get_meta(pos)
if data.infotext then
formspec = formspec..get_infotext_fs(edit_infotext, meta)
end
if data.sort then
formspec = formspec..get_sort_fs(data.formspec.width - 3, meta)
if data.autosort then
formspec = formspec..get_autosort_fs(data.formspec.width - 5, meta)
end
end
if has_pipeworks then
local offset = data.quickmove and (data.formspec.padding * 2 + 3) or data.formspec.padding
formspec = formspec..get_pipeworks_fs(offset, data.height + 1, meta)
end
if data.color or data.digilines then
local offset = data.quickmove and (data.formspec.padding * 3 + 11) or (data.formspec.padding * 2 + 8)
if data.color then
formspec = formspec..get_color_fs(offset, data.height + 1.2, meta)
else
formspec = formspec..get_digilines_fs(offset, data.height + 1.2, meta)
end
end
meta:set_string("formspec", formspec)
end
function technic.chests.get_receive_fields(data)
return function(pos, formname, fields, player)
if not fields or not player then
return
end
local meta = minetest.get_meta(pos)
local chest_inv = meta:get_inventory()
local player_inv = player:get_inventory()
if fields.quit then
if meta:get_int("autosort") == 1 then
technic.chests.sort_inv(chest_inv, meta:get_int("sort_mode"))
end
technic.chests.update_formspec(pos, data)
return
end
if not technic.chests.change_allowed(pos, player, data.locked, data.protected) then
return
end
if data.sort and fields.sort then
technic.chests.sort_inv(chest_inv, meta:get_int("sort_mode"))
return
end
if data.quickmove then
if fields.all_to_chest then
local moved_items = technic.chests.move_inv(player_inv, chest_inv)
if data.digilines and meta:get_int("send_put") == 1 then
technic.chests.send_digiline_message(pos, "put", player, moved_items)
end
technic.chests.log_inv_change(pos, player:get_player_name(), "put", "stuff")
return
elseif fields.all_to_inv then
local moved_items = technic.chests.move_inv(chest_inv, player_inv)
if data.digilines and meta:get_int("send_take") == 1 then
technic.chests.send_digiline_message(pos, "take", player, moved_items)
end
technic.chests.log_inv_change(pos, player:get_player_name(), "take", "stuff")
return
elseif fields.existing_to_chest then
local items = technic.chests.get_inv_items(chest_inv)
local moved_items = technic.chests.move_inv(player_inv, chest_inv, items)
if data.digilines and meta:get_int("send_put") == 1 then
technic.chests.send_digiline_message(pos, "put", player, moved_items)
end
technic.chests.log_inv_change(pos, player:get_player_name(), "put", "stuff")
return
end
end
if not technic.chests.change_allowed(pos, player, data.locked, true) then
return -- Protect settings from being changed, even for open chests
end
if has_pipeworks then
pipeworks.fs_helpers.on_receive_fields(pos, fields)
end
if data.sort and fields.sort_mode then
local value = meta:get_int("sort_mode")
meta:set_int("sort_mode", (value + 1) % 5)
end
if data.autosort and fields.autosort then
local value = meta:get_int("autosort") == 1 and 0 or 1
meta:set_int("autosort", value)
end
if data.color then
for i = 1, 16 do
if fields["color_button"..i] then
local node = minetest.get_node(pos)
if technic.chests.colors[i] then
node.name = data.node_name.."_"..technic.chests.colors[i][1]
else
node.name = data.node_name
end
minetest.swap_node(pos, node)
meta:set_int("color", i)
break
end
end
end
if data.digilines then
if fields.save_channel and fields.channel then
meta:set_string("channel", fields.channel)
end
for _,setting in pairs({"send_put", "send_take", "send_inject", "send_pull", "send_overflow"}) do
if fields[setting] then
local value = fields[setting] == "true" and 1 or 0
meta:set_int(setting, value)
end
end
end
if data.infotext then
if fields.edit_infotext then
technic.chests.update_formspec(pos, data, true)
return
elseif fields.save_infotext and fields.infotext then
meta:set_string("infotext", fields.infotext)
end
end
technic.chests.update_formspec(pos, data)
end
end