code:
-- Based on 4itemnames mod by 4aiman

local wield = {}
local wieldindex = {}
local huds = {}
local dtimes = {}
local dlimit = 3  -- HUD element will be hidden after this many seconds

local hudbars_mod = minetest.get_modpath("hudbars")

local function set_hud(player)
	if not player:is_player() then return end
	local player_name = player:get_player_name()
	-- Fixed offset in config file
	local fixed = tonumber(minetest.settings:get("show_wielded_item_y_offset"))
	local off
	if fixed and fixed ~= -1 then
		-- Manual offset
		off = {x=0, y=-fixed}
	else
		-- Default offset
		off = {x=0, y=-101}

		if hudbars_mod then
			-- Tweak offset if hudbars mod was found

			local rows = math.floor((#hb.get_hudbar_identifiers()-1) / 2) + 1
			local vmargin = tonumber(minetest.settings:get("hudbars_vmargin")) or 24
			off.y = -76 - vmargin*rows
		end

		-- Dirty trick to avoid collision with Minetest's status text (e.g. “Volume changed to 0%”)
		if off.y >= -167 and off.y <= -156 then
			off.y = -181
		end
	end

	huds[player_name] = player:hud_add({
		hud_elem_type = "text",
		position = {x=0.5, y=1},
		offset = off,
		alignment = {x=0, y=0},
		number = 0xFFFFFF ,
		text = "",
	})
end

minetest.register_on_joinplayer(function(player)
	set_hud(player)

	local name = player:get_player_name()
	wield[name] = player:get_wielded_item():get_name()
	wieldindex[name] = player:get_wield_index()
end)

minetest.register_on_leaveplayer(function(player)
	local name = player:get_player_name()
	wield[name] = nil
	wieldindex[name] = nil
end)

minetest.register_globalstep(function(dtime)
	for _, player in pairs(minetest.get_connected_players()) do
		local player_name = player:get_player_name()
		local wstack = player:get_wielded_item()
		local wname = wstack:get_name()
		local windex = player:get_wield_index()

		if dtimes[player_name] and dtimes[player_name] < dlimit then
			dtimes[player_name] = dtimes[player_name] + dtime
			if dtimes[player_name] > dlimit and huds[player_name] then
				player:hud_change(huds[player_name], 'text', "")
			end
		end

		-- Update HUD when wielded item or wielded index changed
		if wname ~= wield[player_name] or windex ~= wieldindex[player_name] then
			wieldindex[player_name] = windex
			wield[player_name] = wname
			dtimes[player_name] = 0

			if huds[player_name] then

				local def = minetest.registered_items[wname]
				local meta = wstack:get_meta()

				--[[ Get description. Order of preference:
				* description from metadata
				* description from item definition
				* itemstring ]]
				local desc = meta:get_string("description")
				if (desc == nil or desc == "") and def then
					desc = def.description
				end
				if desc == nil or desc == "" then
					desc = wname
				end
				-- Cut off item description after first newline
				local firstnewline = string.find(desc, "\n")
				if firstnewline then
					desc = string.sub(desc, 1, firstnewline-1)
				end
				player:hud_change(huds[player_name], 'text', desc)
			end
		end
	end
end)


code:
name = show_wielded_item
description = Displays the name of the wielded item.
depends =
optional_depends = hudbars
author = Wuzzy
title = Show Wielded Item

repo_name: korkut/MeseCraft

license: mit


code:
#Use this setting to manually set the vertical offset of the label which shows
#the name of the wielded item. The offset is in pixels from the bottom of the
#screen.
#Set this to -1 to let the mod guess the offset automatically (recommended).
show_wielded_item_y_offset (Vertical offset of wielded item name display) int -1 -1


code:
24hr Clock [24hr_clock]
=======================

A 24hr clock with one hand.

David_G (kestral246@gmail.com)

**New:** I have updated this mod to work with the craftguide mod. *(Thanks to feedback from FreeGamers.)*

![Family Screenshot](screenshot.png "All my compass and clock mods")

Shown are all my compass and clock mods.

*Based on my hud_compass mod, which provides both a compass and a 24hr clock that can be optionally enabled and placed in any of the four corners of the player's screen.*

Crafting guide
--------------

```
              , tin_ingot   ,
  copper_ingot, glass       , copper_ingot
              , copper_ingot,
```

License
-------
- **new textures:** derived from ccompass, textures CC BY-SA by tacotexmex (changes by kestral246 also CC BY-SA)
- **code:**  My changes to original code are CC0-1.0
- **original compassgps license:** Original code by Echo, PilzAdam, and TeTpaAka is WTFPL. Kilarin (Donald Hines) changes are CC0 (No rights reserved)


code:
-- 24hr_clock
-- By David_G (kestral246@gmail.com)
--
-- 2020-02-19

local activewidth=8  -- Number of inventory slots to check.

minetest.register_globalstep(function(dtime)
	local players  = minetest.get_connected_players()
	for i,player in ipairs(players) do
		local gotaclock=false
		local wielded=false
		local activeinv=nil
		local stackidx=0
		local wielded_item = player:get_wielded_item():get_name()
		if string.sub(wielded_item, 0, 16) == "24hr_clock:clock" then
			wielded=true
			stackidx=player:get_wield_index()
			gotaclock=true
		else
			if player:get_inventory() then
				for i,stack in ipairs(player:get_inventory():get_list("main")) do
					if i<=activewidth and string.sub(stack:get_name(), 0, 16) == "24hr_clock:clock" then
						activeinv=stack
						stackidx=i
						gotaclock=true
						break
					end
				end
			end
		end
		if gotaclock then
			local clock_image = math.floor(24 * minetest.get_timeofday())

			if wielded then
				player:set_wielded_item("24hr_clock:clock"..clock_image)
			elseif activeinv then
				player:get_inventory():set_stack("main",stackidx,"24hr_clock:clock"..clock_image)
			end
		end
	end
end)

local images = {
		"24hr_clock_0.png",
		"24hr_clock_1.png",
		"24hr_clock_2.png",
		"24hr_clock_3.png",
		"24hr_clock_4.png",
		"24hr_clock_5.png",
		"24hr_clock_6.png",
		"24hr_clock_7.png",
		"24hr_clock_8.png",
		"24hr_clock_9.png",
		"24hr_clock_10.png",
		"24hr_clock_11.png",
		"24hr_clock_12.png",
		"24hr_clock_13.png",
		"24hr_clock_14.png",
		"24hr_clock_15.png",
		"24hr_clock_16.png",
		"24hr_clock_17.png",
		"24hr_clock_18.png",
		"24hr_clock_19.png",
		"24hr_clock_20.png",
		"24hr_clock_21.png",
		"24hr_clock_22.png",
		"24hr_clock_23.png",
}

local i
for i,img in ipairs(images) do
		local inv = 1
		if i == 12 then
				inv = 0
		end
		minetest.register_tool("24hr_clock:clock"..(i-1), {
				description = "24-Hour Clock",
				inventory_image = img,
				wield_image = img,
				groups = {not_in_creative_inventory=inv}
		})
end

-- crafting recipe only works if default mod present.
if minetest.get_modpath("default") ~= nil then
	minetest.register_craft({
			output = '24hr_clock:clock11',
			recipe = {
					{'', 'default:tin_ingot', ''},
					{'default:copper_ingot', 'default:glass', 'default:copper_ingot'},
					{'', 'default:copper_ingot', ''}
			}
	})
end


code:
name = 24hr_clock
description = A 24-hour clock with a single hand.
optional_depends = default


code:
name: integration-test

on: [push, pull_request]

jobs:
  build:

    runs-on: ubuntu-latest

    steps:
    - uses: actions/checkout@v1

    - name: integration-test
      run: ./integration-test.sh


code:
name: luacheck

on: [push, pull_request]

jobs:
  build:

    runs-on: ubuntu-latest

    steps:
    - uses: actions/checkout@v1
    - name: apt
      run: sudo apt-get install -y luarocks
    - name: luacheck install
      run: luarocks install --local luacheck
    - name: luacheck run
      run: $HOME/.luarocks/bin/luacheck ./


code:
## Generic ignorable patterns and files
*~
.*.swp
*bak*
tags
*.vim
armor.conf

## Eclipse project files & directories
.project
.settings


code:
unused_args = false

globals = {
	"wieldview",
	"armor",
	"inventory_plus"
}

read_globals = {
	-- Stdlib
	string = {fields = {"split"}},
	table = {fields = {"copy", "getn"}},

	-- Minetest
	"vector", "ItemStack",
	"dump", "VoxelArea",

	-- deps
	"default",
	"minetest",
	"unified_inventory",
	"wardrobe",
	"player_monoids",
	"armor_monoid",
	"sfinv",
	"ARMOR_MATERIALS",
	"ARMOR_FIRE_NODES",
	"pova",
	"skins",
	"u_skins"
}


code:
[mod] Visible Player Armor [3d_armor]
=====================================

Depends: default

Recommends: sfinv, unified_inventory or smart_inventory (use only one to avoid conflicts)

Supports: player_monoids and armor_monoid

Adds craftable armor that is visible to other players. Each armor item worn contributes to
a player's armor group level making them less vulnerable to weapons.

Armor takes damage when a player is hurt but also offers a percentage chance of healing.
Overall level is boosted by 10% when wearing a full matching set.

Fire protection added by TenPlus1 when using crystal armor if Ethereal mod active, level 1
protects against torches, level 2 for crystal spike, level 3 for fire, level 5 for lava.

Armor Configuration
-------------------

Override the following default settings by adding them to your minetest.conf file.

-- Set false to disable individual armor materials.
armor_material_wood = true
armor_material_cactus = true
armor_material_steel = true
armor_material_bronze = true
armor_material_diamond = true
armor_material_gold = true
armor_material_mithril = true
armor_material_crystal = true

-- Increase this if you get initialization glitches when a player first joins.
armor_init_delay = 2

-- Number of initialization attempts.
-- Use in conjunction with armor_init_delay if initialization problems persist.
armor_init_times = 10

-- Increase this if armor is not getting into bones due to server lag.
armor_bones_delay = 1

-- How often player armor items are updated.
armor_update_time = 1

-- Drop armor when a player dies.
-- Uses bones mod if present, otherwise items are dropped around the player.
armor_drop = true

-- Pulverise armor when a player dies, overrides armor_drop.
armor_destroy = false

-- You can use this to increase or decrease overall armor effectiveness,
-- eg: level_multiplier = 0.5 will reduce armor level by half.
armor_level_multiplier = 1

-- You can use this to increase or decrease overall armor healing,
-- eg: armor_heal_multiplier = 0 will disable healing altogether.
armor_heal_multiplier = 1

-- Enable water protection (periodically restores breath when activated)
armor_water_protect = true

-- Enable fire protection (defaults true if using ethereal mod)
armor_fire_protect = false

-- Enable punch damage effects.
armor_punch_damage = true

-- Enable migration of old armor inventories
armor_migrate_old_inventory = true

API
---

Armor Registration:

armor:register_armor(name, def)

Wrapper function for `minetest.register_tool`, while registering armor as
a tool item is still supported, this may be deprecated in future so new code
should use this method.

Additional fields supported by 3d_armor:

	texture = <filename>
	preview = <filename>
	armor_groups =

	damage_groups =

	reciprocate_damage = <bool>
	on_equip = <function>
	on_unequip = <function>
	on_destroy = <function>
	on_damage = <function>
	on_punched = <function>

armor:register_armor_group(group, base)

Example:

armor:register_armor_group("radiation", 100)

armor:register_armor("mod_name:speed_boots", {
	description = "Speed Boots",
	inventory_image = "mod_name_speed_boots_inv.png",
	texture = "mod_name_speed_boots.png",
	preview = "mod_name_speed_boots_preview.png",
	groups = {armor_feet=1, armor_use=500, physics_speed=1.2, flammable=1},
	armor_groups = {fleshy=10, radiation=10},
	damage_groups = {cracky=3, snappy=3, choppy=3, crumbly=3, level=1},
	reciprocate_damage = true,
	on_destroy = function(player, index, stack)
		local pos = player:get_pos()
		if pos then
			minetest.sound_play({
				name = "mod_name_break_sound",
				pos = pos,
				gain = 0.5,
			})
		end
	end,
})

See armor.lua, technic_armor and shields mods for more examples.

Default groups:

Elements: armor_head, armor_torso, armor_legs, armor_feet
Attributes: armor_heal, armor_fire, armor_water
Physics: physics_jump, physics_speed, physics_gravity
Durability: armor_use, flammable

Notes:

Elements may be modified by dependent mods, eg shields adds armor_shield.
Attributes and physics values are 'stackable', durability is determined
by the level of armor_use, total uses == approx (65535/armor_use), non-fleshy
damage groups need to be defined in the tool/weapon used against the player.

Reciprocal tool damage will be done only by the first armor inventory item
 with `reciprocate_damage = true`

Armor Functions:

armor:set_player_armor(player)

Primarily an internal function but can be called externally to apply any
changes that might not otherwise get handled.

armor:punch(player, hitter, time_from_last_punch, tool_capabilities)

Used to apply damage to all equipped armor based on the damage groups of
each individual item.`hitter`, `time_from_last_punch` and `tool_capabilities`
are optional but should be valid if included.

armor:damage(player, index, stack, use)

Adds wear to a single armor itemstack, triggers `on_damage` callbacks and
updates the necessary inventories. Also handles item destruction callbacks
and so should NOT be called from `on_unequip` to avoid an infinite loop.

armor:remove_all(player)

Removes all armors from the player's inventory without triggering any callback.

armor:equip(player, armor_name)

Equip the armor, removing the itemstack from the main inventory if there's one.

armor:unequip(player, armor_name)

Unequip the armor, adding the itemstack to the main inventory.

armor:update_skin(player_name)

Triggers a skin update with the same action as if a field with `skins_set` was submitted.

Item Callbacks:

on_equip = func(player, index, stack)
on_unequip = func(player, index, stack)
on_destroy = func(player, index, stack)
on_damage = func(player, index, stack)
on_punched = func(player, hitter, time_from_last_punch, tool_capabilities)

Notes:

`on_punched` is called every time a player is punched or takes damage, `hitter`,
`time_from_last_punch` and `tool_capabilities` can be `nil` and will be in the
case of fall damage, etc. When fire protection is enabled, hitter == "fire"
in the event of fire damage. Return `false` to override armor damage effects.
When armor is destroyed `stack` will contain a copy of the previous stack.

Global Callbacks:

armor:register_on_update(func(player))
armor:register_on_equip(func(player, index, stack))
armor:register_on_unequip(func(player, index, stack))
armor:register_on_destroy(func(player, index, stack))

Global Callback Example:

armor:register_on_update(function(player)
	print(player:get_player_name().." armor updated!")
end)

Note:

The player physics modifications won't be applied via `set_physics_override` if `player_physics_locked` is set to 1
in the respective player's meta.


code:
-- support for i18n
local S = minetest.get_translator(minetest.get_current_modname())

local skin_previews = {}
local use_player_monoids = minetest.global_exists("player_monoids")
local use_armor_monoid = minetest.global_exists("armor_monoid")
local use_pova_mod = minetest.get_modpath("pova")
local armor_def = setmetatable({}, {
	__index = function()
		return setmetatable({
			groups = setmetatable({}, {
				__index = function()
					return 0
				end})
			}, {
			__index = function()
				return 0
			end
		})
	end,
})
local armor_textures = setmetatable({}, {
	__index = function()
		return setmetatable({}, {
			__index = function()
				return "blank.png"
			end
		})
	end
})

armor = {
	timer = 0,
	elements = {"head", "torso", "legs", "feet"},
	physics = {"jump", "speed", "gravity"},
	attributes = {"heal", "fire", "water"},
	formspec = "model[2.5,0;2,4;armor_preview]" ..
	-- "image[2.5,0;2,4;armor_preview]"..
		default.gui_bg..
		default.gui_bg_img..
		default.gui_slots..
		default.get_hotbar_bg(0, 4.7)..
		"list[current_player;main;0,4.7;8,1;]"..
		"list[current_player;main;0,5.85;8,3;8]",
	def = armor_def,
	textures = armor_textures,
	default_skin = "character",
	materials = {
		wood = "group:wood",
		cactus = "default:cactus",
		steel = "default:steel_ingot",
		bronze = "default:bronze_ingot",
		diamond = "default:diamond",
		gold = "default:gold_ingot",
		mithril = "moreores:mithril_ingot",
		crystal = "ethereal:crystal_ingot",
	},
	fire_nodes = {
		{"default:lava_source",     5, 8},
		{"default:lava_flowing",    5, 8},
		{"fire:basic_flame",        3, 4},
		{"fire:permanent_flame",    3, 4},
		{"ethereal:crystal_spike",  2, 1},
		{"ethereal:fire_flower",    2, 1},
		{"default:torch",           1, 1},
		{"default:torch_ceiling",   1, 1},
		{"default:torch_wall",      1, 1},
	},
	registered_groups = {["fleshy"]=100},
	registered_callbacks = {
		on_update = {},
		on_equip = {},
		on_unequip = {},
		on_damage = {},
		on_destroy = {},
	},
	migrate_old_inventory = true,
  version = "0.4.13",
  get_translator = S
}

armor.config = {
	init_delay = 2,
	init_times = 10,
	bones_delay = 1,
	update_time = 1,
	drop = minetest.get_modpath("mesecraft_bones") ~= nil,
	destroy = false,
	level_multiplier = 1,
	heal_multiplier = 1,
	material_wood = true,
	material_cactus = true,
	material_steel = true,
	material_bronze = true,
	material_diamond = true,
	material_gold = true,
	material_mithril = true,
	material_crystal = true,
	water_protect = true,
	fire_protect = minetest.get_modpath("ethereal") ~= nil,
	punch_damage = true,
}

-- Armor Registration

armor.register_armor = function(self, name, def)
	def.on_secondary_use = function(itemstack, player)
		return armor:equip(player, itemstack)
	end
	def.on_place = function(itemstack, player, pointed_thing)
		if pointed_thing.type == "node" and player and not player:get_player_control().sneak then
			local node = minetest.get_node(pointed_thing.under)
			local ndef = minetest.registered_nodes[node.name]
			if ndef and ndef.on_rightclick then
				return ndef.on_rightclick(pointed_thing.under, node, player, itemstack, pointed_thing)
			end
		end
		return armor:equip(player, itemstack)
	end
	minetest.register_tool(name, def)
end

armor.register_armor_group = function(self, group, base)
	base = base or 100
	self.registered_groups[group] = base
	if use_armor_monoid then
		armor_monoid.register_armor_group(group, base)
	end
end

-- Armor callbacks

armor.register_on_update = function(self, func)
	if type(func) == "function" then
		table.insert(self.registered_callbacks.on_update, func)
	end
end

armor.register_on_equip = function(self, func)
	if type(func) == "function" then
		table.insert(self.registered_callbacks.on_equip, func)
	end
end

armor.register_on_unequip = function(self, func)
	if type(func) == "function" then
		table.insert(self.registered_callbacks.on_unequip, func)
	end
end

armor.register_on_damage = function(self, func)
	if type(func) == "function" then
		table.insert(self.registered_callbacks.on_damage, func)
	end
end

armor.register_on_destroy = function(self, func)
	if type(func) == "function" then
		table.insert(self.registered_callbacks.on_destroy, func)
	end
end

armor.run_callbacks = function(self, callback, player, index, stack)
	if stack then
		local def = stack:get_definition() or {}
		if type(def[callback]) == "function" then
			def[callback](player, index, stack)
		end
	end
	local callbacks = self.registered_callbacks[callback]
	if callbacks then
		for _, func in pairs(callbacks) do
			func(player, index, stack)
		end
	end
end

armor.update_player_visuals = function(self, player)
	if not player then
		return
	end
	local name = player:get_player_name()
	if self.textures[name] then
		default.player_set_textures(player, {
			self.textures[name].skin,
			self.textures[name].armor,
			self.textures[name].wielditem,
		})
	end
	self:run_callbacks("on_update", player)
end

armor.set_player_armor = function(self, player)
	local name, armor_inv = self:get_valid_player(player, "[set_player_armor]")
	if not name then
		return
	end
	local state = 0
	local count = 0
	local material = {count=1}
	local preview = armor:get_preview(name)
	local texture = "3d_armor_trans.png"
	local physics = {}
	local attributes = {}
	local levels = {}
	local groups = {}
	local change = {}
	for _, phys in pairs(self.physics) do
		physics[phys] = 1
	end
	for _, attr in pairs(self.attributes) do
		attributes[attr] = 0
	end
	for group, _ in pairs(self.registered_groups) do
		change[group] = 1
		levels[group] = 0
	end
	local list = armor_inv:get_list("armor")
	if type(list) ~= "table" then
		return
	end
	for i, stack in pairs(list) do
		if stack:get_count() == 1 then
			local def = stack:get_definition()
			for _, element in pairs(self.elements) do
				if def.groups["armor_"..element] then
					if def.armor_groups then
						for group, level in pairs(def.armor_groups) do
							if levels[group] then
								levels[group] = levels[group] + level
							end
						end
					else
						local level = def.groups["armor_"..element]
						levels["fleshy"] = levels["fleshy"] + level
					end
					break
				end
				-- DEPRECATED, use armor_groups instead
				if def.groups["armor_radiation"] and levels["radiation"] then
					levels["radiation"] = def.groups["armor_radiation"]
				end
			end
			local item = stack:get_name()
			local tex = def.texture or item:gsub("%:", "_")
			tex = tex:gsub(".png$", "")
			local prev = def.preview or tex.."_preview"
			prev = prev:gsub(".png$", "")
			texture = texture.."^"..tex..".png"
			preview = preview.."^"..prev..".png"
			state = state + stack:get_wear()
			count = count + 1
			for _, phys in pairs(self.physics) do
				local value = def.groups["physics_"..phys] or 0
				physics[phys] = physics[phys] + value
			end
			for _, attr in pairs(self.attributes) do
				local value = def.groups["armor_"..attr] or 0
				attributes[attr] = attributes[attr] + value
			end
			local mat = string.match(item, "%:.+_(.+)$")
			if material.name then
				if material.name == mat then
					material.count = material.count + 1
				end
			else
				material.name = mat
			end
		end
	end
	for group, level in pairs(levels) do
		if level > 0 then
			level = level * armor.config.level_multiplier
			if material.name and material.count == #self.elements then
				level = level * 1.1
			end
		end
		local base = self.registered_groups[group]
		self.def[name].groups[group] = level
		if level > base then
			level = base
		end
		groups[group] = base - level
		change[group] = groups[group] / base
	end
	for _, attr in pairs(self.attributes) do
		local mult = attr == "heal" and self.config.heal_multiplier or 1
		self.def[name][attr] = attributes[attr] * mult
	end
	for _, phys in pairs(self.physics) do
		self.def[name][phys] = physics[phys]
	end
	if use_armor_monoid then
		armor_monoid.monoid:add_change(player, change, "3d_armor:armor")
	else
		-- Preserve immortal group (damage disabled for player)
		local immortal = player:get_armor_groups().immortal
		if immortal and immortal ~= 0 then
			groups.immortal = 1
		end
		player:set_armor_groups(groups)
	end
	if use_player_monoids then
		player_monoids.speed:add_change(player, physics.speed,
			"3d_armor:physics")
		player_monoids.jump:add_change(player, physics.jump,
			"3d_armor:physics")
		player_monoids.gravity:add_change(player, physics.gravity,
			"3d_armor:physics")
	elseif use_pova_mod then
		-- only add the changes, not the default 1.0 for each physics setting
		pova.add_override(name, "3d_armor", {
			speed = physics.speed - 1,
			jump = physics.jump - 1,
			gravity = physics.gravity - 1,
		})
		pova.do_override(player)
	else
		local player_physics_locked = player:get_meta():get_int("player_physics_locked")
		if player_physics_locked == nil or player_physics_locked == 0 then
			player:set_physics_override(physics)
		end
	end
	self.textures[name].armor = texture
	self.textures[name].preview = preview
	self.def[name].level = self.def[name].groups.fleshy or 0
	self.def[name].state = state
	self.def[name].count = count
	self:update_player_visuals(player)
end

armor.punch = function(self, player, hitter, time_from_last_punch, tool_capabilities)
	local name, armor_inv = self:get_valid_player(player, "[punch]")
	if not name then
		return
	end
	local set_state
	local set_count
	local state = 0
	local count = 0
	local recip = true
	local default_groups = {cracky=3, snappy=3, choppy=3, crumbly=3, level=1}
	local list = armor_inv:get_list("armor")
	for i, stack in pairs(list) do
		if stack:get_count() == 1 then
			local itemname = stack:get_name()
			local use = minetest.get_item_group(itemname, "armor_use") or 0
			local damage = use > 0
			local def = stack:get_definition() or {}
			if type(def.on_punched) == "function" then
				damage = def.on_punched(player, hitter, time_from_last_punch,
					tool_capabilities) ~= false and damage == true
			end
			if damage == true and tool_capabilities then
				local damage_groups = def.damage_groups or default_groups
				local level = damage_groups.level or 0
				local groupcaps = tool_capabilities.groupcaps or {}
				local uses = 0
				damage = false
				for group, caps in pairs(groupcaps) do
					local maxlevel = caps.maxlevel or 0
					local diff = maxlevel - level
					if diff == 0 then
						diff = 1
					end
					if diff > 0 and caps.times then
						local group_level = damage_groups[group]
						if group_level then
							local time = caps.times[group_level]
							if time then
								local dt = time_from_last_punch or 0
								if dt > time / diff then
									if caps.uses then
										uses = caps.uses * math.pow(3, diff)
									end
									damage = true
									break
								end
							end
						end
					end
				end
				if damage == true and recip == true and hitter and
						def.reciprocate_damage == true and uses > 0 then
					local item = hitter:get_wielded_item()
					if item and item:get_name() ~= "" then
						item:add_wear(65535 / uses)
						hitter:set_wielded_item(item)
					end
					-- reciprocate tool damage only once
					recip = false
				end
			end
			if damage == true and hitter == "fire" then
				damage = minetest.get_item_group(itemname, "flammable") > 0
			end
			if damage == true then
				self:damage(player, i, stack, use)
				set_state = self.def[name].state
				set_count = self.def[name].count
			end
			state = state + stack:get_wear()
			count = count + 1
		end
	end
	if set_count and set_count ~= count then
		state = set_state or state
		count = set_count or count
	end
	self.def[name].state = state
	self.def[name].count = count
end

armor.damage = function(self, player, index, stack, use)
	local old_stack = ItemStack(stack)
	stack:add_wear(use)
	self:run_callbacks("on_damage", player, index, stack)
	self:set_inventory_stack(player, index, stack)
	if stack:get_count() == 0 then
		self:run_callbacks("on_unequip", player, index, old_stack)
		self:run_callbacks("on_destroy", player, index, old_stack)
		self:set_player_armor(player)
	end
end

armor.get_weared_armor_elements = function(self, player)
    local name, inv = self:get_valid_player(player, "[get_weared_armor]")
	local weared_armor = {}
	if not name then
		return
	end
    for i=1, inv:get_size("armor") do
        local item_name = inv:get_stack("armor", i):get_name()
        local element = self:get_element(item_name)
        if element ~= nil then
            weared_armor[element] = item_name
        end
	end
	return weared_armor
end

armor.equip = function(self, player, itemstack)
    local name, armor_inv = self:get_valid_player(player, "[equip]")
    local weared_armor = self:get_weared_armor_elements(player)
    local armor_element = self:get_element(itemstack:get_name())
	if name and armor_element then
		if weared_armor[armor_element] ~= nil then
			self:unequip(player, armor_element)
		end
		armor_inv:add_item("armor", itemstack:take_item())
		self:set_player_armor(player)
		self:save_armor_inventory(player)
	end
	return itemstack
end

armor.unequip = function(self, player, armor_element)
    local name, armor_inv = self:get_valid_player(player, "[unequip]")
	local weared_armor = self:get_weared_armor_elements(player)
	if not name or not weared_armor[armor_element] then
		return
	end
	local itemstack = armor_inv:remove_item("armor", ItemStack(weared_armor[armor_element]))
	minetest.after(0, function()
		local inv = player:get_inventory()
		if inv:room_for_item("main", itemstack) then
			inv:add_item("main", itemstack)
		else
			minetest.add_item(player:get_pos(), itemstack)
		end
	end)
    self:set_player_armor(player)
	self:save_armor_inventory(player)
end

armor.remove_all = function(self, player)
    local name, inv = self:get_valid_player(player, "[remove_all]")
	if not name then
		return
    end
	inv:set_list("armor", {})
	self:set_player_armor(player)
	self:save_armor_inventory(player)
end

armor.get_player_skin = function(self, name)
	if (self.skin_mod == "skins" or self.skin_mod == "simple_skins") and skins.skins[name] then
		return skins.skins[name]..".png"
	elseif self.skin_mod == "u_skins" and u_skins.u_skins[name] then
		return u_skins.u_skins[name]..".png"
	elseif self.skin_mod == "wardrobe" and wardrobe.playerSkins and wardrobe.playerSkins[name] then
		return wardrobe.playerSkins[name]
	end
	return armor.default_skin..".png"
end

armor.update_skin = function(self, name)
	minetest.after(0, function()
		local pplayer = minetest.get_player_by_name(name)
		if pplayer then
			self.textures[name].skin = self:get_player_skin(name)
			self:set_player_armor(pplayer)
		end
	end)
end

armor.add_preview = function(self, preview)
	skin_previews[preview] = true
end

armor.get_preview = function(self, name)
	local preview = string.gsub(armor:get_player_skin(name), ".png", "_preview.png")
	if skin_previews[preview] then
		return preview
	end
	return "character_preview.png"
end

armor.get_armor_formspec = function(self, name, listring)
	if armor.def[name].init_time == 0 then
		return "label[0,0;Armor not initialized!]"
	end
	local formspec = armor.formspec..
		"list[detached:"..name.."_armor;armor;0,0.5;2,3;]"
	if listring == true then
		formspec = formspec.."listring[current_player;main]"..
			"listring[detached:"..name.."_armor;armor]"
	end
	-- formspec = formspec:gsub("armor_preview", armor.textures[name].preview)
	local player = minetest.get_player_by_name(name)
	local anim = player:get_local_animation()
	local player_model = table.concat({
		"player_model_"..name,
		player:get_properties().mesh,
		table.concat(player:get_properties().textures,","),
		table.concat({0,-150},","),
		"false",
		"true",
		table.concat({anim.x,anim.y},","),
		"30"
	},";")
	formspec = formspec:gsub("armor_preview",player_model)
	formspec = formspec:gsub("armor_level", armor.def[name].level)
	for _, attr in pairs(self.attributes) do
		formspec = formspec:gsub("armor_attr_"..attr, armor.def[name][attr])
	end
	for group, _ in pairs(self.registered_groups) do
		formspec = formspec:gsub("armor_group_"..group,
			armor.def[name].groups[group])
	end
	return formspec
end

armor.get_element = function(self, item_name)
	for _, element in pairs(armor.elements) do
		if minetest.get_item_group(item_name, "armor_"..element) > 0 then
			return element
		end
	end
end

armor.serialize_inventory_list = function(self, list)
	local list_table = {}
	for _, stack in ipairs(list) do
		table.insert(list_table, stack:to_string())
	end
	return minetest.serialize(list_table)
end

armor.deserialize_inventory_list = function(self, list_string)
	local list_table = minetest.deserialize(list_string)
	local list = {}
	for _, stack in ipairs(list_table or {}) do
		table.insert(list, ItemStack(stack))
	end
	return list
end

armor.load_armor_inventory = function(self, player)
	local _, inv = self:get_valid_player(player, "[load_armor_inventory]")
	if inv then
		local meta = player:get_meta()
		local armor_list_string = meta:get_string("3d_armor_inventory")
		if armor_list_string then
			inv:set_list("armor",
				self:deserialize_inventory_list(armor_list_string))
			return true
		end
	end
end

armor.save_armor_inventory = function(self, player)
	local _, inv = self:get_valid_player(player, "[save_armor_inventory]")
	if inv then
		local meta = player:get_meta()
		meta:set_string("3d_armor_inventory",
			self:serialize_inventory_list(inv:get_list("armor")))
	end
end

armor.update_inventory = function(self, player)
	-- DEPRECATED: Legacy inventory support
end

armor.set_inventory_stack = function(self, player, i, stack)
	local _, inv = self:get_valid_player(player, "[set_inventory_stack]")
	if inv then
		inv:set_stack("armor", i, stack)
		self:save_armor_inventory(player)
	end
end

armor.get_valid_player = function(self, player, msg)
	msg = msg or ""
	if not player then
		minetest.log("warning", S("3d_armor: Player reference is nil @1", msg))
		return
	end
	local name = player:get_player_name()
	if not name then
		minetest.log("warning", S("3d_armor: Player name is nil @1", msg))
		return
	end
	local inv = minetest.get_inventory({type="detached", name=name.."_armor"})
	if not inv then
		minetest.log("warning", S("3d_armor: Detached armor inventory is nil @1", msg))
		return
	end
	return name, inv
end

armor.drop_armor = function(pos, stack)
	local node = minetest.get_node_or_nil(pos)
	if node then
		local obj = minetest.add_item(pos, stack)
		if obj then
			obj:set_velocity({x=math.random(-1, 1), y=5, z=math.random(-1, 1)})
		end
	end
end


code:
-- DEPRECATED, will not be supported in future versions

-- See README.txt for new configuration options.

-- Armor Configuration (defaults)

-- You can remove any unwanted armor materials from this table.
-- Note that existing armor that is removed will show up as an unknown item.
ARMOR_MATERIALS = {
	wood = "group:wood",
	cactus = "default:cactus",
	steel = "default:steel_ingot",
	bronze = "default:bronze_ingot",
	diamond = "default:diamond",
	gold = "default:gold_ingot",
	mithril = "moreores:mithril_ingot",
	crystal = "ethereal:crystal_ingot",
}

-- Enable fire protection (defaults true if using ethereal mod)
ARMOR_FIRE_PROTECT = false

-- Fire protection nodes, (name, protection level, damage)
ARMOR_FIRE_NODES = {
	{"default:lava_source",     5, 4},
	{"default:lava_flowing",    5, 4},
	{"fire:basic_flame",        3, 4},
	{"fire:permanent_flame",    3, 4},
	{"ethereal:crystal_spike",  2, 1},
	{"ethereal:fire_flower",    2, 1},
	{"default:torch",           1, 1},
}

-- Increase this if you get initialization glitches when a player first joins.
ARMOR_INIT_DELAY = 1

-- Number of initialization attempts.
-- Use in conjunction with ARMOR_INIT_DELAY if initialization problems persist.
ARMOR_INIT_TIMES = 1

-- Increase this if armor is not getting into bones due to server lag.
ARMOR_BONES_DELAY = 1

-- How often player armor/wield items are updated.
ARMOR_UPDATE_TIME = 1

-- Drop armor when a player dies.
-- Uses bones mod if present, otherwise items are dropped around the player.
ARMOR_DROP = true

-- Pulverise armor when a player dies, overrides ARMOR_DROP.
ARMOR_DESTROY = false

-- You can use this to increase or decrease overall armor effectiveness,
-- eg: ARMOR_LEVEL_MULTIPLIER = 0.5 will reduce armor level by half.
ARMOR_LEVEL_MULTIPLIER = 1

-- You can use this to increase or decrease overall armor healing,
-- eg: ARMOR_HEAL_MULTIPLIER = 0 will disable healing altogether.
ARMOR_HEAL_MULTIPLIER = 1

-- You can use this to increase or decrease overall armor radiation protection,
-- eg: ARMOR_RADIATION_MULTIPLIER = 0 will completely disable radiation protection.
-- Note: patched technic mod is required
ARMOR_RADIATION_MULTIPLIER = 1


code:
-- support for i18n
local S = armor.get_translator

armor:register_armor("3d_armor:helmet_admin", {
	description = S("Admin Helmet"),
	inventory_image = "3d_armor_inv_helmet_admin.png",
	armor_groups = {fleshy=100},
	groups = {armor_head=1, armor_heal=100, armor_use=0, armor_water=1,
			not_in_creative_inventory=1},
	on_drop = function(itemstack, dropper, pos)
		return
	end,
})

armor:register_armor("3d_armor:chestplate_admin", {
	description = S("Admin Chestplate"),
	inventory_image = "3d_armor_inv_chestplate_admin.png",
	armor_groups = {fleshy=100},
	groups = {armor_torso=1, armor_heal=100, armor_use=0,
			not_in_creative_inventory=1},
	on_drop = function(itemstack, dropper, pos)
		return
	end,
})

armor:register_armor("3d_armor:leggings_admin", {
	description = S("Admin Leggings"),
	inventory_image = "3d_armor_inv_leggings_admin.png",
	armor_groups = {fleshy=100},
	groups = {armor_legs=1, armor_heal=100, armor_use=0,
			not_in_creative_inventory=1},
	on_drop = function(itemstack, dropper, pos)
		return
	end,
})

armor:register_armor("3d_armor:boots_admin", {
	description = S("Admin Boots"),
	inventory_image = "3d_armor_inv_boots_admin.png",
	armor_groups = {fleshy=100},
	groups = {armor_feet=1, armor_heal=100, armor_use=0,
			not_in_creative_inventory=1},
	on_drop = function(itemstack, dropper, pos)
		return
	end,
})

minetest.register_alias("adminboots", "3d_armor:boots_admin")
minetest.register_alias("adminhelmet", "3d_armor:helmet_admin")
minetest.register_alias("adminchestplate", "3d_armor:chestplate_admin")
minetest.register_alias("adminleggings", "3d_armor:leggings_admin")

if armor.materials.wood then
	armor:register_armor("3d_armor:helmet_wood", {
		description = S("Wood Helmet"),
		inventory_image = "3d_armor_inv_helmet_wood.png",
		groups = {armor_head=1, armor_heal=0, armor_use=2000, flammable=1},
		armor_groups = {fleshy=5},
		damage_groups = {cracky=3, snappy=2, choppy=3, crumbly=2, level=1},
	})
	armor:register_armor("3d_armor:chestplate_wood", {
		description = S("Wood Chestplate"),
		inventory_image = "3d_armor_inv_chestplate_wood.png",
		groups = {armor_torso=1, armor_heal=0, armor_use=2000, flammable=1},
		armor_groups = {fleshy=10},
		damage_groups = {cracky=3, snappy=2, choppy=3, crumbly=2, level=1},
	})
	armor:register_armor("3d_armor:leggings_wood", {
		description = S("Wood Leggings"),
		inventory_image = "3d_armor_inv_leggings_wood.png",
		groups = {armor_legs=1, armor_heal=0, armor_use=2000, flammable=1},
		armor_groups = {fleshy=10},
		damage_groups = {cracky=3, snappy=2, choppy=3, crumbly=2, level=1},
	})
	armor:register_armor("3d_armor:boots_wood", {
		description = S("Wood Boots"),
		inventory_image = "3d_armor_inv_boots_wood.png",
		armor_groups = {fleshy=5},
		damage_groups = {cracky=3, snappy=2, choppy=3, crumbly=2, level=1},
		groups = {armor_feet=1, armor_heal=0, armor_use=2000, flammable=1},
	})
	local wood_armor_fuel = {
		helmet = 6,
		chestplate = 8,
		leggings = 7,
		boots = 5
	}
	for armor, burn in pairs(wood_armor_fuel) do
		minetest.register_craft({
			type = "fuel",
			recipe = "3d_armor:" .. armor .. "_wood",
			burntime = burn,
		})
	end
end

if armor.materials.cactus then
	armor:register_armor("3d_armor:helmet_cactus", {
		description = S("Cactus Helmet"),
		inventory_image = "3d_armor_inv_helmet_cactus.png",
		groups = {armor_head=1, armor_heal=0, armor_use=1000},
		armor_groups = {fleshy=5},
		damage_groups = {cracky=3, snappy=3, choppy=2, crumbly=2, level=1},
	})
	armor:register_armor("3d_armor:chestplate_cactus", {
		description = S("Cactus Chestplate"),
		inventory_image = "3d_armor_inv_chestplate_cactus.png",
		groups = {armor_torso=1, armor_heal=0, armor_use=1000},
		armor_groups = {fleshy=10},
		damage_groups = {cracky=3, snappy=3, choppy=2, crumbly=2, level=1},
	})
	armor:register_armor("3d_armor:leggings_cactus", {
		description = S("Cactus Leggings"),
		inventory_image = "3d_armor_inv_leggings_cactus.png",
		groups = {armor_legs=1, armor_heal=0, armor_use=1000},
		armor_groups = {fleshy=10},
		damage_groups = {cracky=3, snappy=3, choppy=2, crumbly=2, level=1},
	})
	armor:register_armor("3d_armor:boots_cactus", {
		description = S("Cactus Boots"),
		inventory_image = "3d_armor_inv_boots_cactus.png",
		groups = {armor_feet=1, armor_heal=0, armor_use=1000},
		armor_groups = {fleshy=5},
		damage_groups = {cracky=3, snappy=3, choppy=2, crumbly=2, level=1},
	})
	local cactus_armor_fuel = {
		helmet = 14,
		chestplate = 16,
		leggings = 15,
		boots = 13
	}
	for armor, burn in pairs(cactus_armor_fuel) do
		minetest.register_craft({
			type = "fuel",
			recipe = "3d_armor:" .. armor .. "_cactus",
			burntime = burn,
		})
	end
end

if armor.materials.steel then
	armor:register_armor("3d_armor:helmet_steel", {
		description = S("Steel Helmet"),
		inventory_image = "3d_armor_inv_helmet_steel.png",
		groups = {armor_head=1, armor_heal=0, armor_use=800,
			physics_speed=-0.01, physics_gravity=0.01},
		armor_groups = {fleshy=10},
		damage_groups = {cracky=2, snappy=3, choppy=2, crumbly=1, level=2},
	})
	armor:register_armor("3d_armor:chestplate_steel", {
		description = S("Steel Chestplate"),
		inventory_image = "3d_armor_inv_chestplate_steel.png",
		groups = {armor_torso=1, armor_heal=0, armor_use=800,
			physics_speed=-0.04, physics_gravity=0.04},
		armor_groups = {fleshy=15},
		damage_groups = {cracky=2, snappy=3, choppy=2, crumbly=1, level=2},
	})
	armor:register_armor("3d_armor:leggings_steel", {
		description = S("Steel Leggings"),
		inventory_image = "3d_armor_inv_leggings_steel.png",
		groups = {armor_legs=1, armor_heal=0, armor_use=800,
			physics_speed=-0.03, physics_gravity=0.03},
		armor_groups = {fleshy=15},
		damage_groups = {cracky=2, snappy=3, choppy=2, crumbly=1, level=2},
	})
	armor:register_armor("3d_armor:boots_steel", {
		description = S("Steel Boots"),
		inventory_image = "3d_armor_inv_boots_steel.png",
		groups = {armor_feet=1, armor_heal=0, armor_use=800,
			physics_speed=-0.01, physics_gravity=0.01},
		armor_groups = {fleshy=10},
		damage_groups = {cracky=2, snappy=3, choppy=2, crumbly=1, level=2},
	})
end

if armor.materials.bronze then
	armor:register_armor("3d_armor:helmet_bronze", {
		description = S("Bronze Helmet"),
		inventory_image = "3d_armor_inv_helmet_bronze.png",
		groups = {armor_head=1, armor_heal=6, armor_use=400,
			physics_speed=-0.01, physics_gravity=0.01},
		armor_groups = {fleshy=10},
		damage_groups = {cracky=3, snappy=2, choppy=2, crumbly=1, level=2},
	})
	armor:register_armor("3d_armor:chestplate_bronze", {
		description = S("Bronze Chestplate"),
		inventory_image = "3d_armor_inv_chestplate_bronze.png",
		groups = {armor_torso=1, armor_heal=6, armor_use=400,
			physics_speed=-0.04, physics_gravity=0.04},
		armor_groups = {fleshy=15},
		damage_groups = {cracky=3, snappy=2, choppy=2, crumbly=1, level=2},
	})
	armor:register_armor("3d_armor:leggings_bronze", {
		description = S("Bronze Leggings"),
		inventory_image = "3d_armor_inv_leggings_bronze.png",
		groups = {armor_legs=1, armor_heal=6, armor_use=400,
			physics_speed=-0.03, physics_gravity=0.03},
		armor_groups = {fleshy=15},
		damage_groups = {cracky=3, snappy=2, choppy=2, crumbly=1, level=2},
	})
	armor:register_armor("3d_armor:boots_bronze", {
		description = S("Bronze Boots"),
		inventory_image = "3d_armor_inv_boots_bronze.png",
		groups = {armor_feet=1, armor_heal=6, armor_use=400,
			physics_speed=-0.01, physics_gravity=0.01},
		armor_groups = {fleshy=10},
		damage_groups = {cracky=3, snappy=2, choppy=2, crumbly=1, level=2},
	})
end

if armor.materials.diamond then
	armor:register_armor("3d_armor:helmet_diamond", {
		description = S("Diamond Helmet"),
		inventory_image = "3d_armor_inv_helmet_diamond.png",
		groups = {armor_head=1, armor_heal=12, armor_use=200},
		armor_groups = {fleshy=15},
		damage_groups = {cracky=2, snappy=1, choppy=1, level=3},
	})
	armor:register_armor("3d_armor:chestplate_diamond", {
		description = S("Diamond Chestplate"),
		inventory_image = "3d_armor_inv_chestplate_diamond.png",
		groups = {armor_torso=1, armor_heal=12, armor_use=200},
		armor_groups = {fleshy=20},
		damage_groups = {cracky=2, snappy=1, choppy=1, level=3},
	})
	armor:register_armor("3d_armor:leggings_diamond", {
		description = S("Diamond Leggings"),
		inventory_image = "3d_armor_inv_leggings_diamond.png",
		groups = {armor_legs=1, armor_heal=12, armor_use=200},
		armor_groups = {fleshy=20},
		damage_groups = {cracky=2, snappy=1, choppy=1, level=3},
	})
	armor:register_armor("3d_armor:boots_diamond", {
		description = S("Diamond Boots"),
		inventory_image = "3d_armor_inv_boots_diamond.png",
		groups = {armor_feet=1, armor_heal=12, armor_use=200},
		armor_groups = {fleshy=15},
		damage_groups = {cracky=2, snappy=1, choppy=1, level=3},
	})
end

if armor.materials.gold then
	armor:register_armor("3d_armor:helmet_gold", {
		description = S("Gold Helmet"),
		inventory_image = "3d_armor_inv_helmet_gold.png",
		groups = {armor_head=1, armor_heal=6, armor_use=300,
			physics_speed=-0.02, physics_gravity=0.02},
		armor_groups = {fleshy=10},
		damage_groups = {cracky=1, snappy=2, choppy=2, crumbly=3, level=2},
	})
	armor:register_armor("3d_armor:chestplate_gold", {
		description = S("Gold Chestplate"),
		inventory_image = "3d_armor_inv_chestplate_gold.png",
		groups = {armor_torso=1, armor_heal=6, armor_use=300,
			physics_speed=-0.05, physics_gravity=0.05},
		armor_groups = {fleshy=15},
		damage_groups = {cracky=1, snappy=2, choppy=2, crumbly=3, level=2},
	})
	armor:register_armor("3d_armor:leggings_gold", {
		description = S("Gold Leggings"),
		inventory_image = "3d_armor_inv_leggings_gold.png",
		groups = {armor_legs=1, armor_heal=6, armor_use=300,
			physics_speed=-0.04, physics_gravity=0.04},
		armor_groups = {fleshy=15},
		damage_groups = {cracky=1, snappy=2, choppy=2, crumbly=3, level=2},
	})
	armor:register_armor("3d_armor:boots_gold", {
		description = S("Gold Boots"),
		inventory_image = "3d_armor_inv_boots_gold.png",
		groups = {armor_feet=1, armor_heal=6, armor_use=300,
			physics_speed=-0.02, physics_gravity=0.02},
		armor_groups = {fleshy=10},
		damage_groups = {cracky=1, snappy=2, choppy=2, crumbly=3, level=2},
	})
end

if armor.materials.mithril then
	armor:register_armor("3d_armor:helmet_mithril", {
		description = S("Mithril Helmet"),
		inventory_image = "3d_armor_inv_helmet_mithril.png",
		groups = {armor_head=1, armor_heal=12, armor_use=100},
		armor_groups = {fleshy=15},
		damage_groups = {cracky=2, snappy=1, level=3},
	})
	armor:register_armor("3d_armor:chestplate_mithril", {
		description = S("Mithril Chestplate"),
		inventory_image = "3d_armor_inv_chestplate_mithril.png",
		groups = {armor_torso=1, armor_heal=12, armor_use=100},
		armor_groups = {fleshy=20},
		damage_groups = {cracky=2, snappy=1, level=3},
	})
	armor:register_armor("3d_armor:leggings_mithril", {
		description = S("Mithril Leggings"),
		inventory_image = "3d_armor_inv_leggings_mithril.png",
		groups = {armor_legs=1, armor_heal=12, armor_use=100},
		armor_groups = {fleshy=20},
		damage_groups = {cracky=2, snappy=1, level=3},
	})
	armor:register_armor("3d_armor:boots_mithril", {
		description = S("Mithril Boots"),
		inventory_image = "3d_armor_inv_boots_mithril.png",
		groups = {armor_feet=1, armor_heal=12, armor_use=100},
		armor_groups = {fleshy=15},
		damage_groups = {cracky=2, snappy=1, level=3},
	})
end

if armor.materials.crystal then
	armor:register_armor("3d_armor:helmet_crystal", {
		description = S("Crystal Helmet"),
		inventory_image = "3d_armor_inv_helmet_crystal.png",
		groups = {armor_head=1, armor_heal=12, armor_use=100, armor_fire=1},
		armor_groups = {fleshy=15},
		damage_groups = {cracky=2, snappy=1, level=3},
	})
	armor:register_armor("3d_armor:chestplate_crystal", {
		description = S("Crystal Chestplate"),
		inventory_image = "3d_armor_inv_chestplate_crystal.png",
		groups = {armor_torso=1, armor_heal=12, armor_use=100, armor_fire=1},
		armor_groups = {fleshy=20},
		damage_groups = {cracky=2, snappy=1, level=3},
	})
	armor:register_armor("3d_armor:leggings_crystal", {
		description = S("Crystal Leggings"),
		inventory_image = "3d_armor_inv_leggings_crystal.png",
		groups = {armor_legs=1, armor_heal=12, armor_use=100, armor_fire=1},
		armor_groups = {fleshy=20},
		damage_groups = {cracky=2, snappy=1, level=3},
	})
	armor:register_armor("3d_armor:boots_crystal", {
		description = S("Crystal Boots"),
		inventory_image = "3d_armor_inv_boots_crystal.png",
		groups = {armor_feet=1, armor_heal=12, armor_use=100, physics_speed=1,
				physics_jump=0.5, armor_fire=1},
		armor_groups = {fleshy=15},
		damage_groups = {cracky=2, snappy=1, level=3},
	})
end

for k, v in pairs(armor.materials) do
	minetest.register_craft({
		output = "3d_armor:helmet_"..k,
		recipe = {
			{v, v, v},
			{v, "", v},
			{"", "", ""},
		},
	})
	minetest.register_craft({
		output = "3d_armor:chestplate_"..k,
		recipe = {
			{v, "", v},
			{v, v, v},
			{v, v, v},
		},
	})
	minetest.register_craft({
		output = "3d_armor:leggings_"..k,
		recipe = {
			{v, v, v},
			{v, "", v},
			{v, "", v},
		},
	})
	minetest.register_craft({
		output = "3d_armor:boots_"..k,
		recipe = {
			{v, "", v},
			{v, "", v},
		},
	})
end


code:
3d_armor -- Crafting Guide
--------------------------

Helmets:

+---+---+---+
| X | X | X |
+---+---+---+
| X |   | X |
+---+---+---+
|   |   |   |
+---+---+---+

[3d_armor:helmet_wood] X = [default:wood]
[3d_armor:helmet_cactus] X = [default:cactus]
[3d_armor:helmet_steel] X = [default:steel_ingot]
[3d_armor:helmet_bronze] X = [default:bronze_ingot]
[3d_armor:helmet_diamond] X = [default:diamond]
[3d_armor:helmet_gold] X = [default:gold_ingot]
[3d_armor:helmet_mithril] X = [moreores:mithril_ingot] *
[3d_armor:helmet_crystal] X = [ethereal:crystal_ingot] **

Chestplates:

+---+---+---+
| X |   | X |
+---+---+---+
| X | X | X |
+---+---+---+
| X | X | X |
+---+---+---+

[3d_armor:chestplate_wood] X = [default:wood]
[3d_armor:chestplate_cactus] X = [default:cactus]
[3d_armor:chestplate_steel] X = [default:steel_ingot]
[3d_armor:chestplate_bronze] X = [default:bronze_ingot]
[3d_armor:chestplate_diamond] X = [default:diamond]
[3d_armor:chestplate_gold] X = [default:gold_ingot]
[3d_armor:chestplate_mithril] X = [moreores:mithril_ingot] *
[3d_armor:chestplate_crystal] X = [ethereal:crystal_ingot] **

Leggings:

+---+---+---+
| X | X | X |
+---+---+---+
| X |   | X |
+---+---+---+
| X |   | X |
+---+---+---+

[3d_armor:leggings_wood] X = [default:wood]
[3d_armor:leggings_cactus] X = [default:cactus]
[3d_armor:leggings_steel] X = [default:steel_ingot]
[3d_armor:leggings_bronze] X = [default:bronze_ingot]
[3d_armor:leggings_diamond] X = [default:diamond]
[3d_armor:leggings_gold] X = [default:gold_ingot]
[3d_armor:leggings_mithril] X = [moreores:mithril_ingot] *
[3d_armor:leggings_crystal] X = [ethereal:crystal_ingot] **

Boots:

+---+---+---+
| X |   | X |
+---+---+---+
| X |   | X |
+---+---+---+

[3d_armor:boots_wood] X = [default:wood]
[3d_armor:boots_cactus] X = [default:cactus]
[3d_armor:boots_steel] X = [default:steel_ingot]
[3d_armor:boots_bronze] X = [default:bronze_ingot
[3d_armor:boots_diamond] X = [default:diamond]
[3d_armor:boots_gold] X = [default:gold_ingot]
[3d_armor:boots_mithril] X = [moreores:mithril_ingot] *
[3d_armor:boots_crystal] X = [ethereal:crystal_ingot] **

 * Requires moreores mod by Calinou - https://forum.minetest.net/viewtopic.php?id=549
** Requires ethereal mod by Chinchow & TenPlus1 - https://github.com/tenplus1/ethereal


code:
default
player_monoids?
armor_monoid?
pova?
fire?
ethereal?
bakedclay?


code: Adds craftable armor that is visible to other players.


code:
local modname = minetest.get_current_modname()
local modpath = minetest.get_modpath(modname)
local worldpath = minetest.get_worldpath()
local last_punch_time = {}
local pending_players = {}
local timer = 0

dofile(modpath.."/api.lua")

-- local functions
local F = minetest.formspec_escape
local S = armor.get_translator

-- integration test
if minetest.settings:get_bool("enable_3d_armor_integration_test") then
	dofile(modpath.."/integration_test.lua")
end

-- Legacy Config Support

local input = io.open(modpath.."/armor.conf", "r")
if input then
	dofile(modpath.."/armor.conf")
	input:close()
end
input = io.open(worldpath.."/armor.conf", "r")
if input then
	dofile(worldpath.."/armor.conf")
	input:close()
end
for name, _ in pairs(armor.config) do
	local global = "ARMOR_"..name:upper()
	if minetest.global_exists(global) then
		armor.config[name] = _G[global]
	end
end
if minetest.global_exists("ARMOR_MATERIALS") then
	armor.materials = table.copy(ARMOR_MATERIALS)
end
if minetest.global_exists("ARMOR_FIRE_NODES") then
	armor.fire_nodes = table.copy(ARMOR_FIRE_NODES)
end

-- Load Configuration

for name, config in pairs(armor.config) do
	local setting = minetest.settings:get("armor_"..name)
	if type(config) == "number" then
		setting = tonumber(setting)
	elseif type(config) == "boolean" then
		setting = minetest.settings:get_bool("armor_"..name)
	end
	if setting ~= nil then
		armor.config[name] = setting
	end
end
for material, _ in pairs(armor.materials) do
	local key = "material_"..material
	if armor.config[key] == false then
		armor.materials[material] = nil
	end
end

-- Mod Compatibility

if minetest.get_modpath("technic") then
	armor.formspec = armor.formspec..
		"label[5,2.5;"..F(S("Radiation"))..": armor_group_radiation]"
	armor:register_armor_group("radiation")
end
local skin_mods = {"skins", "u_skins", "simple_skins", "wardrobe"}
for _, mod in pairs(skin_mods) do
	local path = minetest.get_modpath(mod)
	if path then
		local dir_list = minetest.get_dir_list(path.."/textures")
		for _, fn in pairs(dir_list) do
			if fn:find("_preview.png$") then
				armor:add_preview(fn)
			end
		end
		armor.skin_mod = mod
	end
end
if not minetest.get_modpath("moreores") then
	armor.materials.mithril = nil
end
if not minetest.get_modpath("ethereal") then
	armor.materials.crystal = nil
end

dofile(modpath.."/armor.lua")

-- Armor Initialization

armor.formspec = armor.formspec..
	"label[5,1;"..F(S("Level"))..": armor_level]"..
	"label[5,1.5;"..F(S("Heal"))..": armor_attr_heal]"
if armor.config.fire_protect then
	armor.formspec = armor.formspec.."label[5,2;"..F(S("Fire"))..": armor_attr_fire]"
end
armor:register_on_damage(function(player, index, stack)
	local name = player:get_player_name()
	local def = stack:get_definition()
	if name and def and def.description and stack:get_wear() > 60100 then
		minetest.chat_send_player(name, S("Your @1 is almost broken!", def.description))
		minetest.sound_play("default_tool_breaks", {to_player = name, gain = 2.0})
	end
end)
armor:register_on_destroy(function(player, index, stack)
	local name = player:get_player_name()
	local def = stack:get_definition()
	if name and def and def.description then
		minetest.chat_send_player(name, S("Your @1 got destroyed!", def.description))
		minetest.sound_play("default_tool_breaks", {to_player = name, gain = 2.0})
	end
end)

local function validate_armor_inventory(player)
	-- Workaround for detached inventory swap exploit
	local _, inv = armor:get_valid_player(player, "[validate_armor_inventory]")
	local pos = player:get_pos()
	if not inv then
		return
	end
	local armor_prev = {}
	local attribute_meta = player:get_meta() -- I know, the function's name is weird but let it be like that. ;)
	local armor_list_string = attribute_meta:get_string("3d_armor_inventory")
	if armor_list_string then
		local armor_list = armor:deserialize_inventory_list(armor_list_string)
		for i, stack in ipairs(armor_list) do
			if stack:get_count() > 0 then
				armor_prev[stack:get_name()] = i
			end
		end
	end
	local elements = {}
	local player_inv = player:get_inventory()
	for i = 1, 6 do
		local stack = inv:get_stack("armor", i)
		if stack:get_count() > 0 then
			local item = stack:get_name()
			local element = armor:get_element(item)
			if element and not elements[element] then
				if armor_prev[item] then
					armor_prev[item] = nil
				else
					-- Item was not in previous inventory
					armor:run_callbacks("on_equip", player, i, stack)
				end
				elements[element] = true;
			else
				inv:remove_item("armor", stack)
				minetest.item_drop(stack, player, pos)
				-- The following code returns invalid items to the player's main
				-- inventory but could open up the possibity for a hacked client
				-- to receive items back they never really had. I am not certain
				-- so remove the is_singleplayer check at your own risk :]
				if minetest.is_singleplayer() and player_inv and
						player_inv:room_for_item("main", stack) then
					player_inv:add_item("main", stack)
				end
			end
		end
	end
	for item, i in pairs(armor_prev) do
		local stack = ItemStack(item)
		-- Previous item is not in current inventory
		armor:run_callbacks("on_unequip", player, i, stack)
	end
end

local function init_player_armor(initplayer)
	local name = initplayer:get_player_name()
	local pos = initplayer:get_pos()
	if not name or not pos then
		return false
	end
	local armor_inv = minetest.create_detached_inventory(name.."_armor", {
		on_put = function(inv, listname, index, stack, player)
			validate_armor_inventory(player)
			armor:save_armor_inventory(player)
			armor:set_player_armor(player)
		end,
		on_take = function(inv, listname, index, stack, player)
			validate_armor_inventory(player)
			armor:save_armor_inventory(player)
			armor:set_player_armor(player)
		end,
		on_move = function(inv, from_list, from_index, to_list, to_index, count, player)
			validate_armor_inventory(player)
			armor:save_armor_inventory(player)
			armor:set_player_armor(player)
		end,
		allow_put = function(inv, listname, index, put_stack, player)
			if player:get_player_name() ~= name then
				return 0
			end
			local element = armor:get_element(put_stack:get_name())
			if not element then
				return 0
			end
			for i = 1, 6 do
				local stack = inv:get_stack("armor", i)
				local def = stack:get_definition() or {}
				if def.groups and def.groups["armor_"..element]
						and i ~= index then
					return 0
				end
			end
			return 1
		end,
		allow_take = function(inv, listname, index, stack, player)
			if player:get_player_name() ~= name then
				return 0
			end
			return stack:get_count()
		end,
		allow_move = function(inv, from_list, from_index, to_list, to_index, count, player)
			if player:get_player_name() ~= name then
				return 0
			end
			return count
		end,
	}, name)
	armor_inv:set_size("armor", 6)
	if not armor:load_armor_inventory(initplayer) and armor.migrate_old_inventory then
		local player_inv = initplayer:get_inventory()
		player_inv:set_size("armor", 6)
		for i=1, 6 do
			local stack = player_inv:get_stack("armor", i)
			armor_inv:set_stack("armor", i, stack)
		end
		armor:save_armor_inventory(initplayer)
		player_inv:set_size("armor", 0)
	end
	for i=1, 6 do
		local stack = armor_inv:get_stack("armor", i)
		if stack:get_count() > 0 then
			armor:run_callbacks("on_equip", initplayer, i, stack)
		end
	end
	armor.def[name] = {
		init_time = minetest.get_gametime(),
		level = 0,
		state = 0,
		count = 0,
		groups = {},
	}
	for _, phys in pairs(armor.physics) do
		armor.def[name][phys] = 1
	end
	for _, attr in pairs(armor.attributes) do
		armor.def[name][attr] = 0
	end
	for group, _ in pairs(armor.registered_groups) do
		armor.def[name].groups[group] = 0
	end
	local skin = armor:get_player_skin(name)
	armor.textures[name] = {
		skin = skin,
		armor = "3d_armor_trans.png",
		wielditem = "3d_armor_trans.png",
		preview = armor.default_skin.."_preview.png",
	}
	local texture_path = minetest.get_modpath("player_textures")
	if texture_path then
		local dir_list = minetest.get_dir_list(texture_path.."/textures")
		for _, fn in pairs(dir_list) do
			if fn == "player_"..name..".png" then
				armor.textures[name].skin = fn
				break
			end
		end
	end
	armor:set_player_armor(initplayer)
	return true
end

-- Armor Player Model

default.player_register_model("3d_armor_character.b3d", {
	animation_speed = 30,
	textures = {
		armor.default_skin..".png",
		"3d_armor_trans.png",
		"3d_armor_trans.png",
	},
	animations = {
		stand = {x=0, y=79},
		lay = {x=162, y=166},
		walk = {x=168, y=187},
		mine = {x=189, y=198},
		walk_mine = {x=200, y=219},
		sit = {x=81, y=160},
	},
})

minetest.register_on_player_receive_fields(function(player, formname, fields)
	local name = armor:get_valid_player(player, "[on_player_receive_fields]")
	if not name then
		return
	end
	local player_name = player:get_player_name()
	for field, _ in pairs(fields) do
		if string.find(field, "skins_set") then
			armor:update_skin(player_name)
		end
	end
end)

minetest.register_on_joinplayer(function(player)
	default.player_set_model(player, "3d_armor_character.b3d")
	local player_name = player:get_player_name()

	minetest.after(0, function()
		local pplayer = minetest.get_player_by_name(player_name)
		if pplayer and init_player_armor(pplayer) == false then
			pending_players[pplayer] = 0
		end
	end)
end)

minetest.register_on_leaveplayer(function(player)
	local name = player:get_player_name()
	if name then
		armor.def[name] = nil
		armor.textures[name] = nil
	end
	pending_players[player] = nil
end)

if armor.config.drop == true or armor.config.destroy == true then
	minetest.register_on_dieplayer(function(player)
		local name, armor_inv = armor:get_valid_player(player, "[on_dieplayer]")
		if not name then
			return
		end
		local drop = {}
		for i=1, armor_inv:get_size("armor") do
			local stack = armor_inv:get_stack("armor", i)
			if stack:get_count() > 0 then
				table.insert(drop, stack)
				armor:run_callbacks("on_unequip", player, i, stack)
				armor_inv:set_stack("armor", i, nil)
			end
		end
		armor:save_armor_inventory(player)
		armor:set_player_armor(player)
		local pos = player:get_pos()
		if pos and armor.config.destroy == false then
			minetest.after(armor.config.bones_delay, function()
				local meta = nil
				local maxp = vector.add(pos, 16)
				local minp = vector.subtract(pos, 16)
				local bones = minetest.find_nodes_in_area(minp, maxp, {"mesecraft_bones:bones"})
				for _, p in pairs(bones) do
					local m = minetest.get_meta(p)
					if m:get_string("owner") == name then
						meta = m
						break
					end
				end
				if meta then
					local inv = meta:get_inventory()
					for _,stack in ipairs(drop) do
						if inv:room_for_item("main", stack) then
							inv:add_item("main", stack)
						else
							armor.drop_armor(pos, stack)
						end
					end
				else
					for _,stack in ipairs(drop) do
						armor.drop_armor(pos, stack)
					end
				end
			end)
		end
	end)
end

if armor.config.punch_damage == true then
	minetest.register_on_punchplayer(function(player, hitter,
			time_from_last_punch, tool_capabilities)
		local name = player:get_player_name()
		if name then
			armor:punch(player, hitter, time_from_last_punch, tool_capabilities)
			last_punch_time[name] = minetest.get_gametime()
		end
	end)
end

minetest.register_on_player_hpchange(function(player, hp_change, reason)
	if player and reason.type ~= "drown" and reason.hunger == nil
			and hp_change < 0 then
		local name = player:get_player_name()
		if name then
			local heal = armor.def[name].heal
			if heal >= math.random(100) then
				hp_change = 0
			end
			-- check if armor damage was handled by fire or on_punchplayer
			local time = last_punch_time[name] or 0
			if time == 0 or time + 1 < minetest.get_gametime() then
				armor:punch(player)
			end
		end
	end
	return hp_change
end, true)

minetest.register_globalstep(function(dtime)
	timer = timer + dtime
	if timer > armor.config.init_delay then
		for player, count in pairs(pending_players) do
			local remove = init_player_armor(player) == true
			pending_players[player] = count + 1
			if remove == false and count > armor.config.init_times then
				minetest.log("warning", S("3d_armor: Failed to initialize player"))
				remove = true
			end
			if remove == true then
				pending_players[player] = nil
			end
		end
		timer = 0
	end
end)

-- Fire Protection and water breathing, added by TenPlus1.

if armor.config.fire_protect == true then
	-- override hot nodes so they do not hurt player anywhere but mod
	for _, row in pairs(armor.fire_nodes) do
		if minetest.registered_nodes[row[1]] then
			minetest.override_item(row[1], {damage_per_second = 0})
		end
	end
else
	print (S("[3d_armor] Fire Nodes disabled"))
end

if armor.config.water_protect == true or armor.config.fire_protect == true then
	minetest.register_globalstep(function(dtime)
		armor.timer = armor.timer + dtime
		if armor.timer < armor.config.update_time then
			return
		end
		for _,player in pairs(minetest.get_connected_players()) do
			local name = player:get_player_name()
			local pos = player:get_pos()
			local hp = player:get_hp()
			if not name or not pos or not hp then
				return
			end
			-- water breathing
			if armor.config.water_protect == true then
				if armor.def[name].water > 0 and
						player:get_breath() < 10 then
					player:set_breath(10)
				end
			end
			-- fire protection
			if armor.config.fire_protect == true then
				local fire_damage = true
				pos.y = pos.y + 1.4 -- head level
				local node_head = minetest.get_node(pos).name
				pos.y = pos.y - 1.2 -- feet level
				local node_feet = minetest.get_node(pos).name
				-- is player inside a hot node?
				for _, row in pairs(armor.fire_nodes) do
					-- check fire protection, if not enough then get hurt
					if row[1] == node_head or row[1] == node_feet then
						if fire_damage == true then
							armor:punch(player, "fire")
							last_punch_time[name] = minetest.get_gametime()
							fire_damage = false
						end
						if hp > 0 and armor.def[name].fire < row[2] then
							hp = hp - row[3] * armor.config.update_time
							player:set_hp(hp)
							break
						end
					end
				end
			end
		end
		armor.timer = 0
	end)
end


code:
minetest.log("warning", "[TEST] integration-test enabled!")

minetest.register_on_mods_loaded(function()
	minetest.after(1, function()

		local data = minetest.write_json({ success = true }, true);
		local file = io.open(minetest.get_worldpath().."/integration_test.json", "w" );
		if file then
			file:write(data)
			file:close()
		end

		file = io.open(minetest.get_worldpath().."/registered_nodes.txt", "w" );
		if file then
			for name in pairs(minetest.registered_nodes) do
				file:write(name .. '\n')
			end
			file:close()
		end

		minetest.log("warning", "[TEST] integration tests done!")
		minetest.request_shutdown("success")
	end)
end)


code:
# textdomain: 3d_armor

### api.lua ###

3d_armor: Detached armor inventory is nil @1=3d_armor: La armadura desconectada es nula @1
3d_armor: Player name is nil @1=3d_armor: El nombre del jugador es nulo @1
3d_armor: Player reference is nil @1=3d_armor: La referencia del jugador es nula @1

### armor.lua ###

Admin Boots=Botas de admin
Admin Chestplate=Peto de admin
Admin Helmet=Casco de admin
Admin Leggings=Polainas de admin
Bronze Boots=Botas de bronce
Bronze Chestplate=Peto de bronce
Bronze Helmet=Casco de bronce
Bronze Leggings=Polainas de bronce
Cactus Boots=Botas de cactus
Cactus Chestplate=Peto de cactus
Cactus Helmet=Casco de cactus
Cactus Leggings=Polainas de cactus
Crystal Boots=Botas de cristal
Crystal Chestplate=Peto de cristal
Crystal Helmet=Casco de cristal
Crystal Leggings=Polainas de cristal
Diamond Boots=Botas de diamante
Diamond Chestplate=Peto de diamante
Diamond Helmet=Casco de diamante
Diamond Leggings=Polainas de diamante
Gold Boots=Botas de oro
Gold Chestplate=Peto de oro
Gold Helmet=Casco de oro
Gold Leggings=Polainas de oro
Mithril Boots=Botas de mitrilo
Mithril Chestplate=Peto de mitrilo
Mithril Helmet=Casco de mitrilo
Mithril Leggings=Polainas de mitrilo
Steel Boots=Botas de acero
Steel Chestplate=Peto de acero
Steel Helmet=Casco de acero
Steel Leggings=Polainas de acero
Wood Boots=Botas de madera
Wood Chestplate=Peto de madera
Wood Helmet=Casco de madera
Wood Leggings=Polainas de madera

### init.lua ###

3d_armor: Failed to initialize player=3d_armor: Fallo en la inicialización del jugador
Fire=Fuego
Heal=Salud
Level=Nivel
Radiation=Radiación
Your @1 got destroyed!=¡Tu @1 fue destruído!
Your @1 is almost broken!=
[3d_armor] Fire Nodes disabled=[3d_armor] Nodos de fuego desabilitados

##### not used anymore #####

3d_armor: Player inventory is nil @1=3d_armor: El inventario del jugador es nulo @1
3d_armor_ip: Mod loaded but unused.=3d_armor_ip: Mod cargado, pero sin ser usado.
Back=Volver
Armor=Armadura
3d_armor_sfinv: Mod loaded but unused.=3d_armor_sfinv: Mod cargado, pero sin ser usado.
Armor stand top=Parte arriba maniquí armadura
Armor stand=Maniquí para armadura
Armor Stand=Maniquí para armadura
Locked Armor stand=Maniquí para armadura (bloqueado)
Armor Stand (owned by @1)=Maniquí para armadura (propiedad de @1)
3d_armor_ui: Mod loaded but unused.=3d_armor_ui: Mod cargado, pero sin ser usado.
3d Armor=Armadura 3d
Armor not initialized!=¡Armadura no inicializada!
hazmat_suit: Mod loaded but unused.=hazmat_suit: Mod cargado, pero sin ser usado.
Hazmat Helmet=Casco de hazmat
Hazmat Chestplate=Peto de hazmat
Hazmat Sleeve=Manga de hazmat
Hazmat Leggins=Polainas de hazmat
Hazmat Boots=Botas de hazmat
Hazmat Suit=Traje de hazmat
Admin Shield=Escudo de admin
Wooden Shield=Escudo de madera
Enhanced Wood Shield=Escudo de madera mejorado
Cactus Shield=Escudo de cactus
Enhanced Cactus Shield=Escudo de cactus mejorado
Steel Shield=Escudo de acero
Bronze Shield=Escudo de bronce
Diamond Shield=Escudo de diamante
Gold Shield=Escudo de oro
Mithril Shield=Escudo de mitrilo
Crystal Shield=Escudo de cristal
technic_armor: Mod loaded but unused.=technic_armor: Mod cargado, pero no usado.
Lead=Plomo
Brass=Latón
Cast Iron=Hierro fundido
Carbon Steel=Acero carbono
Stainless Steel=Acero inoxidable
Tin=Estaño
Silver=Plata
Helmet=Casco
Chestplate=Peto
Leggins=Polainas
Boots=Botas
Shield=Escudo
@1 @2=@2 de @1


code:
# textdomain: 3d_armor

### api.lua ###

3d_armor: Detached armor inventory is nil @1=3d_armor : Inventaire détaché pour l'armure non trouvé @1
3d_armor: Player name is nil @1=3d_armor : Nom du joueur non trouvé @1
3d_armor: Player reference is nil @1=3d_armor : Référence au joueur non trouvée @1

### armor.lua ###

Admin Boots=Bottes d'admin
Admin Chestplate=Cuirasse d'admin
Admin Helmet=Casque d'admin
Admin Leggings=Jambières d'admin
Bronze Boots=Bottes en bronze
Bronze Chestplate=Cuirasse en bronze
Bronze Helmet=Casque en bronze
Bronze Leggings=Jambières en bronze
Cactus Boots=Bottes en cactus
Cactus Chestplate=Cuirasse en cactus
Cactus Helmet=Casque en cactus
Cactus Leggings=Jambières en cactus
Crystal Boots=Bottes en cristal
Crystal Chestplate=Cuirasse en cristal
Crystal Helmet=Casque en cristal
Crystal Leggings=Jambières en cristal
Diamond Boots=Bottes en diamant
Diamond Chestplate=Cuirasse en diamant
Diamond Helmet=Casque en diamant
Diamond Leggings=Jambières en diamant
Gold Boots=Bottes en or
Gold Chestplate=Cuirasse en or
Gold Helmet=Casque en or
Gold Leggings=Jambières en or
Mithril Boots=Bottes en mithril
Mithril Chestplate=Cuirasse en mithril
Mithril Helmet=Casque en mithril
Mithril Leggings=Jambières en mithril
Steel Boots=Bottes en acier
Steel Chestplate=Cuirasse en acier
Steel Helmet=Casque en acier
Steel Leggings=Jambières en acier
Wood Boots=Bottes en bois
Wood Chestplate=Cuirasse en bois
Wood Helmet=Casque en bois
Wood Leggings=Jambières en bois

### init.lua ###

3d_armor: Failed to initialize player=3d_armor : Impossible d'initialiser le joueur
Fire=Fire
Heal=Soins
Level=Niveau
Radiation=Radiation
Your @1 got destroyed!=Une partie de votre armure a été détruite : @1 !
Your @1 is almost broken!=Une partie de votre armure est presque détruite : @1 !
[3d_armor] Fire Nodes disabled=[3d_armor] Nœuds de type feu désactivés


code:
# textdomain: 3d_armor

### api.lua ###

3d_armor: Detached armor inventory is nil @1=3d_armor: L'inventario separato dell'armatura è nullo @1
3d_armor: Player name is nil @1=3d_armor: Il nome dell'utente è nullo @1
3d_armor: Player reference is nil @1=3d_armor: Il riferimento all'utente è nullo @1

### armor.lua ###

Admin Boots=Stivali dell'amministratrice/tore
Admin Chestplate=Corazza dell'amministratrice/tore
Admin Helmet=Elmo dell'amministratrice/tore
Admin Leggings=Gambali dell'amministratrice/tore
Bronze Boots=Stivali di bronzo
Bronze Chestplate=Corazza di bronzo
Bronze Helmet=Elmo di bronzo
Bronze Leggings=Gambali di bronzo
Cactus Boots=Stivali di cactus
Cactus Chestplate=Corazza di cactus
Cactus Helmet=Elmo di cactus
Cactus Leggings=Gambali di cactus
Crystal Boots=Stivali di cristallo
Crystal Chestplate=Corazza di cristallo
Crystal Helmet=Elmo di cristallo
Crystal Leggings=Gambali di cristallo
Diamond Boots=Stivali di diamante
Diamond Chestplate=Corazza di diamante
Diamond Helmet=Elmo di diamante
Diamond Leggings=Gambali di diamante
Gold Boots=Stivali d'oro
Gold Chestplate=Corazza d'oro
Gold Helmet=Elmo d'oro
Gold Leggings=Gambali d'oro
Mithril Boots=Stivali di mithril
Mithril Chestplate=Corazza di mithril
Mithril Helmet=Elmo di mithril
Mithril Leggings=Gambali di mithril
Steel Boots=Stivali d'acciaio
Steel Chestplate=Corazza d'acciaio
Steel Helmet=Elmo d'acciaio
Steel Leggings=Gambali d'acciaio
Wood Boots=Stivali di legno
Wood Chestplate=Corazza di legno
Wood Helmet=Elmo di legno
Wood Leggings=Gambali di legno

### init.lua ###

3d_armor: Failed to initialize player=3d_armor: Inizializzazione dell'utente fallita
Fire=Fuoco
Heal=Guarigione
Level=Livello
Radiation=Radiazione
Your @1 got destroyed!=@1 in frantumi!
Your @1 is almost broken!=@1 quasi in frantumi!
[3d_armor] Fire Nodes disabled=[3d_armor] Nodi fuoco disabilitati

##### not used anymore #####

3d_armor_ip: Mod loaded but unused.=3d_armor_ip: Mod caricata ma inutilizzata.
Back=Indietro
Armor=Armatura
3d_armor_sfinv: Mod loaded but unused.=3d_armor_sfinv: Mod caricata ma inutilizzata.
Armor stand top=Parte superiore del supporto per armatura
Armor stand=Supporto per armatura
Armor Stand=Supporto per armatura
Locked Armor stand=Supporto per armatura chiuso a chiave
Armor Stand (owned by @1)=Supporto per armatura (di proprietà di @1)
3d_armor_ui: Mod loaded but unused.=3d_armor_ui: Mod caricata ma inutilizzata.
3d Armor=Armatura 3D
Armor not initialized!=Armatura non inizializzata!
Admin Shield=Scudo dell'amministratrice/tore
Wooden Shield=Scudo di legno
Enhanced Wood Shield=Scudo di legno migliorato
Cactus Shield=Scudo di cactus
Enhanced Cactus Shield=Scudo di cactus migliorato
Steel Shield=Scudo d'acciaio
Bronze Shield=Scudo di bronzo
Diamond Shield=Scudo di diamante
Gold Shield=Scudo d'oro
Mithril Shield=Scudo di mithril
Crystal Shield=Scudo di cristallo


code:
# textdomain: 3d_armor

### api.lua ###

3d_armor: Detached armor inventory is nil @1=3d_armor: Inventori perisai terpisah tiada nilai @1
3d_armor: Player name is nil @1=3d_armor: Nama pemain tiada nilai @1
3d_armor: Player reference is nil @1=3d_armor: Rujukan pemain tiada nilai @1

### armor.lua ###

Admin Boots=But Pentadbir
Admin Chestplate=Perisai Dada Pentadbir
Admin Helmet=Helmet Pentadbir
Admin Leggings=Perisai Kaki Pentadbir
Bronze Boots=But Gangsa
Bronze Chestplate=Perisai Dada Gangsa
Bronze Helmet=Helmet Gangsa
Bronze Leggings=Perisai Kaki Gangsa
Cactus Boots=But Kaktus
Cactus Chestplate=Perisai Dada Kaktus
Cactus Helmet=Helmet Kaktus
Cactus Leggings=Perisai Kaki Kaktus
Crystal Boots=But Kristal
Crystal Chestplate=Perisai Dada Kristal
Crystal Helmet=Helmet Kristal
Crystal Leggings=Perisai Kaki Kristal
Diamond Boots=But Intan
Diamond Chestplate=Perisai Dada Intan
Diamond Helmet=Helmet Intan
Diamond Leggings=Perisai Kaki Intan
Gold Boots=But Emas
Gold Chestplate=Perisai Dada Emas
Gold Helmet=Helmet Emas
Gold Leggings=Perisai Kaki Emas
Mithril Boots=But Mithril
Mithril Chestplate=Perisai Dada Mithril
Mithril Helmet=Helmet Mithril
Mithril Leggings=Perisai Kaki Mithril
Steel Boots=But Keluli
Steel Chestplate=Perisai Dada Keluli
Steel Helmet=Helmet Keluli
Steel Leggings=Perisai Kaki Keluli
Wood Boots=But Kayu
Wood Chestplate=Perisai Dada Kayu
Wood Helmet=Helmet Kayu
Wood Leggings=Perisai Kaki Kayu

### init.lua ###

3d_armor: Failed to initialize player=3d_armor: Gagal mengasalkan pemain
Fire=Api
Heal=Pulih
Level=Tahap
Radiation=Radiasi
Your @1 got destroyed!=@1 anda telah musnah!
Your @1 is almost broken!=
[3d_armor] Fire Nodes disabled=[3d_armor] Nod-nod Api dilumpuhkan

##### not used anymore #####

3d_armor_ip: Mod loaded but unused.=3d_armor_ip: Mods dimuatkan tetapi tidak digunakan.
Back=Kembali
Armor=Perisai
3d_armor_sfinv: Mod loaded but unused.=3d_armor_sfinv: Mods dimuatkan tetapi tidak digunakan.
Armor stand top=Bhg atas dirian perisai
Armor stand=Dirian perisai
Armor Stand=Dirian Perisai
Locked Armor stand=Dirian perisai Berkunci
Armor Stand (owned by @1)=Dirian Perisai (milik @1)
3d_armor_ui: Mod loaded but unused.=3d_armor_ui: Mods dimuatkan tetapi tidak digunakan.
3d Armor=Perisai 3d
Armor not initialized!=Perisai tidak diasalkan!
Admin Shield=Perisai Pegang Pentadbir
Wooden Shield=Perisai Pegang Kayu
Enhanced Wood Shield=Perisai Pegang Kayu Kukuh
Cactus Shield=Perisai Pegang Kaktus
Enhanced Cactus Shield=Perisai Pegang Kaktus Kukuh
Steel Shield=Perisai Pegang Keluli
Bronze Shield=Perisai Pegang Gangsa
Diamond Shield=Perisai Pegang Intan
Gold Shield=Perisai Pegang Emas
Mithril Shield=Perisai Pegang Mithril
Crystal Shield=Perisai Pegang Kristal


code:
# textdomain: 3d_armor

### api.lua ###

3d_armor: Detached armor inventory is nil @1=3d_armor: Inventario avulso de armadura é nulo @1
3d_armor: Player name is nil @1=3d_armor: Nome de jogador é nulo @1
3d_armor: Player reference is nil @1=3d_armor: Referência Jogador é nula @1

### armor.lua ###

Admin Boots=Botas de Administrador
Admin Chestplate=Peitoral de Administrador
Admin Helmet=Capacete de Administrador
Admin Leggings=Calças de Administrador
Bronze Boots=Botas de Bronze
Bronze Chestplate=Peitoral de Bronze
Bronze Helmet=Capacete de Bronze
Bronze Leggings=Calças de Bronze
Cactus Boots=Botas de Madeira
Cactus Chestplate=Peitoral de Cacto
Cactus Helmet=Capacete de Cacto
Cactus Leggings=Calças de Cacto
Crystal Boots=Botas de Cristal
Crystal Chestplate=Peitoral de Cristal
Crystal Helmet=Capacete de Cristal
Crystal Leggings=Calças de Cristal
Diamond Boots=Botas de Diamante
Diamond Chestplate=Peitoral de Diamante
Diamond Helmet=Capacete de Diamante
Diamond Leggings=Calças de Diamante
Gold Boots=Botas de Ouro
Gold Chestplate=Peitoral de Ouro
Gold Helmet=Capacete de Ouro
Gold Leggings=Calças de Ouro
Mithril Boots=Botas de Mithril
Mithril Chestplate=Peitoral de Mithril
Mithril Helmet=Capacete de Mithril
Mithril Leggings=Calças de Mithril
Steel Boots=Botas de Aço
Steel Chestplate=Peitoral de Aço
Steel Helmet=Capacete de Aço
Steel Leggings=Calças de Aço
Wood Boots=Botas de Madeira
Wood Chestplate=Peitoral de Madeira
Wood Helmet=Capacete de Madeira
Wood Leggings=Calças de Madeira

### init.lua ###

3d_armor: Failed to initialize player=3d_armor: Falha ao inicializar jogador
Fire=Fogo
Heal=Saúde
Level=Nível
Radiation=Radiação
Your @1 got destroyed!=@1 foi destruído(a)!
Your @1 is almost broken!=
[3d_armor] Fire Nodes disabled=[3d_armor] Nodes de gofo desabilitados

##### not used anymore #####

3d_armor_ip: Mod loaded but unused.=3d_armor_ip: Mod carregado mas inoperante.
Back=Voltar
Armor=Armadura
3d_armor_sfinv: Mod loaded but unused.=3d_armor_sfinv: Mod carregado mas inoperante.
Armor stand top=Topo de estande de armadura
Armor stand=Estande de armadura
Armor Stand=Estande de Armadura
Locked Armor stand=Estande de Armadura Trancada
Armor Stand (owned by @1)=Estande de Armadura (pertente a @1)
3d_armor_ui: Mod loaded but unused.=3d_armor_ui: Mod carregado mas inoperante.
3d Armor=3d Armor
Armor not initialized!=Armadura não inicializada!
Admin Shield=Escudo de Administrador
Wooden Shield=Escudo de Madeira
Enhanced Wood Shield=Escudo de Madeira Melhorado
Cactus Shield=Escudo de Cacto
Enhanced Cactus Shield=Escudo de Cacto Melhorado
Steel Shield=Escudo de Aço
Bronze Shield=Escudo de Bronze
Diamond Shield=Escudo de Diamante
Gold Shield=Escudo de Ouro
Mithril Shield=Escudo de Mithril
Crystal Shield=Escudo de Cristal


code:
# textdomain: 3d_armor

### api.lua ###

3d_armor: Detached armor inventory is nil @1=3d_armor: Отдельный инвентарь брони является nil @1
3d_armor: Player name is nil @1=3d_armor: Имя игрока является nil @1
3d_armor: Player reference is nil @1=3d_armor: Ссылка игрока является nil @1

### armor.lua ###

Admin Boots=ботинки админа
Admin Chestplate=бронежилет админа
Admin Helmet=шлем админа
Admin Leggings=гамаши админа
Bronze Boots=бронзовые ботинки
Bronze Chestplate=бронзовый бронежилет
Bronze Helmet=бронзовый шлем
Bronze Leggings=бронзовые гамаши
Cactus Boots=кактусовые ботинки
Cactus Chestplate=кактусовый бронежилет
Cactus Helmet=кактусовый шлем
Cactus Leggings=кактусовые гамаши
Crystal Boots=кристалловые ботинки
Crystal Chestplate=кристалловый бронежилет
Crystal Helmet=кристалловый шлем
Crystal Leggings=кристалловые гамаши
Diamond Boots=алмазные ботинки
Diamond Chestplate=алмазный бронежилет
Diamond Helmet=алмазный шлем
Diamond Leggings=алмазные гамаши
Gold Boots=золотые ботинки
Gold Chestplate=золотой бронежилет
Gold Helmet=золотой шлем
Gold Leggings=золотые гамаши
Mithril Boots=мифриловые ботинки
Mithril Chestplate=мифриловый бронежилет
Mithril Helmet=мифриловый шлем
Mithril Leggings=мифриловые гамаши
Steel Boots=стальные ботинки
Steel Chestplate=стальной бронежилет
Steel Helmet=стальной шлем
Steel Leggings=стальные гамаши
Wood Boots=деревянные ботинки
Wood Chestplate=деревянный бронежилет
Wood Helmet=деревянный шлем
Wood Leggings=деревянные гамаши

### init.lua ###

3d_armor: Failed to initialize player=3d_armor: не смог подготовить игрока
Fire=огонь
Heal=исцеление
Level=уровень
Radiation=излучение
Your @1 got destroyed!=твой(и) @1 был(и) разрушен(ы)!
Your @1 is almost broken!=
[3d_armor] Fire Nodes disabled=[3d_armor] блоки огня отключены

##### not used anymore #####

3d_armor_ip: Mod loaded but unused.=3d_armor_ip: мод загружен но не используется.
Back=назад
Armor=бронь
3d_armor_sfinv: Mod loaded but unused.=3d_armor_sfinv: мод загружен но не используется.
Armor stand top=стойка для брони (верх)
Armor stand=стойка для брони
Armor Stand=стойка для брони
Locked Armor stand=защищенная стойка для брони
Armor Stand (owned by @1)=стойка для брони (принадлежит @1)
3d_armor_ui: Mod loaded but unused.=3d_armor_ui: мод загружен но не используется.
3d Armor=3D бронь
Armor not initialized!=бронь не подготовлена!
Admin Shield=щит админа
Wooden Shield=деревянный щит
Enhanced Wood Shield=улучшенный деревянный щит
Cactus Shield=кактусный щит
Enhanced Cactus Shield=улучшенный кактусный щит
Steel Shield=стальной щит
Bronze Shield=бронзовый щит
Diamond Shield=алмазный щит
Gold Shield=золотой щит
Mithril Shield=мифриловый щит
Crystal Shield=кристалловый щит


code:
# textdomain: 3d_armor

### api.lua ###

3d_armor: Detached armor inventory is nil @1=
3d_armor: Player name is nil @1=
3d_armor: Player reference is nil @1=

### armor.lua ###

Admin Boots=
Admin Chestplate=
Admin Helmet=
Admin Leggings=
Bronze Boots=
Bronze Chestplate=
Bronze Helmet=
Bronze Leggings=
Cactus Boots=
Cactus Chestplate=
Cactus Helmet=
Cactus Leggings=
Crystal Boots=
Crystal Chestplate=
Crystal Helmet=
Crystal Leggings=
Diamond Boots=
Diamond Chestplate=
Diamond Helmet=
Diamond Leggings=
Gold Boots=
Gold Chestplate=
Gold Helmet=
Gold Leggings=
Mithril Boots=
Mithril Chestplate=
Mithril Helmet=
Mithril Leggings=
Steel Boots=
Steel Chestplate=
Steel Helmet=
Steel Leggings=
Wood Boots=
Wood Chestplate=
Wood Helmet=
Wood Leggings=

### init.lua ###

3d_armor: Failed to initialize player=
Fire=
Heal=
Level=
Radiation=
Your @1 got destroyed!=
Your @1 is almost broken!=
[3d_armor] Fire Nodes disabled=


code:
name = 3d_armor
depends = default
optional_depends = player_monoids, armor_monoid, pova, fire, ethereal, bakedclay
description = Adds craftable armor that is visible to other players.


code:
# Intllib tool

please consider using the intllib tool to update locale files:

```../../intllib/tools/xgettext.sh ../**/*.lua```

make sure you are in `3d_armor` derectory before running this command


code:
#! /bin/bash

# To create a new translation:
#   msginit --locale=ll_CC -o locale/ll_CC.po -i locale/template.pot

cd "$(dirname "${BASH_SOURCE[0]}")/..";

# Extract translatable strings.
xgettext --from-code=UTF-8 \
		--language=Lua \
		--sort-by-file \
		--keyword=S \
		--keyword=NS:1,2 \
		--keyword=N_ \
		--add-comments='Translators:' \
		--add-location=file \
		-o locale/template.pot \
		$(find .. -name '*.lua')

# Update translations.
find locale -name '*.po' | while read -r file; do
	echo $file
	msgmerge --update $file locale/template.pot;
done


code: Adds 3d_armor page to the sfinv inventory.


code:
-- support for i18n
local S = minetest.get_translator(minetest.get_current_modname())

if not minetest.global_exists("sfinv") then
	minetest.log("warning", S("3d_armor_sfinv: Mod loaded but unused."))
	return
end

sfinv.register_page("3d_armor:armor", {
	title = S("Armor"),
	get = function(self, player, context)
		local name = player:get_player_name()
		local formspec = armor:get_armor_formspec(name, true)
		return sfinv.make_formspec(player, context, formspec, false)
	end
})
armor:register_on_update(function(player)
	if sfinv.enabled then
		sfinv.set_player_inventory_formspec(player)
	end
end)


code:
# textdomain: 3d_armor_sfinv

### init.lua ###

3d_armor_sfinv: Mod loaded but unused.=3d_armor_sfinv : Mod chargé mais inutilisé.
Armor=Armure


code:
# textdomain: 3d_armor_sfinv

### init.lua ###

3d_armor_sfinv: Mod loaded but unused.=
Armor=


code:
name = 3d_armor_sfinv
depends = 3d_armor
optional_depends = sfinv
description = Adds 3d_armor page to the sfinv inventory.


code:
[mod] 3d Armor Stand [3d_armor_stand]
=====================================

Depends: 3d_armor

Adds a chest-like armor stand for armor storage and display.

Crafting
--------

F = Wooden Fence [default:fence_wood]
S = Steel Ingot [default:steel_ingot]

+---+---+---+
|   | F |   |
+---+---+---+
|   | F |   |
+---+---+---+
| S | S | S |
+---+---+---+


code:
-- support for i18n
local S = minetest.get_translator(minetest.get_current_modname())

local armor_stand_formspec = "size[8,7]" ..
	default.gui_bg ..
	default.gui_bg_img ..
	default.gui_slots ..
	default.get_hotbar_bg(0,3) ..
	"list[current_name;armor_head;3,0.5;1,1;]" ..
	"list[current_name;armor_torso;4,0.5;1,1;]" ..
	"list[current_name;armor_legs;3,1.5;1,1;]" ..
	"list[current_name;armor_feet;4,1.5;1,1;]" ..
	"image[3,0.5;1,1;3d_armor_stand_head.png]" ..
	"image[4,0.5;1,1;3d_armor_stand_torso.png]" ..
	"image[3,1.5;1,1;3d_armor_stand_legs.png]" ..
	"image[4,1.5;1,1;3d_armor_stand_feet.png]" ..
	"list[current_player;main;0,3;8,1;]" ..
	"list[current_player;main;0,4.25;8,3;8]"

local elements = {"head", "torso", "legs", "feet"}

local function drop_armor(pos)
	local meta = minetest.get_meta(pos)
	local inv = meta:get_inventory()
	for _, element in pairs(elements) do
		local stack = inv:get_stack("armor_"..element, 1)
		if stack and stack:get_count() > 0 then
			armor.drop_armor(pos, stack)
			inv:set_stack("armor_"..element, 1, nil)
		end
	end
end

local function get_stand_object(pos)
	local object = nil
	local objects = minetest.get_objects_inside_radius(pos, 0.5) or {}
	for _, obj in pairs(objects) do
		local ent = obj:get_luaentity()
		if ent then
			if ent.name == "3d_armor_stand:armor_entity" then
				-- Remove duplicates
				if object then
					obj:remove()
				else
					object = obj
				end
			end
		end
	end
	return object
end

local function update_entity(pos)
	local node = minetest.get_node(pos)
	local object = get_stand_object(pos)
	if object then
		if not string.find(node.name, "3d_armor_stand:") then
			object:remove()
			return
		end
	else
		object = minetest.add_entity(pos, "3d_armor_stand:armor_entity")
	end
	if object then
		local texture = "3d_armor_trans.png"
		local textures = {}
		local meta = minetest.get_meta(pos)
		local inv = meta:get_inventory()
		local yaw = 0
		if inv then
			for _, element in pairs(elements) do
				local stack = inv:get_stack("armor_"..element, 1)
				if stack:get_count() == 1 then
					local item = stack:get_name() or ""
					local def = stack:get_definition() or {}
					local groups = def.groups or {}
					if groups["armor_"..element] then
						if def.texture then
							table.insert(textures, def.texture)
						else
							table.insert(textures, item:gsub("%:", "_")..".png")
						end
					end
				end
			end
		end
		if #textures > 0 then
			texture = table.concat(textures, "^")
		end
		if node.param2 then
			local rot = node.param2 % 4
			if rot == 1 then
				yaw = 3 * math.pi / 2
			elseif rot == 2 then
				yaw = math.pi
			elseif rot == 3 then
				yaw = math.pi / 2
			end
		end
		object:set_yaw(yaw)
		object:set_properties({textures={texture}})
	end
end

local function has_locked_armor_stand_privilege(meta, player)
	local name = ""
	if player then
		if minetest.check_player_privs(player, "protection_bypass") then
			return true
		end
		name = player:get_player_name()
	end
	if name ~= meta:get_string("owner") then
		return false
	end
	return true
end

local function add_hidden_node(pos, player)
	local p = {x=pos.x, y=pos.y + 1, z=pos.z}
	local name = player:get_player_name()
	local node = minetest.get_node(p)
	if node.name == "air" and not minetest.is_protected(pos, name) then
		minetest.set_node(p, {name="3d_armor_stand:top"})
	end
end

local function remove_hidden_node(pos)
	local p = {x=pos.x, y=pos.y + 1, z=pos.z}
	local node = minetest.get_node(p)
	if node.name == "3d_armor_stand:top" then
		minetest.remove_node(p)
	end
end

minetest.register_node("3d_armor_stand:top", {
	description = S("Armor stand top"),
	paramtype = "light",
	drawtype = "plantlike",
	sunlight_propagates = true,
	walkable = true,
	pointable = false,
	diggable = false,
	buildable_to = false,
	drop = "",
	groups = {not_in_creative_inventory = 1},
	on_blast = function() end,
	tiles = {"3d_armor_trans.png"},
})

minetest.register_node("3d_armor_stand:armor_stand", {
	description = S("Armor stand"),
	drawtype = "mesh",
	mesh = "3d_armor_stand.obj",
	tiles = {"3d_armor_stand.png"},
	paramtype = "light",
	paramtype2 = "facedir",
	walkable = false,
	selection_box = {
		type = "fixed",
		fixed = {
			{-0.25, -0.4375, -0.25, 0.25, 1.4, 0.25},
			{-0.5, -0.5, -0.5, 0.5, -0.4375, 0.5},
		},
	},
	groups = {choppy=2, oddly_breakable_by_hand=2},
	sounds = default.node_sound_wood_defaults(),
	on_construct = function(pos)
		local meta = minetest.get_meta(pos)
		meta:set_string("formspec", armor_stand_formspec)
		meta:set_string("infotext", S("Armor Stand"))
		local inv = meta:get_inventory()
		for _, element in pairs(elements) do
			inv:set_size("armor_"..element, 1)
		end
	end,
	can_dig = function(pos, player)
		local meta = minetest.get_meta(pos)
		local inv = meta:get_inventory()
		for _, element in pairs(elements) do
			if not inv:is_empty("armor_"..element) then
				return false
			end
		end
		return true
	end,
	after_place_node = function(pos, placer)
		minetest.add_entity(pos, "3d_armor_stand:armor_entity")
		add_hidden_node(pos, placer)
	end,
	allow_metadata_inventory_put = function(pos, listname, index, stack)
		local def = stack:get_definition() or {}
		local groups = def.groups or {}
		if groups[listname] then
			return 1
		end
		return 0
	end,
	allow_metadata_inventory_move = function(pos)
		return 0
	end,
	on_metadata_inventory_put = function(pos)
		update_entity(pos)
	end,
	on_metadata_inventory_take = function(pos)
		update_entity(pos)
	end,
	after_destruct = function(pos)
		update_entity(pos)
		remove_hidden_node(pos)
	end,
	on_blast = function(pos)
		drop_armor(pos)
		armor.drop_armor(pos, "3d_armor_stand:armor_stand")
		minetest.remove_node(pos)
	end,
})

minetest.register_node("3d_armor_stand:locked_armor_stand", {
	description = S("Locked Armor stand"),
	drawtype = "mesh",
	mesh = "3d_armor_stand.obj",
	tiles = {"3d_armor_stand_locked.png"},
	paramtype = "light",
	paramtype2 = "facedir",
	walkable = false,
	selection_box = {
		type = "fixed",
		fixed = {
			{-0.25, -0.4375, -0.25, 0.25, 1.4, 0.25},
			{-0.5, -0.5, -0.5, 0.5, -0.4375, 0.5},
		},
	},
	groups = {choppy=2, oddly_breakable_by_hand=2},
	sounds = default.node_sound_wood_defaults(),
	on_construct = function(pos)
		local meta = minetest.get_meta(pos)
		meta:set_string("formspec", armor_stand_formspec)
		meta:set_string("infotext", S("Armor Stand"))
		meta:set_string("owner", "")
		local inv = meta:get_inventory()
		for _, element in pairs(elements) do
			inv:set_size("armor_"..element, 1)
		end
	end,
	can_dig = function(pos, player)
		local meta = minetest.get_meta(pos)
		local inv = meta:get_inventory()
		for _, element in pairs(elements) do
			if not inv:is_empty("armor_"..element) then
				return false
			end
		end
		return true
	end,
	after_place_node = function(pos, placer)
		minetest.add_entity(pos, "3d_armor_stand:armor_entity")
		local meta = minetest.get_meta(pos)
		meta:set_string("owner", placer:get_player_name() or "")
		meta:set_string("infotext", S("Armor Stand (owned by @1)", meta:get_string("owner")))
		add_hidden_node(pos, placer)
	end,
	allow_metadata_inventory_put = function(pos, listname, index, stack, player)
		local meta = minetest.get_meta(pos)
		if not has_locked_armor_stand_privilege(meta, player) then
			return 0
		end
		local def = stack:get_definition() or {}
		local groups = def.groups or {}
		if groups[listname] then
			return 1
		end
		return 0
	end,
	allow_metadata_inventory_take = function(pos, listname, index, stack, player)
		local meta = minetest.get_meta(pos)
		if not has_locked_armor_stand_privilege(meta, player) then
			return 0
		end
		return stack:get_count()
	end,
	allow_metadata_inventory_move = function(pos)
		return 0
	end,
	on_metadata_inventory_put = function(pos)
		update_entity(pos)
	end,
	on_metadata_inventory_take = function(pos)
		update_entity(pos)
	end,
	after_destruct = function(pos)
		update_entity(pos)
		remove_hidden_node(pos)
	end,
	on_blast = function(pos)
		-- Not affected by TNT
	end,
})

minetest.register_entity("3d_armor_stand:armor_entity", {
	physical = true,
	visual = "mesh",
	mesh = "3d_armor_entity.obj",
	visual_size = {x=1, y=1},
	collisionbox = {0,0,0,0,0,0},
	textures = {"3d_armor_trans.png"},
	pos = nil,
	timer = 0,
	on_activate = function(self)
		local pos = self.object:get_pos()
		if pos then
			self.pos = vector.round(pos)
			update_entity(pos)
		end
	end,
	on_blast = function(self, damage)
		local drops = {}
		local node = minetest.get_node(self.pos)
		if node.name == "3d_armor_stand:armor_stand" then
			drop_armor(self.pos)
			self.object:remove()
		end
		return false, false, drops
	end,
})

minetest.register_abm({
	nodenames = {"3d_armor_stand:locked_armor_stand", "3d_armor_stand:armor_stand"},
	interval = 15,
	chance = 1,
	action = function(pos, node, active_object_count, active_object_count_wider)
		local num
		num = #minetest.get_objects_inside_radius(pos, 0.5)
		if num > 0 then return end
		update_entity(pos)
	end
})

minetest.register_craft({
	output = "3d_armor_stand:armor_stand",
	recipe = {
		{"", "group:fence", ""},
		{"", "group:fence", ""},
		{"default:steel_ingot", "default:steel_ingot", "default:steel_ingot"},
	}
})

minetest.register_craft({
	output = "3d_armor_stand:locked_armor_stand",
	recipe = {
		{"3d_armor_stand:armor_stand", "default:steel_ingot"},
	}
})


code:
# textdomain: 3d_armor_stand

### init.lua ###

Armor Stand=Support d'armure
Armor Stand (owned by @1)=Support d'armure (propriété de @1)
Armor stand=Support d'armure
Armor stand top=Haut de support d'armure
Locked Armor stand=Support d'armure verrouillé


code:
# textdomain: 3d_armor_stand

### init.lua ###

Armor Stand=
Armor Stand (owned by @1)=
Armor stand=
Armor stand top=
Locked Armor stand=


code:
name = 3d_armor_stand
depends = 3d_armor


code:
Modpack - 3d Armor [0.4.13]
===========================

![](https://github.com/minetest-mods/3d_armor/workflows/luacheck/badge.svg)
![](https://github.com/minetest-mods/3d_armor/workflows/integration-test/badge.svg)

### Table of Contents
<!-- START doctoc generated TOC please keep comment here to allow auto update -->
<!-- DON'T EDIT THIS SECTION, INSTEAD RE-RUN doctoc TO UPDATE -->
<!-- END doctoc generated TOC please keep comment here to allow auto update -->

- [[mod] Visible Player Armor [3d_armor]](#mod-visible-player-armor-3d_armor)
- [[mod] Visible Wielded Items [wieldview]](#mod-visible-wielded-items-wieldview)
- [[mod] Shields [shields]](#mod-shields-shields)
- [[mod] 3d Armor Stand [3d_armor_stand]](#mod-3d-armor-stand-3d_armor_stand)

<!-- END doctoc generated TOC please keep comment here to allow auto update -->

[mod] Visible Player Armor [3d_armor]
-------------------------------------

Minetest Version: 5.0.0

Game: minetest_game and many derivatives

Depends: default

Adds craftable armor that is visible to other players. Each armor item worn contributes to
a player's armor group level making them less vulnerable to attack.

Armor takes damage when a player is hurt, however, many armor items offer a 'stackable'
percentage chance of restoring the lost health points. Overall armor level is boosted by 10%
when wearing a full matching set (helmet, chestplate, leggings and boots of the same material)

Fire protection has been added by TenPlus1 and in use when ethereal mod is found and crystal
armor has been enabled.  each piece of armor offers 1 fire protection, level 1 protects
against torches, level 2 against crystal spikes, 3 for fire and 5 protects when in lava.

Compatible with sfinv, inventory plus or unified inventory by enabling the appropriate
inventory module, [3d_armor_sfinv], [3d_armor_ip] and [3d_armor_ui] respectively.
Also compatible with [smart_inventory] without the need for additional modules.

built in support player skins [skins] by Zeg9 and Player Textures [player_textures] by PilzAdam
and [simple_skins] by TenPlus1.

Armor can be configured by adding a file called armor.conf in 3d_armor mod or world directory.
see armor.conf.example for all available options.

For mod installation instructions, please visit: http://wiki.minetest.com/wiki/Installing_Mods

[mod] Visible Wielded Items [wieldview]
---------------------------------------

Depends: 3d_armor

Makes hand wielded items visible to other players.

[mod] Shields [shields]
-----------------------

Depends: 3d_armor

Originally a part of 3d_armor, shields have been re-included as an optional extra.
If you do not want shields then simply remove the shields folder from the modpack.

[mod] 3d Armor Stand [3d_armor_stand]
-------------------------------------

Depends: 3d_armor

Adds a chest-like armor stand for armor storage and display.


code: Visible player armor & wielded items.


code:
name = minetest-3d_armor
description = Visible player armor & wielded items.