function vzxv.get_inventory(player) local m = player:get_meta() local str = m:get_string "items" local items = str and minetest.deserialize(str) if not items then return {} end local stacks = {} for _, stack in ipairs(items) do table.insert(stacks, ItemStack(stack)) end return stacks end vzxv.on_inventory_update = vzxv.event.create() function vzxv.update_inventory(player, items) local new_items = {} for _, stack in ipairs(items) do if not stack:is_empty() then table.insert(new_items, stack:to_string()) end end local m = player:get_meta() m:set_string("items", minetest.serialize(new_items)) local inv = vzxv.get_inventory(player) vzxv.on_inventory_update:trigger(player, inv) vzxv.update_hotbar(player) end local function match(a, b) a = ItemStack(a) b = ItemStack(b) -- ignore item stack limits a:set_count(1) b:set_count(1) return not a:is_empty() and not b:is_empty() and a:item_fits(b) end function vzxv.inventory_idx(player, stack) local inv = vzxv.get_inventory(player) for i, inv_stack in ipairs(inv) do if match(inv_stack, stack) then return i end end end function vzxv.update_hotbar(player) local hotbar = player:get_inventory() local inv = vzxv.get_inventory(player) for i=1,8 do local hotbar_stack = hotbar:get_stack("main", i) if not hotbar_stack:is_empty() then local idx = vzxv.inventory_idx(player, hotbar_stack) if idx then hotbar_stack:set_count(inv[idx]:get_count()) else hotbar_stack:set_count(0) end hotbar:set_stack("main", i, hotbar_stack) end end end -- add a stack from the inventory at idx to the hotbar function vzxv.add_to_hotbar(player, idx, make_room) local hotbar = player:get_inventory() local inv = vzxv.get_inventory(player) for i=1,8 do local stack = hotbar:get_stack("main", i) if match(stack, inv[idx]) then -- stack is already in hotbar return i elseif stack:is_empty() then hotbar:set_stack("main", i, inv[idx]) return i end end if make_room then for i=7,1,-1 do local stack = hotbar:get_stack("main", i) hotbar:set_stack("main", i + 1, stack) end hotbar:set_stack("main", 1, inv[idx]) return 1 end end -- item is given to player -- TODO: weight limit function vzxv.give_items(player, stack) if stack:is_empty() then return stack end local inv = vzxv.get_inventory(player) local idx = vzxv.inventory_idx(player, stack) if idx then inv[idx]:set_count(inv[idx]:get_count() + stack:get_count()) else table.insert(inv, ItemStack(stack)) end vzxv.update_inventory(player, inv) -- return leftover return ItemStack "" end -- player actively collects item function vzxv.collect_items(player, stack) if stack:is_empty() then return 0 end local leftover = vzxv.give_items(player, stack) local idx = vzxv.inventory_idx(player, stack) if idx then vzxv.add_to_hotbar(player, idx) end return leftover end -- set require_all to require that all that at least the amount of items being -- removed exist in the inventory function vzxv.remove_items(player, stack, require_all) if stack:is_empty() then return ItemStack "" end local idx = vzxv.inventory_idx(player, stack) if not idx then return ItemStack "" end local inv = vzxv.get_inventory(player) if require_all and inv[idx]:get_count() < stack:get_count() then return ItemStack "" end local taken = inv[idx]:take_item(stack:get_count()) vzxv.update_inventory(player, inv) return taken end minetest.register_allow_player_inventory_action(function(player,action,inv,info) if action == "move" then local from = inv:get_stack(info.from_list, info.from_index) -- prevent player from splitting stacks if info.count == from:get_count() then return end end return 0 end) function minetest.handle_node_drops(pos, drops, digger) local rejected = {} for _, drop in ipairs(drops) do drop = ItemStack(drop) local leftover = vzxv.collect_items(digger, drop) if not leftover:is_empty() then table.insert(rejected, leftover) end end -- delay this until after the node has been set to air minetest.after(0, function() for _, stack in ipairs(rejected) do vzxv.drop(pos, stack) end end) end minetest.register_on_joinplayer(function(player) vzxv.update_hotbar(player) end) minetest.register_on_placenode(function(_, _, placer, _, stack) local inv = vzxv.get_inventory(placer) local idx = vzxv.inventory_idx(placer, stack) if idx then inv[idx]:set_count(stack:get_count() - 1) vzxv.update_inventory(placer, inv) end end) local function give_command(player_name, item, count) if not player_name then return false end if not item then return false end local player = minetest.get_player_by_name(player_name) if not player then return false, "unknown player" end count = count and tonumber(count) or 1 local stack = ItemStack(item) stack:set_count(count) local leftover = vzxv.collect_items(player, stack) local count = count - leftover:get_count() return true, ("gave %s %s to %s"):format(count, item, player_name) end minetest.override_chatcommand("give", { params = " []", description = "give item to player", privs = {give = true}, func = function(name, param) local args = {} for arg in param:gmatch "(%S+)" do table.insert(args, arg) end return give_command(unpack(args)) end, }) minetest.override_chatcommand("giveme", { params = " []", description = "give item to you", privs = {give = true}, func = function(name, param) local args = {} for arg in param:gmatch "(%S+)" do table.insert(args, arg) end return give_command(name, unpack(args)) end, }) minetest.register_chatcommand("clear", { params = "", description = "clear inventory of player", privs = {debug = true}, func = function(name, param) local player = minetest.get_player_by_name(param) if not player then return false, "unknown player" end vzxv.update_inventory(player, {}) return true, "inventory cleared" end, }) vzxv.include "ui.lua"