local S = exchange_shop.S function exchange_shop.has_access(meta, player_name) local owner = meta:get_string("owner") if player_name == owner or owner == "" then return true end local privs = minetest.get_player_privs(player_name) return privs.server or privs.protection_bypass end -- Tool wear aware replacement for contains_item. function exchange_shop.list_contains_item(inv, listname, stack) local count = stack:get_count() if count == 0 then return true end local list = inv:get_list(listname) local name = stack:get_name() local wear = stack:get_wear() for _, list_stack in pairs(list) do if list_stack:get_name() == name and list_stack:get_wear() <= wear then if list_stack:get_count() >= count then return true else count = count - list_stack:get_count() end end end end -- Tool wear aware replacement for remove_item. function exchange_shop.list_remove_item(inv, listname, stack) local wanted_count = stack:get_count() if wanted_count == 0 then return stack end local list = inv:get_list(listname) local name = stack:get_name() local wear = stack:get_wear() -- Information about the removed stack -- this includes the metadata of the last taken stack local taken_stack = ItemStack() local remaining = wanted_count local removed_wear = 0 for index, list_stack in pairs(list) do if list_stack:get_name() == name and list_stack:get_wear() <= wear then -- Only sell better tools (less worn out) taken_stack = list_stack:take_item(remaining) inv:set_stack(listname, index, list_stack) removed_wear = math.max(removed_wear, taken_stack:get_wear()) remaining = remaining - taken_stack:get_count() if remaining == 0 then break end end end -- For oversized stacks, ItemStack:add_item returns a leftover -- handle the stack count manually to avoid this issue taken_stack:set_count(wanted_count - remaining) taken_stack:set_wear(removed_wear) return taken_stack end function exchange_shop.exchange_action(player_inv, shop_inv) if not shop_inv:is_empty("cust_ej") or not shop_inv:is_empty("custm_ej") then return S("One or multiple ejection fields are filled.") .. " " .. S("Please empty them or contact the shop owner.") end local owner_wants = shop_inv:get_list("cust_ow") local owner_gives = shop_inv:get_list("cust_og") -- Check validness of stack "owner wants" for i1, item1 in pairs(owner_wants) do local name1 = item1:get_name() for i2, item2 in pairs(owner_wants) do if name1 == "" then break end if i1 ~= i2 and name1 == item2:get_name() then return S("The field '@1' can not contain multiple times the same items.", S("You need")) .. " " .. S("Please contact the shop owner.") end end end -- Check validness of stack "owner gives" for i1, item1 in pairs(owner_gives) do local name1 = item1:get_name() for i2, item2 in pairs(owner_gives) do if name1 == "" then break end if i1 ~= i2 and name1 == item2:get_name() then return S("The field '@1' can not contain multiple times the same items.", S("You give")) .. " " .. S("Please contact the shop owner.") end end end -- Check for space in the shop for i, item in pairs(owner_wants) do if not shop_inv:room_for_item("custm", item) then return S("The stock in this shop is full.") .. " " .. S("Please contact the shop owner.") end end local list_contains_item = exchange_shop.list_contains_item -- Check availability of the shop's items for i, item in pairs(owner_gives) do if not list_contains_item(shop_inv, "stock", item) then return S("This shop is sold out.") end end -- Check for space in the player's inventory for i, item in pairs(owner_gives) do if not player_inv:room_for_item("main", item) then return S("You do not have enough space in your inventory.") end end -- Check availability of the player's items for i, item in pairs(owner_wants) do if not list_contains_item(player_inv, "main", item) then return S("You do not have the required items.") end end local list_remove_item = exchange_shop.list_remove_item -- Conditions are ok: (try to) exchange now local fully_exchanged = true for i, item in pairs(owner_wants) do local stack = list_remove_item(player_inv, "main", item) if shop_inv:room_for_item("custm", stack) then shop_inv:add_item("custm", stack) else -- Move to ejection field shop_inv:add_item("custm_ej", stack) fully_exchanged = false end end for i, item in pairs(owner_gives) do local stack = list_remove_item(shop_inv, "stock", item) if player_inv:room_for_item("main", stack) then player_inv:add_item("main", stack) else -- Move to ejection field shop_inv:add_item("cust_ej", stack) fully_exchanged = false end end if not fully_exchanged then return S("Warning! Stacks are overflowing somewhere!"), true end end