Add custom compare feature
This commit is contained in:
parent
b25a14188a
commit
87eb35a0ab
13
API.md
13
API.md
@ -7,7 +7,7 @@ to check for the mod's existence first (`minetest.get_modpath`
|
||||
returns non-`nil` value).
|
||||
|
||||
## Functions
|
||||
### `select_item.show_dialog(playername, dialogname, filter)`
|
||||
### `select_item.show_dialog(playername, dialogname, filter, compare)`
|
||||
Shows an item selection dialog to a player. The player can choose
|
||||
one item (which triggers a callback) or abort selection
|
||||
(in which case nothing happens).
|
||||
@ -21,13 +21,20 @@ to filter out unwanted items.
|
||||
#### Parameters
|
||||
* `playername`: Name of player to show dialog to
|
||||
* `dialogname`: Identifier of the dialog (must not contain “%%”)
|
||||
* `filter`: Optional filter function to narrow down the visible
|
||||
items (see below)
|
||||
* `filter`: (optional) Filter function to narrow down the visible
|
||||
items (see below)
|
||||
* `compare`: (optional) Custom compare function for sorting,
|
||||
used in `table.sort`.
|
||||
|
||||
Recommended form of `dialogname` is “`<modname>:<name>`”. Almost all
|
||||
names are allowed, but they must never contain the substring “%%”.
|
||||
Example: `example:select_my_item`
|
||||
|
||||
Default sorting sorts items alphabetically by itemstring. It
|
||||
moves items with empty description to the end, preceded by items
|
||||
with description, but `not_in_creative_inventory=1`, and then
|
||||
everything else to the beginning.
|
||||
|
||||
#### Filter function
|
||||
The filter function has the function signature `filter(itemstring)`.
|
||||
This function will be called for each item with the itemstring
|
||||
|
58
init.lua
58
init.lua
@ -3,11 +3,13 @@ select_item = {}
|
||||
-- Cache for result of item filters
|
||||
local player_filters = {}
|
||||
local player_filter_results = {}
|
||||
local player_compares = {}
|
||||
local player_maxpage = {}
|
||||
|
||||
local reset_player_info = function(playername)
|
||||
player_filters[playername] = nil
|
||||
player_filter_results[playername] = nil
|
||||
player_compares[playername] = nil
|
||||
player_maxpage[playername] = nil
|
||||
end
|
||||
|
||||
@ -49,33 +51,40 @@ local check_item = function(itemstring, filter)
|
||||
return true
|
||||
end
|
||||
|
||||
local get_items = function(filter)
|
||||
local get_items = function(filter, compare)
|
||||
local it = {}
|
||||
for itemstring, itemdef in pairs(minetest.registered_items) do
|
||||
if check_item(itemstring, filter) then
|
||||
table.insert(it, {itemstring=itemstring, itemdef=itemdef})
|
||||
end
|
||||
end
|
||||
-- Default sorting: Move description-less items and
|
||||
-- items not_in_creative_inventory=1 to the end, then sort by itemstring.
|
||||
local compare = function(t1, t2)
|
||||
local t1d = minetest.registered_items[t1.itemstring].description
|
||||
local t2d = minetest.registered_items[t2.itemstring].description
|
||||
local t1g = minetest.get_item_group(t1.itemstring, "not_in_creative_inventory")
|
||||
local t2g = minetest.get_item_group(t2.itemstring, "not_in_creative_inventory")
|
||||
if (t1d == "" and t2d ~= "") then
|
||||
return false
|
||||
elseif (t1d ~= "" and t2d == "") then
|
||||
return true
|
||||
local internal_compare
|
||||
if not compare then
|
||||
-- Default sorting: Move description-less items and
|
||||
-- items not_in_creative_inventory=1 to the end, then sort by itemstring.
|
||||
internal_compare = function(t1, t2)
|
||||
local t1d = minetest.registered_items[t1.itemstring].description
|
||||
local t2d = minetest.registered_items[t2.itemstring].description
|
||||
local t1g = minetest.get_item_group(t1.itemstring, "not_in_creative_inventory")
|
||||
local t2g = minetest.get_item_group(t2.itemstring, "not_in_creative_inventory")
|
||||
if (t1d == "" and t2d ~= "") then
|
||||
return false
|
||||
elseif (t1d ~= "" and t2d == "") then
|
||||
return true
|
||||
end
|
||||
if (t1g == 1 and t2g == 0) then
|
||||
return false
|
||||
elseif (t1g == 0 and t2g == 1) then
|
||||
return true
|
||||
end
|
||||
return t1.itemstring < t2.itemstring
|
||||
end
|
||||
if (t1g == 1 and t2g == 0) then
|
||||
return false
|
||||
elseif (t1g == 0 and t2g == 1) then
|
||||
return true
|
||||
else
|
||||
internal_compare = function(t1, t2)
|
||||
return compare(t1.itemstring, t2.itemstring)
|
||||
end
|
||||
return t1.itemstring < t2.itemstring
|
||||
end
|
||||
table.sort(it, compare)
|
||||
table.sort(it, internal_compare)
|
||||
return it
|
||||
end
|
||||
|
||||
@ -85,11 +94,12 @@ local ysize_norm = 9
|
||||
-- Opens the item selection dialog for player with the given filter function at page.
|
||||
-- The dialog has unique identifier dialogname.
|
||||
-- Returns: Number of items it displays.
|
||||
local show_dialog_page = function(playername, dialogname, filter, page)
|
||||
local show_dialog_page = function(playername, dialogname, filter, compare, page)
|
||||
local items
|
||||
if player_filters[playername] == nil then
|
||||
player_filters[playername] = filter
|
||||
items = get_items(filter)
|
||||
player_compares[playername] = compare
|
||||
items = get_items(filter, compare)
|
||||
player_filter_results[playername] = items
|
||||
end
|
||||
items = player_filter_results[playername]
|
||||
@ -151,8 +161,8 @@ local show_dialog_page = function(playername, dialogname, filter, page)
|
||||
return #items
|
||||
end
|
||||
|
||||
select_item.show_dialog = function(playername, dialogname, filter)
|
||||
show_dialog_page(playername, dialogname, filter, 1)
|
||||
select_item.show_dialog = function(playername, dialogname, filter, compare)
|
||||
show_dialog_page(playername, dialogname, filter, compare, 1)
|
||||
end
|
||||
|
||||
local callbacks = {}
|
||||
@ -194,11 +204,11 @@ minetest.register_on_player_receive_fields(function(player, formname, fields)
|
||||
end
|
||||
if page ~= nil then
|
||||
if fields.previous and page > 1 then
|
||||
show_dialog_page(player:get_player_name(), dialogname, player_filters[playername], page - 1)
|
||||
show_dialog_page(player:get_player_name(), dialogname, player_filters[playername], player_compares[playername], page - 1)
|
||||
elseif fields.next then
|
||||
local maxpage = player_maxpage[playername]
|
||||
if maxpage and (page + 1 <= maxpage) then
|
||||
show_dialog_page(playername, dialogname, player_filters[playername], page + 1)
|
||||
show_dialog_page(playername, dialogname, player_filters[playername], player_compares[playername], page + 1)
|
||||
end
|
||||
if not maxpage then
|
||||
minetest.log("warning", "[select_item] Player "..playername.." managed to navigate select_item menu without maxpage set!")
|
||||
|
Loading…
x
Reference in New Issue
Block a user