3 local S
= minetest
.get_translator("select_item")
5 -- Cache for result of item filters
6 local player_filters
= {}
7 local player_filter_results
= {}
8 local player_compares
= {}
9 local player_maxpage
= {}
11 local reset_player_info
= function(playername
)
12 player_filters
[playername
] = nil
13 player_filter_results
[playername
] = nil
14 player_compares
[playername
] = nil
15 player_maxpage
[playername
] = nil
19 select_item
.filters
= {}
21 -- Filters out all items not for the Creative Inventory.
22 -- This elimininates all items reserved for internal use.
23 select_item
.filters
.creative
= function(itemstring
)
24 local itemdef
= minetest
.registered_items
[itemstring
]
25 if itemstring
== "air" then
28 if itemdef
.description
== nil or itemdef
.description
== "" then
31 if minetest
.get_item_group(itemstring
, "not_in_creative_inventory") == 1 then
38 select_item
.filters
.all
= function()
42 local check_item
= function(itemstring
, filter
)
43 local itemdef
= minetest
.registered_items
[itemstring
]
44 if itemstring
== "" or itemstring
== "unknown" or itemstring
== "ignore" or itemdef
== nil then
47 if type(filter
) == "function" then
48 if filter(itemstring
) ~= true then
56 local get_items
= function(filter
, compare
)
58 for itemstring
, itemdef
in pairs(minetest
.registered_items
) do
59 if check_item(itemstring
, filter
) then
60 table.insert(it
, {itemstring
=itemstring
, itemdef
=itemdef
})
63 local internal_compare
65 -- Default sorting: Move description-less items and
66 -- items not_in_creative_inventory=1 to the end, then sort by itemstring.
67 internal_compare
= function(t1
, t2
)
68 local t1d
= minetest
.registered_items
[t1
.itemstring
].description
69 local t2d
= minetest
.registered_items
[t2
.itemstring
].description
70 local t1g
= minetest
.get_item_group(t1
.itemstring
, "not_in_creative_inventory")
71 local t2g
= minetest
.get_item_group(t2
.itemstring
, "not_in_creative_inventory")
72 if (t1d
== "" and t2d
~= "") then
74 elseif (t1d
~= "" and t2d
== "") then
77 if (t1g
== 1 and t2g
== 0) then
79 elseif (t1g
== 0 and t2g
== 1) then
82 return t1
.itemstring
< t2
.itemstring
85 internal_compare
= function(t1
, t2
)
86 return compare(t1
.itemstring
, t2
.itemstring
)
89 table.sort(it
, internal_compare
)
96 -- Opens the item selection dialog for player with the given filter function at page.
97 -- The dialog has unique identifier dialogname.
98 -- Returns: Number of items it displays.
99 local show_dialog_page
= function(playername
, dialogname
, filter
, compare
, page
)
101 if player_filters
[playername
] == nil then
102 player_filters
[playername
] = filter
103 player_compares
[playername
] = compare
104 items
= get_items(filter
, compare
)
105 player_filter_results
[playername
] = items
107 items
= player_filter_results
[playername
]
108 local xsize
, ysize
, total_pages
109 if #items
< xsize_norm
* ysize_norm
then
111 ysize
= math
.ceil(#items
/ xsize
)
116 total_pages
= math
.ceil(#items
/ (xsize
* ysize
))
119 -- Legacy default formspec background (MT<=0.4.17)
120 if minetest
.get_modpath("default") and default
.gui_bg
then
121 bg
= default
.gui_bg
.. default
.gui_bg_img
.. default
.gui_slots
124 local form
= "size[6,2]"..
126 "label[0,0;"..minetest
.formspec_escape(S("There are no items to choose from.")).."]"..
127 "button_exit[0,1;2,1;cancel;"..minetest
.formspec_escape(S("There are no items to choose from.")).."]"
128 minetest
.show_formspec(playername
, "select_item:page1", form
)
131 local form
= "size["..xsize
..","..(ysize
+1).."]" .. bg
134 if page
== nil then page
= 1 end
135 local start
= 1 + (page
-1) * xsize
* ysize
136 player_maxpage
[playername
] = total_pages
137 form
= form
.. "label[0,0;"..minetest
.formspec_escape(S("Select an item:")).."]"
138 for i
=start
, #items
do
139 local itemstring
= items
[i
].itemstring
140 local itemdef
= items
[i
].itemdef
141 local name
= "item_"..itemstring
142 form
= form
.. "item_image_button["..x
..","..y
..";1,1;"..itemstring
..";"..name
..";]"
143 if itemdef
.description
== nil or itemdef
.description
== "" then
144 form
= form
.. "tooltip["..name
..";"..itemstring
.."]"
156 local ynav
= (ysize
+ 0.5)
157 if total_pages
> 1 then
158 form
= form
.. "button[0,"..ynav
..";1,1;previous;<]"
159 form
= form
.. "button[1,"..ynav
..";1,1;next;>]"
160 form
= form
.. "label[2,"..ynav
..";"..minetest
.formspec_escape(S("Page @1/@2", page
, total_pages
)).."]"
162 form
= form
.. "button_exit["..(xsize
-2)..","..ynav
..";2,1;cancel;"..minetest
.formspec_escape(S("Cancel")).."]"
163 minetest
.show_formspec(playername
, "select_item:page"..page
.."%%"..dialogname
, form
)
167 select_item
.show_dialog
= function(playername
, dialogname
, filter
, compare
)
168 show_dialog_page(playername
, dialogname
, filter
, compare
, 1)
172 select_item
.register_on_select_item
= function(callback
)
173 table.insert(callbacks
, callback
)
176 minetest
.register_on_player_receive_fields(function(player
, formname
, fields
)
177 local playername
= player
:get_player_name()
178 if string.sub(formname
, 1, 16) == "select_item:page" then
180 local rest
= string.sub(formname
, 17, string.len(formname
))
181 local split
= string.split(rest
, "%%", true, 2)
182 local page
= tonumber(split
[1])
183 local dialogname
= split
[2]
186 for field
,_
in pairs(fields
) do
187 if string.sub(field
, 1, 5) == "item_" then
188 item
= string.sub(field
, 6, string.len(field
))
192 if item
or fields
.quit
then
194 for i
=1,#callbacks
do
195 local ret
= callbacks
[i
](playername
, dialogname
, item
)
201 minetest
.close_formspec(playername
, formname
)
203 reset_player_info(playername
)
205 if fields
.quit
or fields
.cancel
then
206 reset_player_info(playername
)
209 if fields
.previous
and page
> 1 then
210 show_dialog_page(player
:get_player_name(), dialogname
, player_filters
[playername
], player_compares
[playername
], page
- 1)
211 elseif fields
.next then
212 local maxpage
= player_maxpage
[playername
]
213 if maxpage
and (page
+ 1 <= maxpage
) then
214 show_dialog_page(playername
, dialogname
, player_filters
[playername
], player_compares
[playername
], page
+ 1)
217 minetest
.log("warning", "[select_item] Player "..playername
.." managed to navigate select_item menu without maxpage set!")
224 minetest
.register_on_leaveplayer(function(player
)
225 reset_player_info(player
:get_player_name())