-- Dinv inventory.lua -- Copyright Duane Robertson (duane@duanerobertson.com), 2019 -- Distributed under the LGPLv2.1 (https://www.gnu.org/licenses/old-licenses/lgpl-2.1.en.html) local mod = dinv local mod_name = 'dinv' local sorted_items local ADD_SCROLL_TO_DEFAULT_CHEST = true local PROTECT_INVENTORY = false -- Prevent ANY inventory loss. local WORN_INV = 'worn' local force_rep = { ['wood'] = 'default:wood', ['leaves'] = 'default:leaves', ['stone'] = 'default:stone', ['wool'] = 'wool:white', } -- This tables looks up groups that aren't already stored. mod.group_rep = setmetatable({}, { __index = function(t, k) if not (t and k and type(k) == 'string' and type(t) == 'table') then return end local k = k:gsub('^group:', '') local r if force_rep[k] then r = force_rep[k] else for a, b in pairs(minetest.registered_items) do if b.groups and b.groups[k] then r = a break end end end if r then t[k] = r return t[k] else return end end }) local group_rep = mod.group_rep -- iterator over worn inventory function mod.worn_items(player) if not player then return end local pinv = player:get_inventory() if not pinv then return end local flist = pinv:get_list(WORN_INV) return pairs(flist) end local worn_items = mod.worn_items -- Formspec definitions are confusing. mod.form_size = 'size[11.25,7.25]' mod.main_inventory = 'list[current_player;main;2.25,3.5;8,4;' mod.craft_inventory = 'list[current_player;craft;3.25,0;3,3;]' mod.craft_preview = 'list[current_player;craftpreview;6.25,2;1,1;]' mod.main_inventory_scroll_up = 'image_button[10.25,3.5;1,1;transparent_button.png;dinv_main_inventory_up;Up]' mod.main_inventory_scroll_down = 'image_button[10.25,6.5;1,1;transparent_button.png;dinv_main_inventory_down;Down]' mod.recipe_button = 'image_button[6.25,1;1,1;transparent_button.png;dinv_recipe_next;Next]' mod.worn_items_inv = 'list[current_player;worn;0,3.5;2,4;]' mod.empty_button = 'image_button[2.25,2;1,1;transparent_button.png;dinv_empty_craft;Empty]' mod.fill_button = 'image_button[2.25,1;1,1;transparent_button.png;dinv_fill_craft;Fill]' -- backguard compatibility for older default mod, game pre 5.1 release if not minetest.global_exists("default.chest") then default.chest = {} default.chest.get_chest_formspec = default.get_chest_formspec minetest.log("warning", "[dinv] using older chest api from default mod") end -- All this is necessary to add scroll buttons to chests. if ADD_SCROLL_TO_DEFAULT_CHEST then function default.chest.get_chest_formspec(pos, player) local scroll_to = 8 if player and player.get_player_name then local player_name = player:get_player_name() if mod.dat[player_name].scroll_main_to then scroll_to = mod.dat[player_name].scroll_main_to end end local spos = pos.x .. ',' .. pos.y .. ',' .. pos.z local formspec = 'size[9,9]' .. 'list[nodemeta:' .. spos .. ';main;0,0.3;8,4;]' .. 'list[current_player;main;0,4.85;8,1;]' .. 'list[current_player;main;0,6.08;8,3;' .. scroll_to .. ']' .. 'listring[nodemeta:' .. spos .. ';main]' .. 'listring[current_player;main]' .. 'image_button[8,6.08;1,1;transparent_button.png;dinv_chest_main_inventory_up;Up]' .. 'image_button[8,8.08;1,1;transparent_button.png;dinv_chest_main_inventory_down;Down]' .. default.get_hotbar_bg(0,4.85) return formspec end local original_chest_functions = {} for _, nd in pairs({ 'default:chest', 'default:chest_locked' }) do original_chest_functions[nd] = {} original_chest_functions[nd].on_rightclick = minetest.registered_items[nd].on_rightclick minetest.override_item(nd, { on_rightclick = function(pos, node, clicker, itemstack, pointed_thing) if clicker.get_player_name then local player_name = clicker:get_player_name() local dat = mod.dat[player_name] if dat then dat.chest_opened = pos end end original_chest_functions[nd].on_rightclick(pos, node, clicker, itemstack, pointed_thing) end }) end minetest.register_on_player_receive_fields(function(player, formname, fields) if formname ~= 'default:chest' then return end if not (player and fields) then return end if not ( fields['dinv_chest_main_inventory_up'] or fields['dinv_chest_main_inventory_down'] ) then return end local player_name = player:get_player_name() local dat = mod.dat[player_name] or {} local pos = dat.chest_opened if not pos then return end local pinv = player:get_inventory() local main_inventory_size = pinv:get_size('main') if fields['dinv_chest_main_inventory_up'] then dat['scroll_main_to'] = math.max(8, (dat['scroll_main_to'] or 8) - 16) minetest.show_formspec(player_name, 'default:chest', default.chest.get_chest_formspec(pos, player)) elseif fields['dinv_chest_main_inventory_down'] then dat['scroll_main_to'] = (dat['scroll_main_to'] or 8) + 16 if dat['scroll_main_to'] >= main_inventory_size then dat['scroll_main_to'] = 8 end minetest.show_formspec(player_name, 'default:chest', default.chest.get_chest_formspec(pos, player)) end end) end function mod.damage_armor(player, damage) local wear = (damage + 1) * 100 for k, v in worn_items(player) do local vs = v:get_name() local it = minetest.registered_items[vs] if it._dinv_armor then local ow = v:get_wear() v:add_wear(wear) player:get_inventory():set_stack(WORN_INV, k, v) if ow + wear > 65535 then mod.set_armor(player) mod.set_armor_textures(player) end end end end function mod.empty_craft(player) local pinv = player:get_inventory() local craft_size = pinv:get_size('craft') for i = 1, craft_size do local st = pinv:get_stack('craft', i) if pinv:room_for_item('main', st) then pinv:add_item('main', st) pinv:set_stack('craft', i, nil) else return end end return true end function mod.empty_trash(player) local pos if player and player.get_player_name then local player_name = player:get_player_name() if mod.dat[player_name].trash_opened then pos = mod.dat[player_name].trash_opened end end if not pos then return end local meta = minetest.get_meta(pos) if not meta then return end local inv = meta:get_inventory() if not inv then return end local size = inv:get_size('main') for i = 1, size do --local st = inv:get_stack('main', i) inv:set_stack('main', i, nil) end end function mod.get_all_craft_recipes(craft_item) local recipes = {} for k, v in pairs(minetest.get_all_craft_recipes(craft_item) or {}) do if v.type ~= 'cooking' then table.insert(recipes, v) end end if #recipes < 1 then return end return recipes end -- Calculate how big the main inventory should be. function mod.get_main_size_by_bags(player) local isize = 32 for k, v in worn_items(player) do local vs = v:get_name() local it = minetest.registered_items[vs] if it._dinv_storage_size then isize = isize + it._dinv_storage_size end end return isize end function mod.get_trashcan_formspec(pos, player) local scroll_to = 0 if player and player.get_player_name then local player_name = player:get_player_name() if mod.dat[player_name].scroll_main_to then scroll_to = mod.dat[player_name].scroll_main_to end end local spos = pos.x .. ',' .. pos.y .. ',' .. pos.z local formspec = 'size[9,8]' .. 'list[nodemeta:' .. spos .. ';main;0,0.3;8,2;]' .. 'list[current_player;main;0,4;8,4;' .. scroll_to .. ']' .. 'listring[]' .. 'image_button[3,2.5;2,1;transparent_button.png;dinv_trash_empty;Empty Trash]' .. 'image_button[8,4;1,1;transparent_button.png;dinv_trash_inventory_up;Up]' .. 'image_button[8,6;1,1;transparent_button.png;dinv_trash_inventory_down;Down]' return formspec end -- Any warmth over zero is sufficient at the moment. function mod.get_warmth(player) if not player then return end local warmth = 0 for k, v in worn_items(player) do local vs = v:get_name() local it = minetest.registered_items[vs] if it._dinv_warmth then warmth = warmth + it._dinv_warmth end end return warmth end -- Check if there are any stacks in the given inventory, -- at the given positions. This is important to avoid losing -- those items when a bag is removed. function mod.items_at_range(inv, name, i, j) if not (inv and name and i and j) then return end local a = inv:get_list(name) if not a then return end for ind = i + 1, j do if a[ind] and a[ind]:get_name() ~= '' then return true end end end -- The main formspec... function mod.make_inventory_spec_sfinv(this, player, context) if not player then return end local player_name = player:get_player_name() if not mod.dat[player_name] then mod.dat[player_name] = {} end local dat = mod.dat[player_name] local scroll_main_to = dat['scroll_main_to'] or 0 local inventory = '' inventory = inventory .. mod.worn_items_inv inventory = inventory .. mod.empty_button inventory = inventory .. mod.fill_button inventory = inventory .. mod.main_inventory .. scroll_main_to .. ']' inventory = inventory .. mod.craft_inventory inventory = inventory .. 'listring[]' inventory = inventory .. mod.craft_preview inventory = inventory .. mod.main_inventory_scroll_up inventory = inventory .. mod.main_inventory_scroll_down inventory = inventory .. mod.recipe_grid(player) inventory = inventory .. mod.recipe_list(player) local size = 'size[11.25,7.25]' local show_inv = false return sfinv.make_formspec(player, context, inventory, show_inv, size) end -- Change one or more privileges. Set a privilege value -- to 0, in the input table, to remove it. ----------------------------------------------- -- Note that this can remove granted privileges. ----------------------------------------------- function mod.modify_privs(player, p) local player_name = player:get_player_name() local privs = minetest.get_player_privs(player_name) or {} for k, v in pairs(p) do if v == 0 then privs[k] = nil else privs[k] = v end end minetest.set_player_privs(player_name, privs) end -- Quick table of all wearable items. ----------------------------------------------------- -- Populating this after the game starts might cause -- problems, so I do it twice, just in case. ----------------------------------------------------- mod.wearable = { } function mod.populate_wearable_table() for k, v in pairs(minetest.registered_items) do if v._dinv_armor or v._dinv_storage_size or v._dinv_on_wear or v._dinv_on_remove or v._dinv_while_worn then mod.wearable[k] = true end end end mod.populate_wearable_table() minetest.after(0, function() mod.populate_wearable_table() end) function mod.receive_sfinv_fields(self, player, context, fields) if not (player and fields) then return end if not ( fields['dinv_main_inventory_up'] or fields['dinv_main_inventory_down'] or fields['dinv_recipe_list'] or fields['dinv_recipe_next'] or fields['dinv_empty_craft'] or fields['dinv_fill_craft'] ) then return end local pinv = player:get_inventory() local main_inventory_size = pinv:get_size('main') if fields and fields['dinv_main_inventory_up'] then mod.scroll_main(player, -16, main_inventory_size) elseif fields and fields['dinv_main_inventory_down'] then mod.scroll_main(player, 16, main_inventory_size) elseif fields and fields['dinv_recipe_list'] then mod.show_recipe(player, fields['dinv_recipe_list']) elseif fields and fields['dinv_recipe_next'] then mod.switch_recipe(player, 1) elseif fields and fields['dinv_empty_craft'] then mod.empty_craft(player) elseif fields and fields['dinv_fill_craft'] then mod.recipe_fill(player) end end function mod.recipe_fill(player) local player_name = player:get_player_name() local dat = mod.dat[player_name] local craft_item_number = dat['craft_item_number'] local recipe_number = dat['recipe_number'] or 1 if not craft_item_number then return end local craft_item = sorted_items[craft_item_number] if not craft_item then return end local recipes = mod.get_all_craft_recipes(craft_item) if not recipes then return end local pinv = player:get_inventory() local main_size = pinv:get_size('main') if recipe_number > #recipes then recipe_number = 1 dat['recipe_number'] = recipe_number end local recipe = recipes[recipe_number] local w = recipe.width or 3 if w == 0 or w > 3 then w = 3 end local items = {} local totals = {} local g_s = {} local i = 0 for y = 0, 2 do for x = 1, w do i = i + 1 local item, group if recipe.type == 'normal' then item = recipe.items[(y * w) + x] end if item then items[i] = item totals[item] = (totals[item] or 0) + 1 end end end local avail = {} local groups = {} local stack_max = {} local only_one local max = 999999 for k, v in pairs(totals) do if k:find('^group:') then local group = k:gsub('^group:', '') for i = 1, main_size do local st = pinv:get_stack('main', i) local name = st:get_name() --[[ print(name) if name == 'bones:bones' then pinv:set_stack('main', i, nil) end --]] local it = minetest.registered_items[name] if not it then --print(mod_name..': Cannot find item: ' .. name) return end if it.groups and it.groups[group] then local ct = st:get_count() avail[k] = (avail[k] or 0) + ct groups[k] = (groups[k] or {}) groups[k][name] = (groups[k][name] or 0) + ct stack_max[name] = it.stack_max or 99 end end local gmax for l, w in pairs(groups[k] or {}) do if not gmax then gmax = w / v end gmax = math.min(math.max(gmax, w / v), stack_max[l]) end if gmax then max = math.min(max, gmax) end else for i = 1, main_size do local st = pinv:get_stack('main', i) local name = st:get_name() if k == name then avail[k] = (avail[k] or 0) + st:get_count() local it = minetest.registered_items[k] if not it then --print(mod_name..': Cannot find item: ' .. name) return end stack_max[name] = it.stack_max or 99 if stack_max[name] < 2 then only_one = true end end end if max and avail[k] and stack_max[k] then max = math.min(math.min(max, avail[k] / v), stack_max[k]) end end end for k, v in pairs(totals) do if not (avail[k] and avail[k] >= v) then --print(mod_name..': Cannot find ' .. k .. ' in inventory.') return end end if only_one then max = 1 else max = math.floor(max) end if max < 1 then return end if not mod.empty_craft(player) then --print(mod_name..': Cannot empty craft inventory') return end for k, v in pairs(items) do if v:find('^group:') then for l in pairs(groups[v]) do local w = groups[v][l] if w >= max then local st = pinv:remove_item('main', l .. ' ' .. max) groups[v][l] = groups[v][l] - st:get_count() pinv:set_stack('craft', k, st) break end end else local st = pinv:remove_item('main', v .. ' ' .. max) pinv:set_stack('craft', k, st) end end end -- Return a 3 x 3 grid of images matching the selected recipe. -- This appears over then actual craft grid, but won't interfere -- with it. function mod.recipe_grid(player) local player_name = player:get_player_name() local dat = mod.dat[player_name] local craft_item_number = dat['craft_item_number'] local recipe_number = dat['recipe_number'] or 1 if not craft_item_number then return '' end local craft_item = sorted_items[craft_item_number] if not craft_item then return '' end local recipes = mod.get_all_craft_recipes(craft_item) if not recipes then return '' end if recipe_number > #recipes then recipe_number = 1 dat['recipe_number'] = recipe_number end local recipe = recipes[recipe_number] local inv = '' inv = inv .. 'container[3.25,0]' do local tooltip = craft_item inv = inv .. 'item_image[3,2;1,1;' .. craft_item .. ']' tooltip = minetest.registered_items[craft_item].description or tooltip inv = inv .. 'tooltip[3,2;0.8,0.8;' .. 'recipe: ' .. tooltip .. ']' end local w = recipe.width or 3 if w == 0 or w > 3 then w = 3 end local g_s = {} local i = 0 for y = 0, 2 do for x = 1, w do i = i + 1 local item, group if recipe.type == 'normal' then item = recipe.items[(y * w) + x] end local tooltip = item if item and item:find('^group') then --print(item) item = group_rep[item] if item then g_s[i] = true end elseif item then tooltip = minetest.registered_items[item].description or tooltip end if item then inv = inv .. 'item_image[' .. (x - 1) .. ',' .. (y) .. ';1,1;' .. item .. ']' inv = inv .. 'tooltip[' .. (x - 1) .. ',' .. (y) .. ';0.8,0.8;' .. 'recipe: ' .. tooltip .. ']' end end end for i = 1, 9 do if g_s[i] then local x = (i - 1) % w local y = math.floor((i - 1) / w) inv = inv .. 'image[' .. (x - 0) .. ',' .. (y) .. ';1,1;big_g.png]' end end inv = inv .. 'container_end[]' if #recipes > 1 then inv = inv .. mod.recipe_button end return inv end -- Return a listbox filled with items that can be crafted. function mod.recipe_list(player) if not sorted_items then sorted_items = {} for k, v in pairs(minetest.registered_items) do if k and k ~= '' and mod.get_all_craft_recipes(k) then local recs = mod.get_all_craft_recipes(k) for a, b in pairs(recs) do if b.type ~= 'cooking' then table.insert(sorted_items, k) break end end end end table.sort(sorted_items) end local inv = '' inv = inv .. 'textlist[7.25,0;3.75,2.9;dinv_recipe_list;' local t for k, v in pairs(sorted_items) do if t then inv = inv .. ',' end inv = inv .. v --print(v) t = true end inv = inv .. ';' return inv end -- Recreate the inventory formspec when the player scrolls -- up or down in the main inventory. function mod.scroll_main(player, amount, max) if not (player and amount) then return end local player_name = player:get_player_name() if not player_name then return end local scroll = mod.dat[player_name].scroll_main_to or 0 if scroll and scroll % 8 == 0 then scroll = (scroll + amount) if scroll > max - 1 or scroll < 0 then scroll = 0 end mod.dat[player_name].scroll_main_to = scroll sfinv.set_player_inventory_formspec(player) end end function mod.scroll_trash(player, amount, max) if not (player and amount) then return end local player_name = player:get_player_name() if not player_name then return end local dat = mod.dat[player_name] or {} local pos = dat.trash_opened if not pos then return end local scroll = mod.dat[player_name].scroll_main_to or 0 if scroll and scroll % 8 == 0 then scroll = (scroll + amount) if scroll > max - 1 or scroll < 0 then scroll = 0 end mod.dat[player_name].scroll_main_to = scroll minetest.show_formspec(player_name, mod_name..':trashcan', mod.get_trashcan_formspec(pos, player)) end end function mod.set_armor(player) if not player then return end local armor = 100 for k, v in worn_items(player) do local vs = v:get_name() local it = minetest.registered_items[vs] if it._dinv_armor then armor = armor * it._dinv_armor end end local player_name = player:get_player_name() if player_name then minetest.chat_send_player(player_name, 'Your armor: ' .. armor) end local armor_g = player:get_armor_groups() if not (armor_g and armor_g.fleshy) then return end armor_g.fleshy = armor player:set_armor_groups(armor_g) end ----------------------------------------------- -- Todo: Handle different character textures. ----------------------------------------------- function mod.set_armor_textures(player) local prop = player:get_properties() local textures = prop.textures --local tex = (textures and textures[1] or 'character.png') local tex = 'character.png' local pile = {} for k, v in worn_items(player) do local vs = v:get_name() local it = minetest.registered_items[vs] if it._dinv_location and it._dinv_texture then pile[it._dinv_location] = it._dinv_texture end end for _, loc in pairs({ 'body', 'feet', 'head', 'arm', 'back' }) do if pile[loc] then tex = tex .. '^' .. pile[loc] end end textures = { tex } if minetest.get_modpath("player_api") then player_api.set_textures(player, textures) else default.player_set_textures(player, textures) end end -- Set the size of the main inventory. function mod.set_main_size_by_bags(player) if not player then return end local pinv = player:get_inventory() if not pinv then return end local prsize = pinv:get_size('main') local isize = mod.get_main_size_by_bags(player) if PROTECT_INVENTORY and isize < prsize then print(mod_name..': *** Preventing lost inventory from reducing bag sizes') isize = prsize end if not pinv:set_size('main', isize) then print(mod_name..': *** ERROR setting inventory size.') end return isize end -- Recreate the inventory formspec to show a recipe given -- by the return value from the recipe list. function mod.show_recipe(player, field) if not (player and field) then return end local player_name = player:get_player_name() if not player_name then return end local t = minetest.explode_textlist_event(field) if t.type == 'CHG' and t.index then mod.dat[player_name].craft_item_number = tonumber(t.index) mod.dat[player_name].recipe_number = 1 sfinv.set_player_inventory_formspec(player) end end -- Recreate the inventory formspec to show a different recipe -- for the current item (if it has more than one). function mod.switch_recipe(player, amount) if not (player and amount) then return end local player_name = player:get_player_name() if not player_name then return end local dat = mod.dat[player_name] if not dat.recipe_number then dat.recipe_number = 1 end dat.recipe_number = dat.recipe_number + amount if dat.recipe_number < 1 then dat.recipe_number = 1 end sfinv.set_player_inventory_formspec(player) end function mod.trashcan_can_dig(pos,player) local meta = minetest.get_meta(pos); local inv = meta:get_inventory() return inv:is_empty('main') end function mod.trashcan_construct(pos) local meta = minetest.get_meta(pos) meta:set_string('infotext', 'Trashcan') local inv = meta:get_inventory() inv:set_size('main', 8*2) end function mod.trashcan_rightclick(pos, node, player, itemstack, pointed_thing) local player_name if player and player.get_player_name then player_name = player:get_player_name() end if not player_name then return end local dat = mod.dat[player_name] if dat then dat.trash_opened = pos end minetest.show_formspec(player_name, mod_name..':trashcan', mod.get_trashcan_formspec(pos, player)) end -- Return true if there's an item at that body location. function mod.wearing_on_location(player, loc) for k, v in worn_items(player) do local vs = v:get_name() local it = minetest.registered_items[vs] if it._dinv_location == loc then return true end end end -- Check for BAD THINGS if a player moves/adds/removes this item. minetest.register_allow_player_inventory_action(function(player, action, inventory, inventory_info) if not (player and action and inventory and inventory_info) then return end if not (inventory_info.from_list == WORN_INV or inventory_info.to_list == WORN_INV or inventory_info.listname == WORN_INV) then return end local item_from, item_from_s if action == 'move' and inventory_info.from_list then item_from = inventory:get_stack(inventory_info.from_list, inventory_info.from_index) else item_from = inventory_info.stack end if item_from and item_from.get_name then item_from_s = item_from:get_name() end local item_to, item_to_s if action == 'move' and inventory_info.to_list then item_to = inventory:get_stack(inventory_info.to_list, inventory_info.to_index) end if item_to and item_to.get_name then item_to_s = item_to:get_name() end if action == 'move' then if not mod.wearable[item_from_s] then if inventory_info.to_list == WORN_INV then return 0 else return end end if item_to_s and item_to_s ~= '' then return 0 end if inventory_info.to_list == inventory_info.from_list then return end local item_from_it = minetest.registered_items[item_from_s] if item_from_it._dinv_location and inventory_info.to_list == WORN_INV and mod.wearing_on_location(player, item_from_it._dinv_location) then return 0 end if item_from_it._dinv_storage_size then local prsize = mod.get_main_size_by_bags(player) local isize = prsize if inventory_info.to_list == WORN_INV then isize = isize + item_from_it._dinv_storage_size elseif inventory_info.from_list == WORN_INV then isize = isize - item_from_it._dinv_storage_size end if isize < prsize and mod.items_at_range(inventory, 'main', isize, prsize) then return 0 elseif inventory_info.to_index > isize then return 0 end end elseif action == 'take' and mod.wearable[item_from_s] then return 0 elseif action == 'put' then return 0 end end) -- Damage items that can only be worn for a limited time. local last_wear_check = 0 minetest.register_globalstep(function(dtime) local time = minetest.get_gametime() if type(time) ~= 'number' then return end if time - last_wear_check < 5 then return end local players = minetest.get_connected_players() for i = 1, #players do local player = players[i] for k, v in worn_items(player) do local vs = v:get_name() local it = minetest.registered_items[vs] if it._dinv_wears_out then local ow = v:get_wear() local wear = it._dinv_wears_out v:add_wear(wear) player:get_inventory():set_stack(WORN_INV, k, v) if ow + wear > 65535 then if it._dinv_on_remove then it._dinv_on_remove(player) end --[[ mod.set_armor(player) mod.set_armor_textures(player) --]] end if it._dinv_while_worn then it._dinv_while_worn(player) end end end end last_wear_check = minetest.get_gametime() end) minetest.register_on_joinplayer(function(player) local player_name = player:get_player_name() --[[ if not mod.dat[player_name] then mod.dat[player_name] = {} end --]] local pinv = player:get_inventory() pinv:set_size(WORN_INV, 8) mod.set_main_size_by_bags(player) mod.set_armor(player) mod.set_armor_textures(player) end) --sfinv.register_page(mod_name..':inventory', { sfinv.override_page('sfinv:crafting', { title = 'Inventory', get = mod.make_inventory_spec_sfinv, on_player_receive_fields = mod.receive_sfinv_fields, }) -- Handle inventory moves (change armor, etc.). minetest.register_on_player_inventory_action(function(player, action, inventory, inventory_info) if not (player and action and inventory and inventory_info) then return end if not (inventory_info.from_list == WORN_INV or inventory_info.to_list == WORN_INV or inventory_info.listname == WORN_INV) then return end local item if action == 'move' then if not (inventory_info.to_list and inventory_info.to_index) then return end item = inventory:get_stack(inventory_info.to_list, inventory_info.to_index) else item = inventory_info.stack end if not item then return end local item_s = item:get_name() if not mod.wearable[item_s] then return end mod.set_main_size_by_bags(player) mod.set_armor(player) mod.set_armor_textures(player) local it = minetest.registered_items[item_s] if inventory_info.to_list == inventory_info.from_list then -- nop elseif it._dinv_on_wear and inventory_info.to_list == WORN_INV then it._dinv_on_wear(player) elseif it._dinv_on_remove and inventory_info.from_list == WORN_INV then it._dinv_on_remove(player) end end) -- Get input from the trash formspec buttons. minetest.register_on_player_receive_fields(function(player, formname, fields) if formname ~= mod_name..':trashcan' then return end if not (player and fields) then return end if not ( fields['dinv_trash_inventory_up'] or fields['dinv_trash_inventory_down'] or fields['dinv_trash_empty'] ) then return end local pinv = player:get_inventory() local main_inventory_size = pinv:get_size('main') if fields and fields['dinv_trash_inventory_up'] then mod.scroll_trash(player, -16, main_inventory_size) elseif fields and fields['dinv_trash_inventory_down'] then mod.scroll_trash(player, 16, main_inventory_size) elseif fields and fields['dinv_trash_empty'] then mod.empty_trash(player) end end) -- Every time the player gets punched, armor is damaged, -- even if no damage is done to the player. minetest.register_on_punchplayer(function(player, hitter, time_from_last_punch, tool_capabilities, dir, damage) mod.damage_armor(player, damage) end) if not minetest.get_modpath('bones') then print(mod_name..': Player gear will suffer when the player dies.') minetest.register_on_dieplayer(function(player, reason) if not player then return end local pinv = player:get_inventory() if not pinv then return end local wear = 20000 local main_size = pinv:get_size('main') for i = 1, main_size do local st = pinv:get_stack('main', i) local name = st:get_name() if minetest.registered_tools[name] then local ow = st:get_wear() st:add_wear(wear) pinv:set_stack('main', i, st) end end mod.damage_armor(player, 199) mod.set_armor(player) mod.set_armor_textures(player) end) end