mirror of
https://github.com/SmallJoker/exchange_shop.git
synced 2024-11-16 23:50:22 +01:00
[WIP] Add item picker
WARNING: Do not revert back to the previous commits after this one! Doing so will give away items for free (as players will be able to take out any items that they prevously selected with the item picker) If you want to be able to revert then maybe it'd be better to make the existing code store a copy of the item in its own inventory first (like mese tubes in pipeworks). The GUI currently uses flow because I'm lazy, if more performance is needed then I can probably convert it to a formspec.
This commit is contained in:
parent
c79c4adf39
commit
c370b8051a
2
mod.conf
2
mod.conf
|
@ -1,4 +1,4 @@
|
|||
name = exchange_shop
|
||||
description = An improved exchange shop
|
||||
depends = default
|
||||
depends = default, flow
|
||||
optional_depends = mesecons_mvps
|
||||
|
|
225
shop.lua
225
shop.lua
|
@ -9,6 +9,7 @@ local S = exchange_shop.S
|
|||
local shop_positions = {}
|
||||
|
||||
local tconcat = table.concat
|
||||
local lower = utf8.lower
|
||||
|
||||
local function get_exchange_shop_formspec(mode, pos, meta)
|
||||
local name = "nodemeta:" .. pos.x .. "," .. pos.y .. "," .. pos.z
|
||||
|
@ -70,17 +71,30 @@ local function get_exchange_shop_formspec(mode, pos, meta)
|
|||
return formspec
|
||||
end
|
||||
|
||||
local function make_slots_btns(x, y, w, h, list, label)
|
||||
local fs = {make_slots(x, y, w, h, list, label)}
|
||||
local i = 0
|
||||
for y2 = 1, h do
|
||||
for x2 = 1, w do
|
||||
i = i + 1
|
||||
fs[#fs + 1] = ("image_button[%s,%s;1.2,1.2;;%s_%s;;false;false]"):format(x + x2 - 1.1, y + y2 - 1.1, list, i)
|
||||
end
|
||||
end
|
||||
print(dump(fs))
|
||||
return tconcat(fs)
|
||||
end
|
||||
|
||||
if mode == "owner_custm" or mode == "owner_stock" then
|
||||
local overflow = not meta:get_inventory():is_empty("custm_ej")
|
||||
|
||||
-- owner
|
||||
local formspec = (
|
||||
"size[10,10]" ..
|
||||
"formspec_version[3]size[10,10]real_coordinates[false]" ..
|
||||
"item_image[0,-0.1;1,1;".. exchange_shop.shopname .. "]" ..
|
||||
"label[0.9,0.1;" .. S("Exchange Shop") .. "]" ..
|
||||
default.gui_close_btn("9.3,-0.1") ..
|
||||
make_slots(0.1, 2, 2, 2, "cust_ow", S("You need:")) ..
|
||||
make_slots(2.6, 2, 2, 2, "cust_og", S("You give:")) ..
|
||||
make_slots_btns(0.1, 2, 2, 2, "cust_ow", S("You need:")) ..
|
||||
make_slots_btns(2.6, 2, 2, 2, "cust_og", S("You give:")) ..
|
||||
"label[5,0.4;" .. S("Current stock:") .. "]"
|
||||
)
|
||||
|
||||
|
@ -140,6 +154,178 @@ local function get_exchange_shop_formspec(mode, pos, meta)
|
|||
end
|
||||
|
||||
|
||||
local function shop_valid(pos, player)
|
||||
return minetest.get_node(pos).name == exchange_shop.shopname and
|
||||
not minetest.is_protected(pos, player:get_player_name())
|
||||
end
|
||||
|
||||
-- TODO: Maybe not use flow
|
||||
local function go_back(player, ctx)
|
||||
if shop_valid(ctx.pos, player) then
|
||||
local name = player:get_player_name()
|
||||
shop_positions[name] = ctx.pos
|
||||
minetest.show_formspec(name, "exchange_shop:shop_formspec",
|
||||
get_exchange_shop_formspec("owner_custm", ctx.pos))
|
||||
end
|
||||
end
|
||||
|
||||
local items_cache = {}
|
||||
minetest.after(0, function()
|
||||
for item, def in pairs(minetest.registered_items) do
|
||||
if (not def.groups or (def.groups.not_in_creative_inventory ~= 1 and
|
||||
def.groups.stairs ~= 1)) and def.description ~= "" then
|
||||
items_cache[#items_cache + 1] = item
|
||||
end
|
||||
end
|
||||
|
||||
table.sort(items_cache)
|
||||
end)
|
||||
|
||||
local function matches_search(query, description, lang)
|
||||
return query == "" or
|
||||
lower(minetest.get_translated_string(lang, description)):find(query, 1, true)
|
||||
end
|
||||
|
||||
local gui = flow.widgets
|
||||
local item_picker = flow.make_gui(function(player, ctx)
|
||||
local rows = {name='items', w = 11.8, h = 5.8, custom_scrollbar = {
|
||||
w = 0.9,
|
||||
scrollbar_bg = "inventory_creative_scrollbar_bg.png",
|
||||
slider = "inventory_creative_slider.png",
|
||||
arrow_up = "inventory_creative_arrow_up.png",
|
||||
arrow_down = "inventory_creative_arrow_down.png",
|
||||
}}
|
||||
|
||||
local query = ctx.form.Dsearch and lower(ctx.form.Dsearch) or ""
|
||||
|
||||
-- Reset items scrollbar
|
||||
if ctx.query ~= query then
|
||||
ctx.form["_scrollbar-items"] = 0
|
||||
ctx.query = query
|
||||
end
|
||||
|
||||
local name = player:get_player_name()
|
||||
local info = minetest.get_player_information(name)
|
||||
local lang = info and info.lang_code or ""
|
||||
|
||||
local row = {}
|
||||
for _, item in ipairs(items_cache) do
|
||||
local description = minetest.registered_items[item].description
|
||||
if matches_search(query, description, lang) then
|
||||
if #row >= 10 then
|
||||
rows[#rows + 1] = gui.HBox(row)
|
||||
row = {}
|
||||
end
|
||||
row[#row + 1] = gui.ItemImageButton{
|
||||
w = 1, h = 1,
|
||||
item_name = item,
|
||||
on_event = function(p, c)
|
||||
if c.item ~= item or c.form.amount ~= "1" then
|
||||
c.item = item
|
||||
c.desc = description or item
|
||||
c.form.amount = "1"
|
||||
return true
|
||||
end
|
||||
end,
|
||||
}
|
||||
end
|
||||
end
|
||||
if #rows > 0 or #row > 0 then
|
||||
rows[#rows + 1] = gui.HBox(row)
|
||||
else
|
||||
rows[#rows + 1] = gui.Label{label = S("No items found.")}
|
||||
end
|
||||
|
||||
local item_preview
|
||||
|
||||
return gui.VBox{
|
||||
gui.HBox{
|
||||
gui.Style{selectors = {"back"}, props = {border = false}},
|
||||
gui.ItemImageButton{
|
||||
item_name = exchange_shop.shopname, w = 1, h = 1,
|
||||
on_event = go_back, name = "back",
|
||||
},
|
||||
gui.Label{label = S("Select item"), align_h = "left", expand = true},
|
||||
|
||||
-- Search box
|
||||
gui.HBox{
|
||||
align_v = "centre",
|
||||
bgimg = "inventory_search_bg9.png",
|
||||
bgimg_middle = 25,
|
||||
spacing = 0,
|
||||
gui.Spacer{expand = false, padding = 0.06},
|
||||
gui.Style{selectors = {"Dsearch"}, props = {border = false, bgcolor = "transparent"}},
|
||||
gui.Field{name = "Dsearch", w = 3, h = 0.7},
|
||||
gui.ImageButton{
|
||||
w = 0.7, h = 0.7, drawborder = false, padding = 0.05,
|
||||
texture_name = "inventory_search.png",
|
||||
},
|
||||
gui.ImageButton{
|
||||
w = 0.7, h = 0.7, drawborder = false, padding = 0.05,
|
||||
texture_name = "inventory_search_clear.png",
|
||||
on_event = function(_, c)
|
||||
if c.form.Dsearch ~= "" then
|
||||
c.form.Dsearch = ""
|
||||
return true
|
||||
end
|
||||
end
|
||||
},
|
||||
}
|
||||
},
|
||||
gui.StyleType{
|
||||
selectors = {"item_image_button"},
|
||||
props = {
|
||||
bgimg = "formspec_cell.png",
|
||||
bgimg_hovered = "formspec_cell.png^[brighten",
|
||||
border = false,
|
||||
}
|
||||
},
|
||||
gui.ScrollableVBox(rows),
|
||||
gui.HBox{
|
||||
gui.ItemImage{w = 1, h = 1, item_name = ctx.item},
|
||||
gui.Label{
|
||||
label = ctx.desc and ctx.item ~= "" and
|
||||
S("Selected item: @1", ctx.desc) or
|
||||
S("No item selected")
|
||||
},
|
||||
},
|
||||
gui.HBox{
|
||||
gui.Field{name = "amount", label = S("Amount"), default = "1"},
|
||||
gui.HBox{
|
||||
expand = true, align_h = "end", align_v = "end",
|
||||
gui.Button{
|
||||
label = S("Clear"),
|
||||
w = 3.5,
|
||||
on_event = function(p, c)
|
||||
c.item = ""
|
||||
c.form.amount = "0"
|
||||
return true
|
||||
end,
|
||||
},
|
||||
gui.Button{
|
||||
label = S("Save"),
|
||||
w = 3.5,
|
||||
on_event = function(p, c)
|
||||
if shop_valid(c.pos, p) then
|
||||
local item = ItemStack(c.item)
|
||||
local amount = tonumber(c.form.amount)
|
||||
if amount and amount == amount and amount >= 1 then
|
||||
item:set_count(math.min(amount, item:get_stack_max()))
|
||||
end
|
||||
shop_positions[name] = c.pos
|
||||
local meta = minetest.get_meta(c.pos)
|
||||
meta:get_inventory():set_stack(c.list, c.idx, item)
|
||||
minetest.show_formspec(name, "exchange_shop:shop_formspec",
|
||||
get_exchange_shop_formspec("owner_custm", c.pos, meta))
|
||||
end
|
||||
end,
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
end)
|
||||
|
||||
|
||||
minetest.register_on_player_receive_fields(function(sender, formname, fields)
|
||||
if formname ~= "exchange_shop:shop_formspec" then
|
||||
return
|
||||
|
@ -183,6 +369,23 @@ minetest.register_on_player_receive_fields(function(sender, formname, fields)
|
|||
end
|
||||
minetest.show_formspec(player_name, "exchange_shop:shop_formspec",
|
||||
get_exchange_shop_formspec(mode, pos, meta))
|
||||
else
|
||||
for field in pairs(fields) do
|
||||
local list, idx = field:match("(cust_o[wg])_([1-4])")
|
||||
if list then
|
||||
idx = tonumber(idx)
|
||||
local stack = minetest.get_meta(pos):get_inventory():get_stack(list, idx)
|
||||
item_picker:show(sender, {
|
||||
pos = pos,
|
||||
list = list,
|
||||
idx = idx,
|
||||
item = stack:get_name(),
|
||||
desc = stack:get_short_description(),
|
||||
form = {amount = stack:get_count()}
|
||||
})
|
||||
return
|
||||
end
|
||||
end
|
||||
end
|
||||
end)
|
||||
|
||||
|
@ -243,7 +446,11 @@ minetest.register_node(exchange_shop.shopname, {
|
|||
get_exchange_shop_formspec(mode, pos, meta))
|
||||
end,
|
||||
|
||||
allow_metadata_inventory_move = function(pos, _, _, _, _, count, player)
|
||||
allow_metadata_inventory_move = function(pos, from_list, to_list, _, _, count, player)
|
||||
if from_list:sub(1, 6) == "cust_o" or to_list:sub(1, 6) == "cust_o" then
|
||||
return 0
|
||||
end
|
||||
|
||||
local player_name = player:get_player_name()
|
||||
return not minetest.is_protected(pos, player_name) and count or 0
|
||||
end,
|
||||
|
@ -257,15 +464,19 @@ minetest.register_node(exchange_shop.shopname, {
|
|||
return 0
|
||||
end
|
||||
if not minetest.is_protected(pos, player_name)
|
||||
and listname ~= "custm_ej" then
|
||||
and listname ~= "custm_ej" and listname:sub(1, 6) ~= "cust_o" then
|
||||
return stack:get_count()
|
||||
end
|
||||
return 0
|
||||
end,
|
||||
|
||||
allow_metadata_inventory_take = function(pos, _, _, stack, player)
|
||||
allow_metadata_inventory_take = function(pos, listname, _, stack, player)
|
||||
local player_name = player:get_player_name()
|
||||
return not minetest.is_protected(pos, player_name) and stack:get_count() or 0
|
||||
if minetest.is_protected(pos, player_name) or
|
||||
listname:sub(1, 6) == "cust_o" then
|
||||
return 0
|
||||
end
|
||||
return stack:get_count()
|
||||
end
|
||||
})
|
||||
|
||||
|
|
Loading…
Reference in New Issue
Block a user