From 272a7a7fc86a5c07f92758cb21a5305df1a9177b Mon Sep 17 00:00:00 2001 From: Duane Robertson Date: Thu, 25 Jul 2019 22:55:59 -0500 Subject: [PATCH] Clean up code. Add rings and more textures. --- init.lua | 853 ++++++++++++--------- textures/anvil.png | Bin 0 -> 656 bytes textures/dinv_char_chain_armor.png | Bin 1731 -> 1780 bytes textures/dinv_char_diamond_plate_armor.png | Bin 0 -> 1351 bytes textures/dinv_char_fur_cloak.png | Bin 0 -> 459 bytes textures/dinv_char_plate_armor.png | Bin 0 -> 1346 bytes textures/dinv_char_steel_helm.png | Bin 0 -> 375 bytes textures/dinv_char_steel_shield.png | Bin 0 -> 340 bytes textures/glass.png | Bin 0 -> 706 bytes 9 files changed, 488 insertions(+), 365 deletions(-) create mode 100644 textures/anvil.png create mode 100644 textures/dinv_char_diamond_plate_armor.png create mode 100644 textures/dinv_char_fur_cloak.png create mode 100644 textures/dinv_char_plate_armor.png create mode 100644 textures/dinv_char_steel_helm.png create mode 100644 textures/dinv_char_steel_shield.png create mode 100644 textures/glass.png diff --git a/init.lua b/init.lua index 5db2411..e6a3c6c 100644 --- a/init.lua +++ b/init.lua @@ -13,23 +13,28 @@ mod.world = minetest.get_worldpath() mod.dat = {} -local worn_inv = 'worn' +local ADD_SCROLL_TO_DEFAULT_CHEST = true local sorted_items +local WORN_INV = 'worn' +local PROTECT_INVENTORY = false -- Prevent ANY inventory loss. minetest.register_craftitem(mod_name..':bag_small', { inventory_image = 'bags_small.png', stack_max = 1, + _dinv_storage_size = 8, }) minetest.register_craftitem(mod_name..':bag_medium', { inventory_image = 'bags_medium.png', stack_max = 1, + _dinv_storage_size = 16, }) minetest.register_craftitem(mod_name..':bag_large', { inventory_image = 'bags_large.png', stack_max = 1, + _dinv_storage_size = 24, }) minetest.register_tool(mod_name..':leather_armor', { @@ -61,7 +66,25 @@ minetest.register_tool(mod_name..':steel_helmet', { description = 'Steel Helmet', _dinv_armor = 0.8, _dinv_location = 'head', - --_dinv_texture = '', + _dinv_texture = 'dinv_char_steel_helm.png', +}) + +minetest.register_tool(mod_name..':ring_protection_9', { + inventory_image = 'anvil.png', + description = 'Ring of Protection', + _dinv_armor = 0.9, +}) + +minetest.register_tool(mod_name..':ring_flight', { + inventory_image = 'glass.png', + description = 'Ring of Flight', + _dinv_wears_out = 10000, + _dinv_on_wear = function(player) + mod.modify_privs(player, { fly = true, noclip = 0 }) + end, + _dinv_on_remove = function(player) + mod.modify_privs(player, { fly = 0, noclip = 0 }) + end, }) minetest.register_tool(mod_name..':wood_shield', { @@ -77,7 +100,7 @@ minetest.register_tool(mod_name..':steel_shield', { description = 'Steel Shield', _dinv_armor = 0.7, _dinv_location = 'arm', - --_dinv_texture = '', + _dinv_texture = 'dinv_char_steel_shield.png', }) minetest.register_tool(mod_name..':chain_armor', { @@ -93,7 +116,7 @@ minetest.register_tool(mod_name..':plate_armor', { description = 'Plate Mail', _dinv_armor = 0.6, _dinv_location = 'body', - --_dinv_texture = '', + _dinv_texture = 'dinv_char_plate_armor.png', }) minetest.register_tool(mod_name..':diamond_plate_armor', { @@ -101,7 +124,7 @@ minetest.register_tool(mod_name..':diamond_plate_armor', { description = 'Diamond Plate Mail', _dinv_armor = 0.45, _dinv_location = 'body', - --_dinv_texture = '', + _dinv_texture = 'dinv_char_diamond_plate_armor.png', }) minetest.register_tool(mod_name..':fur_cloak', { @@ -110,7 +133,7 @@ minetest.register_tool(mod_name..':fur_cloak', { _dinv_armor = 0.98, _dinv_warmth = 2, _dinv_location = 'back', - --_dinv_texture = '', + _dinv_texture = 'dinv_char_fur_cloak.png', }) --print(dump(minetest.registered_tools[mod_name..':plate_armor'])) @@ -272,28 +295,6 @@ minetest.register_craft({ }) -mod.bag_sizes = { - [mod_name..':bag_small'] = 8, - [mod_name..':bag_medium'] = 16, - [mod_name..':bag_large'] = 24, - [mod_name..':bag_huge'] = 32, - [mod_name..':bag_hole'] = 64, -} - - -mod.wearable = { } -do - for k, v in pairs(mod.bag_sizes) do - mod.wearable[k] = true - end - - for k, v in pairs(minetest.registered_items) do - if v._dinv_armor then - mod.wearable[k] = true - end - end -end - local force_rep = { ['wood'] = 'default:wood', @@ -302,7 +303,6 @@ local force_rep = { ['wool'] = 'wool:white', } - -- This tables looks up groups that aren't already stored. mod.group_rep = setmetatable({}, { __index = function(t, k) @@ -334,6 +334,7 @@ mod.group_rep = setmetatable({}, { local group_rep = mod.group_rep + -- iterator over worn inventory function mod.worn_items(player) if not player then @@ -345,12 +346,14 @@ function mod.worn_items(player) return end - local flist = pinv:get_list(worn_inv) + 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.75]' mod.main_inventory = 'list[current_player;main;0,4;8,4;' mod.craft_inventory = 'list[current_player;craft;3,0;3,3;]' @@ -361,6 +364,172 @@ mod.recipe_buttons = 'image_button[3,3;1,1;transparent_button.png;dinv_recipe_ba mod.worn_items_inv = 'list[current_player;worn;9.25,4;2,4;]' +-- 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 + + +-- 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 + + +-- 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(player) if not player then return @@ -387,91 +556,50 @@ function mod.make_inventory_spec(player) end -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 - +-- 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 {} - 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 + for k, v in pairs(p) do + if v == 0 then + privs[k] = nil + else + privs[k] = v end - minetest.show_formspec(player_name, 'default:chest', default.chest.get_chest_formspec(pos, player)) 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 then + mod.wearable[k] = true + end + end +end +mod.populate_wearable_table() +minetest.after(0, function() + mod.populate_wearable_table() 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] @@ -544,6 +672,7 @@ function mod.recipe_grid(player) end +-- Return a listbox filled with items that can be crafted. function mod.recipe_list(player) if not sorted_items then sorted_items = {} @@ -577,6 +706,8 @@ function mod.recipe_list(player) 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 @@ -599,20 +730,63 @@ function mod.scroll_main(player, amount, max) end -function mod.get_main_size_by_bags(player) - local isize = 32 +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() - if mod.bag_sizes[vs] then - isize = isize + mod.bag_sizes[vs] + local it = minetest.registered_items[vs] + if it._dinv_armor then + armor = armor * it._dinv_armor end end - return isize + 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 } + player_api.set_textures(player, textures) +end + + +-- Set the size of the main inventory. function mod.set_main_size_by_bags(player) if not player then return @@ -626,35 +800,21 @@ function mod.set_main_size_by_bags(player) local prsize = pinv:get_size('main') local isize = mod.get_main_size_by_bags(player) - --[[ - if isize < prsize then - print('*** Preventing lost inventory from reducing bag sizes') + 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('*** ERROR setting inventory size.') + print(mod_name..': *** ERROR setting inventory size.') end return isize 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) - player:set_inventory_formspec(mod.make_inventory_spec(player)) -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 @@ -676,6 +836,8 @@ function mod.show_recipe(player, field) 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 @@ -700,6 +862,197 @@ function mod.switch_recipe(player, amount) 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 + 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) + player:set_inventory_formspec(mod.make_inventory_spec(player)) +end) + + +-- 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 formspec buttons/list. minetest.register_on_player_receive_fields(function(player, formname, fields) if not (player and fields) then return @@ -732,238 +1085,8 @@ minetest.register_on_player_receive_fields(function(player, formname, fields) end) -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 - - --print(dump(inventory_info.from_list), dump(inventory_info.to_list)) - --print(dump(item_from_s), dump(item_to_s)) - --print(action) - - 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 mod.bag_sizes[item_from_s] then - local prsize = mod.get_main_size_by_bags(player) - local isize = prsize - if inventory_info.to_list == worn_inv then - isize = isize + mod.bag_sizes[item_from_s] - elseif inventory_info.from_list == worn_inv then - isize = isize - mod.bag_sizes[item_from_s] - 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) - - -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 - - -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 - - -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 } - player_api.set_textures(player, textures) -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] - --print(dump(it)) - if it._dinv_armor then - armor = armor * it._dinv_armor - end - end - - print('armor = ', armor) - - local armor_g = player:get_armor_groups() - if not (armor_g and armor_g.fleshy) then - return - end - - armor_g.fleshy = armor - --print(dump(armor_g)) - player:set_armor_groups(armor_g) -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 - - +-- 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) - - -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) -end) - - -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 diff --git a/textures/anvil.png b/textures/anvil.png new file mode 100644 index 0000000000000000000000000000000000000000..2ca8b2c6ba6f26cf000dd7578d1d428ba7f96857 GIT binary patch literal 656 zcmV;B0&o3^P)O*K7GH$PH2K~*|J zRzFBxKS*9cNM1rqVna$@MNVf$PiRL`X-HCQNmFb|Q*BFCZ%kKlO;>VFSaVNUbWdA% zQ(k*kVSQI(eph0ESYv@%VRcz#fLdgITV{n_XoO#Bg|$WN?yX zag$|nlVx#~W^s*hdz^55opE=FbbzFKho^gosC8K%)%^ef00MMU zPE!DXwke^N0003CNklIAb&)- zZ>W!_S6HBrcW@v-5FuNkESaE|nw%1y5*w2c6Q7irpaw+9u4IxF9Lg3JO82 z5E0|%#iBr*Lr`8qPEkogMn#O5g$YY+unNoT7@3-y>Z?exGGUD`CTXAoa}#}OCT#MI qD6z?iR~D-pM*PyKY8V+t9smHyQ76X$KS((M0000;75P~CK1FEEEpJTu;v=L_`n?9YPD{uq*7g3Rf*BP zV%dS|9XiHBk5ds}W`3EK`F?L!!GQw@4jede;J|?c2M!!KaDU+c4e`yu(`V1szEKFi z_~Y-yyCnRpFR!kxNM~CDnQZ)3PY?{LcJg5P%SbL4YcXdvCxS3J^lvoW4>h_3jfKwY$9j4<}O; z1$my~xGpkHiKB=t^-)Tpl)^9!WSZQWzglmw_1EZzfq$v2`+LCCXU|m}h1iZu9EDi6 zL$nL%ojqVRp8?QlwYk1{g;TDO#L>R5?YI<0L6K*;o<}A#Ov_?5oltMKh@%Jq+i_Sg z<}^B8WRhT*2H|##rW?4PM-oLu!4}u6k|r^lrjuuq)^VS$zXl)*cQ|gDBnq*dGBQoj zb)Di?1%FBv*shBZ8bZ^Ef&kqx_~H+rzO|MOqg0|_ZMh{KSQQ$ZC4m0F!}yP@6dqZ`KEC6LB3S(;L*)tHY*BvHut@`85%guwR!X!ZJx zFE7Y5$$UIQHw*&brzi?EO=Gq3u^pGiWQ=7ym}ZIXdc}6V+D~MfCBp4?ub|a@hV8hF zFMnTCsW(_J=9IlEX&fPRo!x2)LXgQ6nM&etN2A>#my$-i%Y1T;Qm~keDcLqj98;;) zSkIIOZ?lEZ`Q>j)dihqJ?y@9`4((E1+?E-{WWw-HZ_fIH$HOihx zv~yhgdtbxR zE}+>xW-*=6=?@6D8@y_bB#r^@r68|XN2V!_R-2+IX!rW87jtaKAq=*ZZ2P@>fF_fK z$<-x}TP6&)3AAg|s)*L6W8m$h|E&v3p*@TKyf3F^(fAHw> z&(b8ua$Nl7oHUMD&Zbzl#b&)?vtA+7gxU27+qOxQ7=&PUeMK6_6nRdX#8ewc#Nm#> z_wiQ?D%BdB<$~SDN1+(L_8=sP8?eqG}IS9ez>hi`@*2|lZ zGr+Q)ef!nR7kkesS3HEK;kadnFaCyQJIEvfA^7WGzWn)HOW;NU$Ar58x8ji`315Ex zC-K>@e<=nJ&lx;Cr&6smcz8~dB)Aoi@b*Ma%i`+_>JHAR)atitxqnemcW{PM&}en2 z)arBxXIQpPv)j8F+d0N8S^M}`&(?8|l4Y^mZWv!)U|BZ)asj|}G$cu4CZi#ll&lvE zG$HVp3-Y31d|P&3^?#?o!FT1Ok3Uhi>(cI>kVGN7?S|E2PWNQ+we*U~)sRNBMcJ!j zIWDv7E8;LD&u@N?OfA#A`4WsHG{ay$o8o#k{`}c*@4dzYZ{eR8v(b0a8I3If0000< KMNUMnLSTYtR8mm@ delta 1666 zcmV-|27UST4Z{tPRDTNr6H>*P_W%F}P)S5VRA}DqmpP0aSsBNFRrRXt=&tInzPsn} zz<4yW){=8V)&y+AT4Gl#q>V_)kjRiAAtNLqLPA2zoq>eOkRT;RD|}ARc&5+luCBZ4 zZP2r`tc~n7gGuOL_|>cL>Amm&9S^o_*|KHJmMvShY}vA9%YT+F|8FSI8}8nFUtWDw z6z>1-m&)rn{ML8AE61lNFZ_4+-uu#Nc!cYKG>*vg992;;ESo&b5W0>Kfo3@?S`DG=lzEP#sC4>6 zM5ThFD9pzf0Dt6p{!0IOp5fFRw0eE~`Rv*XP@gwwn)ca8ReOC&sVZ5TzF?2nYqB&Y z&vP_QqbPEUEThOW+=hp47?efvO8;RHfT9ov0kSNweE}~hKv9%U^rb|~*WaMo>GAmA zM5ZiDiXz9dZL%~ajw15ZM@os55+MXxn!M7#+wfTV3x6~r(4}$x8gTdC`!bF~Ov@&Y zLJZR)S_cgF513EJ0C?>VXHOnsRcj=1bhXyBY|65vEOKneAWmid}5W}jH zr3sp*QGZ^lK*|!+wow!nMOBG{08I$)|MsJo=CUd(6s_A-~LJ zQK>LK9Z}>NuGd5pg24AF%Mw*pxsHOeG@;h;kY!2LaY^F{MblXOJ}3%#mXf6z$P%y9 zrGLnCyiSkF`5Cg51pb_gX;Ky?wR)XAO>vt|R=&?*?*>2n@sD1r08ueby2BmfD8g~; zq-jdC)5S0?8hbYYSWGAMcK4W#FX#?;SuK5rUXzQ{5dbaM1u5A(JYw|d0SCvoI6ryH z-r-FEP9FS|gX3FFo}F=Y`wp{EZdVQjGfTFsr zmp+~04ppa4)p3Z{0h-X5JUgS+>r+ZeyEhDE$3zfBE4{6`&gio&J#3(x>M1IC=DdR=0;? znlxJNO#xa5w0eD}7w2?`y9BExj(=MxiDQ6kDaffe$kG(A-JvW?I)fpL=>*fV2!j>t z)si?2d8^yUpG`3>i;L3}k|bs^onToui|Le_TgRVGDaw*(Cr{WvJi?z%UtI&R@jnnkr!yF0ST@u1vrSJ1YV|sbqJL848SB*w zy;5PYe?St2o5)!b*O(=^7XBczo4`S-t4 z-sC7Obi<(48(c*^3PTh{K}zWD?gKCzU*NU7NGa*>VBv ztpmJvmuMXT3iI*#8-ELkEPqKDpN;4Yc3945lts>bIzbZ}VX(SfCYhX{;kDYFpFF{^ zY{qA!O`ZYgqo=fb1HxcMk!74de#niZW0sc#QN=Vlef$t1bi!bTWmh>LJta#L)~n^` z{4VD+49jNn?DPvwhW{l6^aslCx^6RiW<{Q-;1Hu^t(4ZbdKzx$pvZJW+uha?JFua?ZG6M8$l|KeV9 zK03i`wW&Jpm4f0hq$oCzBVE@wlVBX73c+H0f$h}!({FyEu;tD130o~p9XWo00RR91 M07*qoM6N<$f}g`Mu>b%7 diff --git a/textures/dinv_char_diamond_plate_armor.png b/textures/dinv_char_diamond_plate_armor.png new file mode 100644 index 0000000000000000000000000000000000000000..c673a500638c9c7ad358e39bdbdf7bb934ea2750 GIT binary patch literal 1351 zcmV-N1-SZ&P)5NWhJ$b|xeATSvY07#N#rCOR{uB`y^azK)#e+NZrbxDaLaTG1ZgY$FZC?ZJ` zBuOGo6Vf;)jblocDvGL-rRhqw@+@1s0ZR%H1Y!R6^PD_iy}(w(=K17wDV}8+X_}xL z25}S-_&!NACC_v6JV%yg;wW6HmQqmH_kfFg>M|v5ey!FU93MPGH;aUUPmpV`%*oOO z!?H-?1VvSu4Ej`Rbpqd?OI6o78;__qZQ?LQR%ATKL6l?+%OdoBeAmISNMiCxxW6x~v;{7*y?c}G-J6_^N8I@MQzTht z@7C>C--4=QRjMR$f^M4hM=p_QGMM;z^Y+CW@Z0 z)o7w>`r`hx@rW?+IUNpYcDgvTDV^#TgQG)s>rqU~hLW_kyPJ{Lw>X zS)tMH@aS=GG3T;^j)%^b1=|e^NmdpLn)>;BZ-FhVfIFQ~&@{3%qgXDJL=mTM@?lN^ zyL%nGd!0OoYQ0IZT*2;MUpfUEtq!WLFZsjkXm+}&x=y3jK~dHJ+yky`K=0{edQTtY zxid!nW3n_^_`*NLVMzb*1-fD4xz1Y)dai?RnDh@{5QpJf4Tyq(asLES5D0t^-7q;m zc(#569^Bs-9^Bs-x;wjccXlb3Ds*>t3BwShXe}wAX17r_ZAl$(QkAM{)a>@!3g{p8 zNaC2Y@fcAMn4XSFSNuF)>rV>ci?6=PHN&9MzDDSKoI5in;}Q0??uGO@{lgyBS{>6W zq3Q<1<3j?^BTeT&M~b4%zXSsxQI0A literal 0 HcmV?d00001 diff --git a/textures/dinv_char_fur_cloak.png b/textures/dinv_char_fur_cloak.png new file mode 100644 index 0000000000000000000000000000000000000000..1968fdcb9f8767ae6e1226b67f061604db995d4b GIT binary patch literal 459 zcmeAS@N?(olHy`uVBq!ia0vp^4nVBH!3HE3&8=$zQfx`y?k)`fL2$v|<&%LToCO|{ z#S9F3${@^GvDCf{D9B#o>Fdh=m|codnXAt(MxTL!F~ZZuF(l*O+bgj}vkgSr9){aD z99Sq|Jvl~2{H}-ig{NhVv0ma6eC8xH=ypT5x|AB2qD%T43>zH0g%Tu?`sXF(+|GgKsY}vA9%a$!$wrtt5Wy_W= z|2Krofjf8aWy^_wL-imszDU?%W~tJ>ob<6a-Y=AdVtr zMM0Kje);~}E9-sq$*0TjYwfsM!Ns|74C`#)~N)(C0a3$`~=R{#h9LGqK zM3TfLQA83&6iQ_jRV7W5wQ6N)x^V+m6d(w~V)nC)EL*?8wOWJc< zqo^w5eveY6itjDPYP!y3G^AW_5Cs9UBIC|xh?0z9Sp=Sk=gcsy0%71IiV{g2QEj&A z9Ur}Z3Frpt3l(Hpie?xHg2?p31U!6jUs!7iTx4heCOi8#nT&?qc<%!wS?1u@?U!dk zRk2EC;wVNpP3+MSQIeQW#)N@S82C&lV?;^99u3h=lQ@d8UdVnj9N^6z5CmLjMjSM~4KS%kb>vWz&oz#=`+= zk}&F>y|Lh^cSf2djE4h~DB4KAS+>X*MIp2C7=XzOLwzd^*x5f|Xa4}*Fllsl(9Asb zcIRai$>pdtnwXZgqK;Q_aO*avWl?D~k#o7t3`~(1wF^b|-v1D*RHo8su9rjAbn?X_ zf*_K_5%bv$C6}YMdxKv05CBy-IPdp}!jS$+muj<3mZdnhP3Zf?VMxAMTv5lX7@nOV z$uf>@FW2u?7LyVb5c>Wy$KmYJ(gTW>DxTvY$?`vFqN-ABwwXYZHvnN#Q4OC5|RH-hC&mAg_CZm3jdb@)&n_?A;1ilYIy?q_u^RNmMnK@E1`K&^tatH%we-_Qry)Geb8_ddEjZL9kH+Lf>c9J3|x%e9uKUOimA;gxJ$WG#k2~jy20S| z7~geClEvjnQIy3=(Dx8!naQA!VHNrHr|&lY#w}OyCpX6(xgJ{zw*UYD07*qoM6N<$ Ef`sXInE(I) literal 0 HcmV?d00001 diff --git a/textures/dinv_char_steel_helm.png b/textures/dinv_char_steel_helm.png new file mode 100644 index 0000000000000000000000000000000000000000..117ecfbe17c42cf0b7d2fdb1fbb6ed997cd2335f GIT binary patch literal 375 zcmeAS@N?(olHy`uVBq!ia0vp^4nVBH!3HE3&8=$zQfx`y?k)`fL2$v|<&%LToCO|{ z#S9F3${@^GvDCf{D9B#o>Fdh=m|cod$4u>{O*#VuBa5etV@Srmw=)d6n+*h7^%cEu z`wFnLA6$B2XR>w4%Parwx%l{&URe89VtG@C;lw9NnfGQh&HFxAzh9%Ps(yjx)X=q^ z9d_@$ynZOa{KXEi6CWW^}Kgb|*u+=P~1spQl)V)Z9_GH`}!5!sDvT4(kN_ z&d&E~;LKQk`jb<;hl9_)p308DkFrBr& O5O})!xvX;p literal 0 HcmV?d00001 diff --git a/textures/dinv_char_steel_shield.png b/textures/dinv_char_steel_shield.png new file mode 100644 index 0000000000000000000000000000000000000000..8b96d97edd70cade639f98eeffb2d03eb369f84e GIT binary patch literal 340 zcmeAS@N?(olHy`uVBq!ia0vp^4nVBH!3HE3&8=$zQfx`y?k)`fL2$v|<&%LToCO|{ z#S9F3${@^GvDCf{D9B#o>Fdh=m|codU44D;(Kw*cLr)jSkc@k8Z`x)b3J^K=@xSGa zl)`|HC5kM^n=UNuXr8~wS=>Ic+`iRWGw+?1M__@TsXm{Th}AYHk9nK#JUsO9;c?45 z4{u%0@tc17Wd)}L1Cu}l1B(I!BL@~{!@H36FB#R(2X}q`DP_h{cQ^l<{M-2rmp=x` z+kgLRTNQozKU;fY%x>$@(1-74?3|kFsL!F<%~Y=5qr~uSckb@62TyB{Du3W@*}j>- zhB1FVw;TV<`QZyLGMv6SCsF2eG1DX+_Jj*l!xhdRPb=%4nX>b5`G0PsaINgNM3=8X P&oX$r`njxgN@xNA&qIHp literal 0 HcmV?d00001 diff --git a/textures/glass.png b/textures/glass.png new file mode 100644 index 0000000000000000000000000000000000000000..cab2229a3db23d0ec9f7b2729de3ae1eeb0c7c55 GIT binary patch literal 706 zcmV;z0zLhSP)FxBNq_5N1h{%h1`};osrp z`TG35zrytO`1}0*(9zTY000320RsaA1Ox;I1_lQQ2M7oV3JMAf3kwVk3=Itp4h{|v z4-XI!5D^g(A}BUQL_~FUb$xw(1-3Sm00018bW%=J05&{BMM_LfQBqY^R#;eCTwP#c zWoBq;X=`h4Z*XyOb8~fdb$EDrd3k$#e0+a@e}IC6goK2Ig@uKMh=_@bi;Rttlb4s6 znVhGrtgWuLy1&7}$j#8u($mx6;l%V8eEF6MAU-uVHZ}vNbZoW( zD+@EPd~7TZ`CxN*J|;#EVM!gVDq@|~LL&HWrPz2R#I3NXh}Gug_KuDU^s!bI6p_nG z!BoJ-t{I-6oDrXt>#L$r8@s8<$Tv9TSdf)p7~i)5(0rK^7$ zrWKAJrdqLa8NiUzH*$-_<_#Nrbp>4wMP);mfEern5i2VuWai)(6qbi0DD`3!<6~pf o;}Z0+%c1~1{7Upj6E?{J0JP;W^1BUnD*ylh07*qoM6N<$f~V3x0ssI2 literal 0 HcmV?d00001