emeraldbank/shop.lua
Freeman d5117240db fix crash causes by take an item from shop to inv
el crash se causa si el item que retiras de la tienda se coloca sobre
otro item que este en tu inventario

este crash no retorna nada en en log

parece un crash de cliente
2023-03-12 15:58:38 +01:00

352 lines
12 KiB
Lua

-- Copyright (C) 2021, 2022 Ale
-- This file is part of Emeraldbank Minetest Mod.
-- Emeraldbank is free software: you can redistribute it and/or modify
-- it under the terms of the GNU Affero General Public License as
-- published by the Free Software Foundation, either version 3 of the
-- License, or (at your option) any later version.
-- Emeraldbank 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 Affero General Public License for more details.
-- You should have received a copy of the GNU Affero General Public License
-- along with Emeraldbank. If not, see <https://www.gnu.org/licenses/>.
local S = core.get_translator(core.get_current_modname())
local shopcraft = core.settings:get_bool("emeraldbank.shop_craft") or true
-- privilege
core.register_privilege("admin_shop", {
description = "Permission to edit others shops",
give_to_singleplayer = false,
})
local shop_timer = 5
local stock_h = 3
local stock_w = 5
local formspec_prefix = "emeraldbank:shop_formspec"
emeraldbank.player_inv =
"list[current_player;main;0,4.5;9,3;9]"..
mcl_formspec.get_itemslot_bg(0,4.5,9,3)..
"list[current_player;main;0,7.74;9,1;]"..
mcl_formspec.get_itemslot_bg(0,7.74,9,1)..
"listring[current_player;main]"
function emeraldbank.get_shop_fs(pos, clicker)
local meta = core.get_meta(pos)
local count = meta:get_int("count")
local price = meta:get_int("price")
local shop_item = meta:get_string("shop_item")
local list_name = "nodemeta:"..pos.x..','..pos.y..','..pos.z
local pname = clicker:get_player_name()
local owner = meta:get_string("owner")
local player_press_key = clicker:get_player_control().aux1
local shop_fs = ""
local is_admin = core.check_player_privs(pname, {admin_shop=true})
if (pname == owner or is_admin) and not player_press_key then
shop_fs = "size[9,8.75]"..
"label[0,0;"..S("Your stock:").."]"..
"list["..list_name..";stock;0,0.5;"..stock_w..","..stock_h..";]"..
mcl_formspec.get_itemslot_bg(0,0.5,stock_w,stock_h)..
"field[6.5,2;2,1;count;"..S("Count")..";"..count.."]"..
"field[6.5,3;2,1;price;"..S("Price")..";"..price.."]"..
"label[6,0;"..S("In exchange, you give:").."]"..
"item_image[6.5,0.5;1,1;"..shop_item.."]"..
mcl_formspec.get_itemslot_bg(6.5,0.5,1,1)..
"label[0,4;"..S("Owner, Use (special key + right mouse button) for customer interface").."]"..
emeraldbank.player_inv
else
shop_fs = "size[9,8.75]"..
"label[3.7,0;"..S("Owner gives:").."]"..
"item_image[4,1;1,1;"..shop_item.."]"..
mcl_formspec.get_itemslot_bg(4,1,1,1)..
"label[5,1.5;"..S("x @1", count).."]"..
"label[4,2;"..S("Price: @1", price).."]"..
"button[3.5,3;2,1;exchange;"..S("Exchange").."]"..
emeraldbank.player_inv
end
return shop_fs
end
local function swap_shop(pos, closed)
local oldnode = core.get_node(pos)
local oldnodemeta = core.get_meta(pos):to_table()
local nodename = core.get_node(pos).name
if closed then
core.swap_node(pos, {name = "emeraldbank:shop_empty"})
else
core.swap_node(pos, {name = "emeraldbank:shop"})
end
core.get_meta(pos):from_table(oldnodemeta)
end
local function set_item(pos, stack, player)
local meta = core.get_meta(pos)
local itemname = stack:get_name()
local itemcount = stack:get_count()
meta:set_string("shop_item", itemname)
core.show_formspec(player:get_player_name(), formspec_prefix..core.pos_to_string(pos), emeraldbank.get_shop_fs(pos, player) )
end
local function check_empty(pos)
local meta = core.get_meta(pos)
local inv = meta:get_inventory()
local count = meta:get_int("count")
local shop_item = meta:get_string("shop_item")
if inv:is_empty("stock") then
meta:set_string("shop_item", "")
swap_shop(pos, true)
elseif not inv:contains_item("stock", shop_item.." "..count, true) then
swap_shop(pos, true)
else
swap_shop(pos)
end
end
local function get_stonks(pos, player)
local name = player:get_player_name()
local meta = core.get_meta(pos)
local owner = meta:get_string("owner")
local stonks = meta:get_int("stonks")
if name == owner and stonks > 0 then
core.sound_play("cash", {
to_player = name,
gain = 1.0,
fade = 0.0,
pitch = 1.0,
})
emeraldbank.add_emeralds(player, stonks)
meta:set_int("stonks", 0)
core.chat_send_player(name, S("You've earned @1 Emeralds with your shops.", stonks) )
end
end
local function after_place_node(pos, placer, itemstack)
local owner = placer:get_player_name()
local meta = core.get_meta(pos)
meta:set_string("infotext", S("Exchange shop (owned by @1)", owner))
meta:set_string("owner", owner)
meta:set_int("count", 10) -- default count
meta:set_int("price", 5) -- default price
core.get_node_timer(pos):start(shop_timer)
local inv = meta:get_inventory()
inv:set_size("stock", stock_w*stock_h)
end
local function on_rightclick(pos, node, clicker, itemstack)
local meta = core.get_meta(pos)
local nodename = core.get_node(pos).name
local owner = meta:get_string("owner")
local pname = clicker:get_player_name()
get_stonks(pos, clicker)
--if nodename == "emeraldbank:shop" or pname == owner then
core.show_formspec(pname, formspec_prefix..core.pos_to_string(pos), emeraldbank.get_shop_fs(pos, clicker) )
--end
end
local function on_punch(pos, node, puncher, pointed_thing)
get_stonks(pos, puncher)
end
local function on_metadata_inventory_put(pos, listname, index, stack, player)
set_item(pos, stack, player) -- this func already show the fs
check_empty(pos)
end
local function on_metadata_inventory_move(pos, from_list, from_index, to_list, to_index, count, player)
check_empty(pos)
end
local function on_metadata_inventory_take(pos, listname, index, stack, player)
-- check_empty(pos) -- CRASH
core.show_formspec(player:get_player_name(), formspec_prefix..core.pos_to_string(pos), emeraldbank.get_shop_fs(pos, player) )
end
local function on_timer(pos, elapsed)
local meta = core.get_meta(pos)
local owner = meta:get_string("owner")
local is_online = core.player_exists(owner)
core.get_node_timer(pos):start(shop_timer)
check_empty(pos)
if is_online then
local player = core.get_player_by_name(owner)
if not player or player.is_fake_player then return end
get_stonks(pos, player)
end
end
local function can_dig(pos, player)
local pname = player:get_player_name()
local is_admin = core.check_player_privs(pname, {admin_shop=true})
local meta = core.get_meta(pos)
local owner = meta:get_string("owner")
local inv = meta:get_inventory()
if inv:is_empty("stock") and (pname == owner or is_admin) then
return true
end
end
-- register shop node
core.register_node("emeraldbank:shop", {
description = S("Shop"),
_doc_items_longdesc = S("A shop to sell your items with emeralds."),
is_ground_content = false,
tiles = {
"default_tree.png",
"default_tree.png",
"default_tree.png^mcl_core_emerald.png"
},
stack_max = 64,
groups = {axey=1, handy=1, building_block=1, enderman_takable=1},
sounds = mcl_sounds.node_sound_wood_defaults(),
_mcl_blast_resistance = 5,
_mcl_hardness = 1,
after_place_node = after_place_node,
on_rightclick = on_rightclick,
on_punch = on_punch,
on_metadata_inventory_put = on_metadata_inventory_put,
on_metadata_inventory_move = on_metadata_inventory_move,
on_metadata_inventory_take = on_metadata_inventory_take,
on_timer = on_timer,
can_dig = can_dig
})
-- register shop node
core.register_node("emeraldbank:shop_empty", {
description = S("Shop Empty"),
_doc_items_longdesc = S("A shop to sell your items with emeralds."),
is_ground_content = false,
tiles = {
"default_tree.png",
"default_tree.png",
"default_tree.png^mcl_core_emerald.png^mcl_core_barrier.png"
},
stack_max = 64,
groups = {axey=1, handy=1, building_block=1, enderman_takable=1, not_in_creative_inventory=1},
sounds = mcl_sounds.node_sound_wood_defaults(),
drop = "emeraldbank:shop",
_mcl_blast_resistance = 5,
_mcl_hardness = 1,
after_place_node = after_place_node,
on_rightclick = on_rightclick,
on_punch = on_punch,
on_metadata_inventory_put = on_metadata_inventory_put,
on_metadata_inventory_move = on_metadata_inventory_move,
on_metadata_inventory_take = on_metadata_inventory_take,
on_timer = on_timer,
can_dig = can_dig
})
core.register_on_player_receive_fields(function(sender, formname, fields)
local prefix_len = string.len(formspec_prefix)
if formname:sub(1,prefix_len) == formspec_prefix then
local pos_string = formname:sub(prefix_len+1)
local pos = core.string_to_pos(pos_string)
local meta = core.get_meta(pos)
local name = sender:get_player_name()
local playermeta = sender:get_meta()
local player_pos = sender:get_pos()
local old_count = meta:get_int("count")
local new_count = tonumber(fields.count)
local old_price = meta:get_int("price")
local new_price = tonumber(fields.price)
local shop_item = meta:get_string("shop_item")
local minv = meta:get_inventory()
local pinv = sender:get_inventory()
local bankemeralds = playermeta:get_int("emeraldbank:emerald")
-- set or reset timer
core.get_node_timer(pos):start(shop_timer)
-- set item count
if fields.count and string.find(fields.count, "^[0-9]+$") then
if new_count >= 1 and new_count <= 64 and new_count ~= meta:get_int("count") then
meta:set_int("count", new_count)
check_empty(pos)
end
end
-- set price
if fields.price and string.find(fields.price, "^[0-9]+$") then
if new_price >= 1 and new_price <= 10000 and new_price ~= meta:get_int("price") then
meta:set_int("price", new_price)
end
end
-- someone hit exchange button
if fields.exchange ~= nil and fields.exchange ~= "" then
-- owner try exchanges
if meta:get_string("owner") == name then
mcl_title.set(sender, "subtitle", {text=S("This is your own shop, you can't exchange to yourself!"), color="dark_red"})
else
local can_exchange = true
-- have u money?
if bankemeralds < old_price then
can_exchange = false
mcl_title.set(sender, "subtitle", {text=S("Not enough Emeralds in your account"), color="dark_red"})
end
--there are enough items?
if not minv:contains_item("stock", shop_item.." "..old_count, true) then
can_exchange = false
mcl_title.set(sender, "subtitle", {text=S("Out of Stock!"), color="dark_red"})
end
-- do not trade air
if shop_item == "" or shop_item == "air" then
can_exchange = false
end
if can_exchange then
minv:remove_item("stock", shop_item.." "..old_count)
core.add_item(player_pos, shop_item.." "..old_count)
emeraldbank.add_emeralds(sender, -old_price)
meta:set_int("stonks", meta:get_int("stonks")+old_price)
mcl_title.set(sender, "subtitle", {text=S("Exchanged!"), color="green"})
check_empty(pos)
core.show_formspec(sender:get_player_name(), formspec_prefix..core.pos_to_string(pos), emeraldbank.get_shop_fs(pos, sender) )
end
end
end
end
end)
if shopcraft then
core.register_craft({
output = "emeraldbank:shop 3",
recipe = {
{"mcl_core:emerald", "mcl_core:emerald", "mcl_core:emerald"},
{"mcl_core:emerald", "mcl_core:tree", "mcl_core:emerald"},
{"mcl_core:emerald", "mcl_core:emerald", "mcl_core:emerald"},
}
})
end