[minetest-mod-3d-armor] 01/04: New upstream version 0.4.9

Julien Puydt julien.puydt at laposte.net
Tue May 2 07:59:28 UTC 2017


This is an automated email from the git hooks/post-receive script.

jpuydt-guest pushed a commit to annotated tag debian/0.4.9-1
in repository minetest-mod-3d-armor.

commit 5d9cc3c6554f7db89d30231bb7029a7100bb5524
Author: Julien Puydt <julien.puydt at laposte.net>
Date:   Tue May 2 09:07:17 2017 +0200

    New upstream version 0.4.9
---
 3d_armor/README.txt                         |  177 ++++-
 3d_armor/admin.lua                          |   45 --
 3d_armor/api.lua                            |  474 +++++++++++++
 3d_armor/armor.conf.example                 |    4 +
 3d_armor/armor.lua                          | 1015 +++++++++------------------
 3d_armor/depends.txt                        |    4 +-
 3d_armor/init.lua                           |  659 ++++++++++-------
 3d_armor_ip/LICENSE.txt                     |    5 +
 3d_armor_ip/depends.txt                     |    2 +
 3d_armor_ip/description.txt                 |    1 +
 3d_armor_ip/init.lua                        |   34 +
 3d_armor_sfinv/LICENSE.txt                  |    5 +
 {hazmat_suit => 3d_armor_sfinv}/depends.txt |    2 +-
 3d_armor_sfinv/description.txt              |    1 +
 3d_armor_sfinv/init.lua                     |   18 +
 3d_armor_stand/init.lua                     |   10 +-
 3d_armor_ui/LICENSE.txt                     |    5 +
 3d_armor_ui/depends.txt                     |    2 +
 3d_armor_ui/description.txt                 |    1 +
 3d_armor_ui/init.lua                        |   51 ++
 README.md                                   |   13 +-
 hazmat_suit/depends.txt                     |    2 +-
 hazmat_suit/init.lua                        |   56 +-
 shields/init.lua                            |  216 ++++--
 technic_armor/depends.txt                   |    2 +-
 technic_armor/init.lua                      |   33 +-
 wieldview/README.txt                        |   10 +-
 wieldview/depends.txt                       |    1 -
 wieldview/init.lua                          |   11 +-
 29 files changed, 1743 insertions(+), 1116 deletions(-)

diff --git a/3d_armor/README.txt b/3d_armor/README.txt
index 3ec204d..db445be 100644
--- a/3d_armor/README.txt
+++ b/3d_armor/README.txt
@@ -3,7 +3,9 @@
 
 Depends: default
 
-Recommends: sfinv, inventory_plus or unified_inventory (use only one to avoid conflicts)
+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.
@@ -14,10 +16,173 @@ 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.
 
-Configuration
--------------
+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 = 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 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
+
+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 = <table>
+	damage_groups = <table>
+	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:getpos()
+		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.
+
+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 can be configured by adding a file called armor.conf in 3d_armor mod and/or world directory.
-see armor.conf.example for all available options.
+armor:register_on_update(function(player)
+	print(player:get_player_name().." armor updated!")
+end)
 
-Note: worldpath config settings override any settings made in the mod's directory.
diff --git a/3d_armor/admin.lua b/3d_armor/admin.lua
deleted file mode 100644
index f499987..0000000
--- a/3d_armor/admin.lua
+++ /dev/null
@@ -1,45 +0,0 @@
-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")
-
-minetest.register_tool("3d_armor:helmet_admin", {
-	description = "Admin Helmet",
-	inventory_image = "3d_armor_inv_helmet_admin.png",
-	groups = {armor_head=1000, armor_heal=1000, armor_use=0, armor_water=1, not_in_creative_inventory=1},
-	wear = 0,
-	on_drop = function(itemstack, dropper, pos)
-		return
-	end,
-})
-
-minetest.register_tool("3d_armor:chestplate_admin", {
-	description = "Admin Chestplate",
-	inventory_image = "3d_armor_inv_chestplate_admin.png",
-	groups = {armor_torso=1000, armor_heal=1000, armor_use=0, not_in_creative_inventory=1},
-	wear = 0,
-	on_drop = function(itemstack, dropper, pos)
-		return
-	end,
-})
-
-minetest.register_tool("3d_armor:leggings_admin", {
-	description = "Admin Leggings",
-	inventory_image = "3d_armor_inv_leggings_admin.png",
-	groups = {armor_legs=1000, armor_heal=1000, armor_use=0, not_in_creative_inventory=1},
-	wear = 0,
-	on_drop = function(itemstack, dropper, pos)
-		return
-	end,
-})
-
-minetest.register_tool("3d_armor:boots_admin", {
-	description = "Admin Boots",
-	inventory_image = "3d_armor_inv_boots_admin.png",
-	groups = {armor_feet=1000, armor_heal=1000, armor_use=0, not_in_creative_inventory=1},
-	wear = 0,
-	on_drop = function(itemstack, dropper, pos)
-		return
-	end,
-})
-
diff --git a/3d_armor/api.lua b/3d_armor/api.lua
new file mode 100644
index 0000000..00ec740
--- /dev/null
+++ b/3d_armor/api.lua
@@ -0,0 +1,474 @@
+local skin_previews = {}
+local use_player_monoids = minetest.global_exists("player_monoids")
+local use_armor_monoid = minetest.global_exists("armor_monoid")
+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 = "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 = {},
+	},
+	version = "0.4.9",
+}
+
+armor.config = {
+	init_delay = 2,
+	init_times = 10,
+	bones_delay = 1,
+	update_time = 1,
+	drop = minetest.get_modpath("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)
+	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
+end
+
+armor.set_player_armor = function(self, player)
+	local name, player_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 textures = {}
+	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 = player_inv:get_list("armor")
+	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
+				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
+		self.def[name][attr] = attributes[attr]
+	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
+		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")
+	else
+		player:set_physics_override(physics)
+	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)
+	self:run_callbacks("on_update", player)
+end
+
+armor.punch = function(self, player, hitter, time_from_last_punch, tool_capabilities)
+	local name, player_inv = self:get_valid_player(player, "[punch]")
+	if not name then
+		return
+	end
+	local state = 0
+	local count = 0
+	local recip = true
+	local default_groups = {cracky=3, snappy=3, choppy=3, crumbly=3, level=1}
+	local list = player_inv:get_list("armor")
+	for i, stack in pairs(list) do
+		if stack:get_count() == 1 then
+			local name = stack:get_name()
+			local use = minetest.get_item_group(name, "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(name, "flammable") > 0
+			end
+			if damage == true then
+				self:damage(player, i, stack, use)
+			end
+			state = state + stack:get_wear()
+			count = count + 1
+		end
+	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, i, 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_player_skin = function(self, name)
+	local skin = nil
+	if self.skin_mod == "skins" or self.skin_mod == "simple_skins" then
+		skin = skins.skins[name]
+	elseif self.skin_mod == "u_skins" then
+		skin = u_skins.u_skins[name]
+	elseif self.skin_mod == "wardrobe" then
+		local skins = wardrobe.playerSkins or {}
+		if skins[name] then
+			skin = string.gsub(skins[name], "%.png$","")
+		end
+	end
+	return skin or armor.default_skin
+end
+
+armor.add_preview = function(self, preview)
+	skin_previews[preview] = true
+end
+
+armor.get_preview = function(self, name)
+	local preview = armor:get_player_skin(name).."_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)
+	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.attributes) do
+		formspec = formspec:gsub("armor_group_"..group, armor.def[name][group])
+	end
+	return formspec
+end
+
+armor.update_inventory = function(self, player)
+	-- DEPRECATED: Legacy inventory support
+end
+
+armor.set_inventory_stack = function(self, player, i, stack)
+	local msg = "[set_inventory_stack]"
+	local name = player:get_player_name()
+	if not name then
+		minetest.log("warning", "3d_armor: Player name is nil "..msg)
+		return
+	end
+	local player_inv = player:get_inventory()
+	local armor_inv = minetest.get_inventory({type="detached", name=name.."_armor"})
+	if not player_inv then
+		minetest.log("warning", "3d_armor: Player inventory is nil "..msg)
+		return
+	elseif not armor_inv then
+		minetest.log("warning", "3d_armor: Detached armor inventory is nil "..msg)
+		return
+	end
+	player_inv:set_stack("armor", i, stack)
+	armor_inv:set_stack("armor", i, stack)
+end
+
+armor.get_valid_player = function(self, player, msg)
+	msg = msg or ""
+	if not player then
+		minetest.log("warning", "3d_armor: Player reference is nil "..msg)
+		return
+	end
+	local name = player:get_player_name()
+	if not name then
+		minetest.log("warning", "3d_armor: Player name is nil "..msg)
+		return
+	end
+	local inv = player:get_inventory()
+	if not inv then
+		minetest.log("warning", "3d_armor: Player inventory is nil "..msg)
+		return
+	end
+	return name, inv
+end
+
+armor.drop_armor = function(pos, stack)
+	local obj = minetest.add_item(pos, stack)
+	if obj then
+		obj:setvelocity({x=math.random(-1, 1), y=5, z=math.random(-1, 1)})
+	end
+end
diff --git a/3d_armor/armor.conf.example b/3d_armor/armor.conf.example
index 75e072d..9ce34b4 100644
--- a/3d_armor/armor.conf.example
+++ b/3d_armor/armor.conf.example
@@ -1,3 +1,7 @@
+-- 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.
diff --git a/3d_armor/armor.lua b/3d_armor/armor.lua
index 49c2cae..306a687 100644
--- a/3d_armor/armor.lua
+++ b/3d_armor/armor.lua
@@ -1,717 +1,348 @@
-ARMOR_INIT_DELAY = 1
-ARMOR_INIT_TIMES = 1
-ARMOR_BONES_DELAY = 1
-ARMOR_UPDATE_TIME = 1
-ARMOR_DROP = minetest.get_modpath("bones") ~= nil
-ARMOR_DESTROY = false
-ARMOR_LEVEL_MULTIPLIER = 1
-ARMOR_HEAL_MULTIPLIER = 1
-ARMOR_RADIATION_MULTIPLIER = 1
-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",
-}
-ARMOR_FIRE_PROTECT = minetest.get_modpath("ethereal") ~= nil
-ARMOR_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},
-}
-
-local skin_mod = nil
-local inv_mod = nil
-local use_player_monoids = minetest.global_exists("player_monoids")
-local use_armor_monoid = minetest.global_exists("armor_monoid")
-local preview_textures = {}
-
-local modpath = minetest.get_modpath(ARMOR_MOD_NAME)
-local worldpath = minetest.get_worldpath()
-local input = io.open(modpath.."/armor.conf", "r")
-if input then
-	dofile(modpath.."/armor.conf")
-	input:close()
-	input = nil
-end
-input = io.open(worldpath.."/armor.conf", "r")
-if input then
-	dofile(worldpath.."/armor.conf")
-	input:close()
-	input = nil
+local S = function(s) return s end
+if minetest.global_exists("intllib") then
+	S = intllib.Getter()
 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
-
-armor = {
-	timer = 0,
-	elements = {"head", "torso", "legs", "feet"},
-	physics = {"jump","speed","gravity"},
-	formspec = "size[8,8.5]"..
-		default.gui_bg..
-		default.gui_bg_img..
-		default.gui_slots..
-		default.get_hotbar_bg(0,4.25)..
-		"image[2,0.5;2,4;armor_preview]"..
-		"list[current_player;main;0,4.25;8,1;]"..
-		"list[current_player;main;0,5.5;8,3;8]"..
-		"list[current_player;craft;4,0.5;3,3;]"..
-		"list[current_player;craftpreview;7,1.5;1,1;]"..
-		"listring[current_player;main]"..
-		"listring[current_player;craft]",
-	textures = {},
-	default_skin = "character",
-	version = "0.4.8",
-}
 
-local armor_formpage = "image[2.5,0;2,4;armor_preview]"..
-	default.gui_bg..
-	default.gui_bg_img..
-	default.gui_slots..
-	default.get_hotbar_bg(0,4.25)..
-	"label[5,1;Level: armor_level]"..
-	"label[5,1.5;Heal:  armor_heal]"..
-	"label[5,2;Fire:  armor_fire]"..
-	"label[5,2.5;Radiation:  armor_radiation]"..
-	"list[current_player;main;0,4.25;8,1;]"..
-	"list[current_player;main;0,5.5;8,3;8]"
-if minetest.get_modpath("inventory_plus") then
-	inv_mod = "inventory_plus"
-	armor.formspec = "size[8,8.5]button[6,0;2,0.5;main;Back]"..armor_formpage
-	if minetest.get_modpath("crafting") then
-		inventory_plus.get_formspec = function(player, page)
-		end
-	end
-elseif minetest.get_modpath("unified_inventory") and not unified_inventory.sfinv_compat_layer then
-	inv_mod = "unified_inventory"
-	unified_inventory.register_button("armor", {
-		type = "image",
-		image = "inventory_plus_armor.png",
-	})
-	unified_inventory.register_page("armor", {
-		get_formspec = function(player, perplayer_formspec)
-			local fy = perplayer_formspec.formspec_y
-			local name = player:get_player_name()
-			local formspec = "background[0.06,"..fy..";7.92,7.52;3d_armor_ui_form.png]"..
-				"label[0,0;Armor]"..
-				"list[detached:"..name.."_armor;armor;0,"..fy..";2,3;]"..
-				"image[2.5,"..(fy - 0.25)..";2,4;"..armor.textures[name].preview.."]"..
-				"label[5.0,"..(fy + 0.0)..";Level: "..armor.def[name].level.."]"..
-				"label[5.0,"..(fy + 0.5)..";Heal:  "..armor.def[name].heal.."]"..
-				"label[5.0,"..(fy + 1.0)..";Fire:  "..armor.def[name].fire.."]"..
-				"label[5.0,"..(fy + 1.5)..";Radiation:  "..armor.def[name].radiation.."]"..
-				"listring[current_player;main]"..
-				"listring[detached:"..name.."_armor;armor]"
-			return {formspec=formspec}
-		end,
-	})
-elseif minetest.get_modpath("inventory_enhanced") then
-	inv_mod = "inventory_enhanced"
-elseif minetest.get_modpath("smart_inventory") then
-	inv_mod = "smart_inventory"
-elseif minetest.get_modpath("sfinv") then
-	inv_mod = "sfinv"
-	armor.formspec = armor_formpage
-	sfinv.register_page("3d_armor:armor", {
-		title = "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
-	})
-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
-				preview_textures[fn] = true
-			end
-		end
-		skin_mod = mod
-	end
-end
+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.def = {
-	state = 0,
-	count = 0,
-}
+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.update_player_visuals = function(self, player)
-	if not player then
+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
-	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
-end
+	end,
+})
 
-armor.set_player_armor = function(self, player)
-	local name, player_inv = armor:get_valid_player(player, "[set_player_armor]")
-	if not name then
+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
-	local armor_texture = "3d_armor_trans.png"
-	local armor_level = 0
-	local armor_heal = 0
-	local armor_fire = 0
-	local armor_water = 0
-	local armor_radiation = 0
-	local state = 0
-	local items = 0
-	local elements = {}
-	local textures = {}
-	local physics_o = {speed=1,gravity=1,jump=1}
-	local material = {type=nil, count=1}
-	local preview = armor:get_preview(name)
-	for _,v in ipairs(self.elements) do
-		elements[v] = false
-	end
-	for i=1, 6 do
-		local stack = player_inv:get_stack("armor", i)
-		local item = stack:get_name()
-		if stack:get_count() == 1 then
-			local def = stack:get_definition()
-			for k, v in pairs(elements) do
-				if v == false then
-					local level = def.groups["armor_"..k]
-					if level then
-						local texture = def.texture or item:gsub("%:", "_")
-						table.insert(textures, texture..".png")
-						preview = preview.."^"..texture.."_preview.png"
-						armor_level = armor_level + level
-						state = state + stack:get_wear()
-						items = items + 1
-						armor_heal = armor_heal + (def.groups["armor_heal"] or 0)
-						armor_fire = armor_fire + (def.groups["armor_fire"] or 0)
-						armor_water = armor_water + (def.groups["armor_water"] or 0)
-						armor_radiation = armor_radiation + (def.groups["armor_radiation"] or 0)
-						for kk,vv in ipairs(self.physics) do
-							local o_value = def.groups["physics_"..vv]
-							if o_value then
-								physics_o[vv] = physics_o[vv] + o_value
-							end
-						end
-						local mat = string.match(item, "%:.+_(.+)$")
-						if material.type then
-							if material.type == mat then
-								material.count = material.count + 1
-							end
-						else
-							material.type = mat
-						end
-						elements[k] = true
-					end
-				end
-			end
-		end
-	end
-	if minetest.get_modpath("shields") then
-		armor_level = armor_level * 0.9
-	end
-	if material.type and material.count == #self.elements then
-		armor_level = armor_level * 1.1
-	end
-	armor_level = armor_level * ARMOR_LEVEL_MULTIPLIER
-	armor_heal = armor_heal * ARMOR_HEAL_MULTIPLIER
-	armor_radiation = armor_radiation * ARMOR_RADIATION_MULTIPLIER
-	if #textures > 0 then
-		armor_texture = table.concat(textures, "^")
-	end
-	local armor_groups = {fleshy=100}
-	if armor_level > 0 then
-		armor_groups.level = math.floor(armor_level / 20)
-		armor_groups.fleshy = 100 - armor_level
-		armor_groups.radiation = 100 - armor_radiation
-	end
-	if use_armor_monoid then
-		armor_monoid.monoid:add_change(player, {
-			fleshy = armor_groups.fleshy / 100
-		}, "3d_armor:armor")
-	else
-		player:set_armor_groups(armor_groups)
-	end
-	if use_player_monoids then
-		player_monoids.speed:add_change(player, physics_o.speed,
-			"3d_armor:physics")
-		player_monoids.jump:add_change(player, physics_o.jump,
-			"3d_armor:physics")
-		player_monoids.gravity:add_change(player, physics_o.gravity,
-			"3d_armor:physics")
-	else
-		player:set_physics_override(physics_o)
-	end
-	self.textures[name].armor = armor_texture
-	self.textures[name].preview = preview
-	self.def[name].state = state
-	self.def[name].count = items
-	self.def[name].level = armor_level
-	self.def[name].heal = armor_heal
-	self.def[name].jump = physics_o.jump
-	self.def[name].speed = physics_o.speed
-	self.def[name].gravity = physics_o.gravity
-	self.def[name].fire = armor_fire
-	self.def[name].water = armor_water
-	self.def[name].radiation = armor_radiation
-	self:update_player_visuals(player)
-end
+	end,
+})
 
-armor.update_armor = function(self, player)
-	-- Legacy support: Called when armor levels are changed
-	-- Other mods can hook on to this function, see hud mod for example
-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")
 
-armor.get_player_skin = function(self, name)
-	local skin = nil
-	if skin_mod == "skins" or skin_mod == "simple_skins" then
-		skin = skins.skins[name]
-	elseif skin_mod == "u_skins" then
-		skin = u_skins.u_skins[name]
-	elseif skin_mod == "wardrobe" then
-		skin = string.gsub(wardrobe.playerSkins[name], "%.png$","")
-	end
-	return skin or armor.default_skin
+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},
+	})
 end
 
-armor.get_preview = function(self, name)
-	local preview = armor:get_player_skin(name).."_preview.png"
-	if preview_textures[preview] then
-		return preview
-	end
-	return "character_preview.png"
+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},
+	})
 end
 
-armor.get_armor_formspec = function(self, name, listring)
-	if not armor.textures[name] then
-		minetest.log("error", "3d_armor: Player texture["..name.."] is nil [get_armor_formspec]")
-		return ""
-	end
-	if not armor.def[name] then
-		minetest.log("error", "3d_armor: Armor def["..name.."] is nil [get_armor_formspec]")
-		return ""
-	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)
-	formspec = formspec:gsub("armor_level", armor.def[name].level)
-	formspec = formspec:gsub("armor_heal", armor.def[name].heal)
-	formspec = formspec:gsub("armor_fire", armor.def[name].fire)
-	formspec = formspec:gsub("armor_radiation", armor.def[name].radiation)
-	formspec = formspec:gsub("player_name", armor.def[name].radiation)
-	return formspec
+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
 
-armor.update_inventory = function(self, player)
-	local name = armor:get_valid_player(player, "[set_player_armor]")
-	if not name or inv_mod == "inventory_enhanced" then
-		return
-	end
-	if inv_mod == "smart_inventory" then
-		local state = smart_inventory.get_page_state("player", name)
-		if state then
-			state:get("update_hook"):submit()
-		end
-	elseif inv_mod == "sfinv" then
-		if sfinv.set_page then
-			sfinv.set_page(player, "3d_armor:armor")
-		else
-			-- Backwards compat
-			sfinv.set_player_inventory_formspec(player, {
-				page = "3d_armor:armor"
-			})
-		end
-	elseif inv_mod == "unified_inventory" then
-		if unified_inventory.current_page[name] == "armor" then
-			unified_inventory.set_inventory_formspec(player, "armor")
-		end
-	else
-		if inv_mod == "inventory_plus" then
-			local formspec = armor:get_armor_formspec(name, true)
-			local page = player:get_inventory_formspec()
-			if page:find("detached:"..name.."_armor") then
-				inventory_plus.set_inventory_formspec(player, formspec)
-			end
-		elseif not core.setting_getbool("creative_mode") then
-			local formspec = armor:get_armor_formspec(name)
-			player:set_inventory_formspec(formspec)
-		end
-	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
 
-armor.get_valid_player = function(self, player, msg)
-	msg = msg or ""
-	if not player then
-		minetest.log("error", "3d_armor: Player reference is nil "..msg)
-		return
-	end
-	local name = player:get_player_name()
-	if not name then
-		minetest.log("error", "3d_armor: Player name is nil "..msg)
-		return
-	end
-	local pos = player:getpos()
-	local player_inv = player:get_inventory()
-	local armor_inv = minetest.get_inventory({type="detached", name=name.."_armor"})
-	if not pos then
-		minetest.log("error", "3d_armor: Player position is nil "..msg)
-		return
-	elseif not player_inv then
-		minetest.log("error", "3d_armor: Player inventory is nil "..msg)
-		return
-	elseif not armor_inv then
-		minetest.log("error", "3d_armor: Detached armor inventory is nil "..msg)
-		return
-	end
-	return name, player_inv, armor_inv, pos
+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
 
-armor.drop_armor = function(pos, stack)
-	local obj = minetest.add_item(pos, stack)
-	if obj then
-		obj:setvelocity({x=math.random(-1, 1), y=5, z=math.random(-1, 1)})
-	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
 
--- Register 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},
-	},
-})
-
--- Register Callbacks
-
-minetest.register_on_player_receive_fields(function(player, formname, fields)
-	local name = armor:get_valid_player(player, "[on_player_receive_fields]")
-	if not name or inv_mod == "inventory_enhanced" then
-		return
-	end
-	if inv_mod == "inventory_plus" and fields.armor then
-		local formspec = armor:get_armor_formspec(name, true)
-		inventory_plus.set_inventory_formspec(player, formspec)
-		return
-	end
-	for field, _ in pairs(fields) do
-		if string.find(field, "skins_set") then
-			minetest.after(0, function(player)
-				local skin = armor:get_player_skin(name)
-				armor.textures[name].skin = skin..".png"
-				armor:set_player_armor(player)
-			end, player)
-		end
-	end
-end)
-
-minetest.register_on_joinplayer(function(player)
-	default.player_set_model(player, "3d_armor_character.b3d")
-	local name = player:get_player_name()
-	local player_inv = player:get_inventory()
-	local armor_inv = minetest.create_detached_inventory(name.."_armor", {
-		on_put = function(inv, listname, index, stack, player)
-			player:get_inventory():set_stack(listname, index, stack)
-			armor:set_player_armor(player)
-			armor:update_inventory(player)
-		end,
-		on_take = function(inv, listname, index, stack, player)
-			player:get_inventory():set_stack(listname, index, nil)
-			armor:set_player_armor(player)
-			armor:update_inventory(player)
-		end,
-		on_move = function(inv, from_list, from_index, to_list, to_index, count, player)
-			local plaver_inv = player:get_inventory()
-			local stack = inv:get_stack(to_list, to_index)
-			player_inv:set_stack(to_list, to_index, stack)
-			player_inv:set_stack(from_list, from_index, nil)
-			armor:set_player_armor(player)
-			armor:update_inventory(player)
-		end,
-		allow_put = function(inv, listname, index, stack, player)
-			return 1
-		end,
-		allow_take = function(inv, listname, index, stack, player)
-			return stack:get_count()
-		end,
-		allow_move = function(inv, from_list, from_index, to_list, to_index, count, player)
-			return count
-		end,
-	}, name)
-	if inv_mod == "inventory_plus" then
-		inventory_plus.register_button(player,"armor", "Armor")
-	end
-	armor_inv:set_size("armor", 6)
-	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.def[name] = {
-		state = 0,
-		count = 0,
-		level = 0,
-		heal = 0,
-		jump = 1,
-		speed = 1,
-		gravity = 1,
-		fire = 0,
-		water = 0,
-		radiation = 0,
-	}
-	armor.textures[name] = {
-		skin = armor.default_skin..".png",
-		armor = "3d_armor_trans.png",
-		wielditem = "3d_armor_trans.png",
-		preview = armor.default_skin.."_preview.png",
-	}
-	if skin_mod == "skins" then
-		local skin = skins.skins[name]
-		if skin and skins.get_type(skin) == skins.type.MODEL then
-			armor.textures[name].skin = skin..".png"
-		end
-	elseif skin_mod == "simple_skins" then
-		local skin = skins.skins[name]
-		if skin then
-			armor.textures[name].skin = skin..".png"
-		end
-	elseif skin_mod == "u_skins" then
-		local skin = u_skins.u_skins[name]
-		if skin and u_skins.get_type(skin) == u_skins.type.MODEL then
-			armor.textures[name].skin = skin..".png"
-		end
-	elseif skin_mod == "wardrobe" then
-		local skin = wardrobe.playerSkins[name]
-		if skin then
-			armor.textures[name].skin = skin
-		end
-	end
-	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
-	for i=1, ARMOR_INIT_TIMES do
-		minetest.after(ARMOR_INIT_DELAY * i, function(player)
-			armor:set_player_armor(player)
-			if not inv_mod then
-				armor:update_inventory(player)
-			end
-		end, player)
-	end
-end)
-
-if ARMOR_DROP == true or ARMOR_DESTROY == true then
-	minetest.register_on_dieplayer(function(player)
-		local name, player_inv, armor_inv, pos = armor:get_valid_player(player, "[on_dieplayer]")
-		if not name then
-			return
-		end
-		local drop = {}
-		for i=1, player_inv:get_size("armor") do
-			local stack = armor_inv:get_stack("armor", i)
-			if stack:get_count() > 0 then
-				table.insert(drop, stack)
-				armor_inv:set_stack("armor", i, nil)
-				player_inv:set_stack("armor", i, nil)
-			end
-		end
-		armor:set_player_armor(player)
-		if inv_mod == "unified_inventory" then
-			unified_inventory.set_inventory_formspec(player, "craft")
-		elseif inv_mod == "inventory_plus" then
-			local formspec = inventory_plus.get_formspec(player,"main")
-			inventory_plus.set_inventory_formspec(player, formspec)
-		else
-			armor:update_inventory(player)
-		end
-		if ARMOR_DESTROY == false then
-			minetest.after(ARMOR_BONES_DELAY, function()
-				local meta = nil
-				local maxp = vector.add(pos, 8)
-				local minp = vector.subtract(pos, 8)
-				local bones = minetest.find_nodes_in_area(minp, maxp, {"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)
+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
 
-minetest.register_on_player_hpchange(function(player, hp_change)
-	local name, player_inv, armor_inv = armor:get_valid_player(player, "[on_hpchange]")
-	if name and hp_change < 0 then
-
-		-- used for insta kill tools/commands like /kill (doesnt damage armor)
-		if hp_change < -100 then
-			return hp_change
-		end
-
-		local heal_max = 0
-		local state = 0
-		local items = 0
-		for i=1, 6 do
-			local stack = player_inv:get_stack("armor", i)
-			if stack:get_count() > 0 then
-				local use = stack:get_definition().groups["armor_use"] or 0
-				local heal = stack:get_definition().groups["armor_heal"] or 0
-				local item = stack:get_name()
-				stack:add_wear(use)
-				armor_inv:set_stack("armor", i, stack)
-				player_inv:set_stack("armor", i, stack)
-				state = state + stack:get_wear()
-				items = items + 1
-				if stack:get_count() == 0 then
-					local desc = minetest.registered_items[item].description
-					if desc then
-						minetest.chat_send_player(name, "Your "..desc.." got destroyed!")
-					end
-					armor:set_player_armor(player)
-					armor:update_inventory(player)
-				end
-				heal_max = heal_max + heal
-			end
-		end
-		armor.def[name].state = state
-		armor.def[name].count = items
-		heal_max = heal_max * ARMOR_HEAL_MULTIPLIER
-		if heal_max > math.random(100) then
-			hp_change = 0
-		end
-		armor:update_armor(player)
-	end
-	return hp_change
-end, true)
-
--- Fire Protection and water breating, added by TenPlus1
-
-if ARMOR_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 ("[3d_armor] Fire Nodes disabled")
+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
 
-minetest.register_globalstep(function(dtime)
-	armor.timer = armor.timer + dtime
-	if armor.timer < ARMOR_UPDATE_TIME then
-		return
-	end
-	for _,player in pairs(minetest.get_connected_players()) do
-		local name = player:get_player_name()
-		local pos = player:getpos()
-		local hp = player:get_hp()
-		-- water breathing
-		if name and armor.def[name].water > 0 then
-			if player:get_breath() < 10 then
-				player:set_breath(10)
-			end
-		end
-		-- fire protection
-		if ARMOR_FIRE_PROTECT == true
-		and name and pos and hp then
-			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 hp > 0 and armor.def[name].fire < row[2] then
-						hp = hp - row[3] * ARMOR_UPDATE_TIME
-						player:set_hp(hp)
-						break
-					end
-				end
-			end
-		end
-	end
-	armor.timer = 0
-end)
-
--- kill player when command issued
-minetest.register_chatcommand("kill", {
-	params = "<name>",
-	description = "Kills player instantly",
-	privs = {ban=true},
-	func = function(name, param)
-		local player = minetest.get_player_by_name(param)
-		if player then
-			player:set_hp(0)
-		end
-	end,
-})
-
-minetest.register_chatcommand("killme", {
-	description = "Kill yourself instantly",
-	func = function(name)
-		local player = minetest.get_player_by_name(name)
-		if player then
-			player:set_hp(-1001)
-		end
-	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
diff --git a/3d_armor/depends.txt b/3d_armor/depends.txt
index 0d20f61..fa1b233 100644
--- a/3d_armor/depends.txt
+++ b/3d_armor/depends.txt
@@ -1,9 +1,7 @@
 default
 player_monoids?
 armor_monoid?
-inventory_plus?
-unified_inventory?
-sfinv?
 fire?
 ethereal?
 bakedclay?
+intllib?
diff --git a/3d_armor/init.lua b/3d_armor/init.lua
index c73d2de..a96f480 100644
--- a/3d_armor/init.lua
+++ b/3d_armor/init.lua
@@ -1,254 +1,409 @@
-ARMOR_MOD_NAME = minetest.get_current_modname()
-dofile(minetest.get_modpath(ARMOR_MOD_NAME).."/armor.lua")
-dofile(minetest.get_modpath(ARMOR_MOD_NAME).."/admin.lua")
-
-if ARMOR_MATERIALS.wood then
-	minetest.register_tool("3d_armor:helmet_wood", {
-		description = "Wood Helmet",
-		inventory_image = "3d_armor_inv_helmet_wood.png",
-		groups = {armor_head=5, armor_heal=0, armor_use=2000},
-		wear = 0,
-	})
-	minetest.register_tool("3d_armor:chestplate_wood", {
-		description = "Wood Chestplate",
-		inventory_image = "3d_armor_inv_chestplate_wood.png",
-		groups = {armor_torso=10, armor_heal=0, armor_use=2000},
-		wear = 0,
-	})
-	minetest.register_tool("3d_armor:leggings_wood", {
-		description = "Wood Leggings",
-		inventory_image = "3d_armor_inv_leggings_wood.png",
-		groups = {armor_legs=5, armor_heal=0, armor_use=2000},
-		wear = 0,
-	})
-	minetest.register_tool("3d_armor:boots_wood", {
-		description = "Wood Boots",
-		inventory_image = "3d_armor_inv_boots_wood.png",
-		groups = {armor_feet=5, armor_heal=0, armor_use=2000},
-		wear = 0,
-	})
-end
-
-if ARMOR_MATERIALS.cactus then
-	minetest.register_tool("3d_armor:helmet_cactus", {
-		description = "Cactuc Helmet",
-		inventory_image = "3d_armor_inv_helmet_cactus.png",
-		groups = {armor_head=5, armor_heal=0, armor_use=1000},
-		wear = 0,
-	})
-	minetest.register_tool("3d_armor:chestplate_cactus", {
-		description = "Cactus Chestplate",
-		inventory_image = "3d_armor_inv_chestplate_cactus.png",
-		groups = {armor_torso=10, armor_heal=0, armor_use=1000},
-		wear = 0,
-	})
-	minetest.register_tool("3d_armor:leggings_cactus", {
-		description = "Cactus Leggings",
-		inventory_image = "3d_armor_inv_leggings_cactus.png",
-		groups = {armor_legs=5, armor_heal=0, armor_use=1000},
-		wear = 0,
-	})
-	minetest.register_tool("3d_armor:boots_cactus", {
-		description = "Cactus Boots",
-		inventory_image = "3d_armor_inv_boots_cactus.png",
-		groups = {armor_feet=5, armor_heal=0, armor_use=1000},
-		wear = 0,
-	})
-end
-
-if ARMOR_MATERIALS.steel then
-	minetest.register_tool("3d_armor:helmet_steel", {
-		description = "Steel Helmet",
-		inventory_image = "3d_armor_inv_helmet_steel.png",
-		groups = {armor_head=10, armor_heal=0, armor_use=500},
-		wear = 0,
-	})
-	minetest.register_tool("3d_armor:chestplate_steel", {
-		description = "Steel Chestplate",
-		inventory_image = "3d_armor_inv_chestplate_steel.png",
-		groups = {armor_torso=15, armor_heal=0, armor_use=500},
-		wear = 0,
-	})
-	minetest.register_tool("3d_armor:leggings_steel", {
-		description = "Steel Leggings",
-		inventory_image = "3d_armor_inv_leggings_steel.png",
-		groups = {armor_legs=15, armor_heal=0, armor_use=500},
-		wear = 0,
-	})
-	minetest.register_tool("3d_armor:boots_steel", {
-		description = "Steel Boots",
-		inventory_image = "3d_armor_inv_boots_steel.png",
-		groups = {armor_feet=10, armor_heal=0, armor_use=500},
-		wear = 0,
-	})
-end
-
-if ARMOR_MATERIALS.bronze then
-	minetest.register_tool("3d_armor:helmet_bronze", {
-		description = "Bronze Helmet",
-		inventory_image = "3d_armor_inv_helmet_bronze.png",
-		groups = {armor_head=10, armor_heal=6, armor_use=250},
-		wear = 0,
-	})
-	minetest.register_tool("3d_armor:chestplate_bronze", {
-		description = "Bronze Chestplate",
-		inventory_image = "3d_armor_inv_chestplate_bronze.png",
-		groups = {armor_torso=15, armor_heal=6, armor_use=250},
-		wear = 0,
-	})
-	minetest.register_tool("3d_armor:leggings_bronze", {
-		description = "Bronze Leggings",
-		inventory_image = "3d_armor_inv_leggings_bronze.png",
-		groups = {armor_legs=15, armor_heal=6, armor_use=250},
-		wear = 0,
-	})
-	minetest.register_tool("3d_armor:boots_bronze", {
-		description = "Bronze Boots",
-		inventory_image = "3d_armor_inv_boots_bronze.png",
-		groups = {armor_feet=10, armor_heal=6, armor_use=250},
-		wear = 0,
-	})
-end
-
-if ARMOR_MATERIALS.diamond then
-	minetest.register_tool("3d_armor:helmet_diamond", {
-		description = "Diamond Helmet",
-		inventory_image = "3d_armor_inv_helmet_diamond.png",
-		groups = {armor_head=15, armor_heal=12, armor_use=100},
-		wear = 0,
-	})
-	minetest.register_tool("3d_armor:chestplate_diamond", {
-		description = "Diamond Chestplate",
-		inventory_image = "3d_armor_inv_chestplate_diamond.png",
-		groups = {armor_torso=20, armor_heal=12, armor_use=100},
-		wear = 0,
-	})
-	minetest.register_tool("3d_armor:leggings_diamond", {
-		description = "Diamond Leggings",
-		inventory_image = "3d_armor_inv_leggings_diamond.png",
-		groups = {armor_legs=20, armor_heal=12, armor_use=100},
-		wear = 0,
-	})
-	minetest.register_tool("3d_armor:boots_diamond", {
-		description = "Diamond Boots",
-		inventory_image = "3d_armor_inv_boots_diamond.png",
-		groups = {armor_feet=15, armor_heal=12, armor_use=100},
-		wear = 0,
-	})
-end
-
-if ARMOR_MATERIALS.gold then
-	minetest.register_tool("3d_armor:helmet_gold", {
-		description = "Gold Helmet",
-		inventory_image = "3d_armor_inv_helmet_gold.png",
-		groups = {armor_head=10, armor_heal=6, armor_use=250},
-		wear = 0,
-	})
-	minetest.register_tool("3d_armor:chestplate_gold", {
-		description = "Gold Chestplate",
-		inventory_image = "3d_armor_inv_chestplate_gold.png",
-		groups = {armor_torso=15, armor_heal=6, armor_use=250},
-		wear = 0,
-	})
-	minetest.register_tool("3d_armor:leggings_gold", {
-		description = "Gold Leggings",
-		inventory_image = "3d_armor_inv_leggings_gold.png",
-		groups = {armor_legs=15, armor_heal=6, armor_use=250},
-		wear = 0,
-	})
-	minetest.register_tool("3d_armor:boots_gold", {
-		description = "Gold Boots",
-		inventory_image = "3d_armor_inv_boots_gold.png",
-		groups = {armor_feet=10, armor_heal=6, armor_use=250},
-		wear = 0,
-	})
-end
-
-if ARMOR_MATERIALS.mithril then
-	minetest.register_tool("3d_armor:helmet_mithril", {
-		description = "Mithril Helmet",
-		inventory_image = "3d_armor_inv_helmet_mithril.png",
-		groups = {armor_head=15, armor_heal=12, armor_use=50},
-		wear = 0,
-	})
-	minetest.register_tool("3d_armor:chestplate_mithril", {
-		description = "Mithril Chestplate",
-		inventory_image = "3d_armor_inv_chestplate_mithril.png",
-		groups = {armor_torso=20, armor_heal=12, armor_use=50},
-		wear = 0,
-	})
-	minetest.register_tool("3d_armor:leggings_mithril", {
-		description = "Mithril Leggings",
-		inventory_image = "3d_armor_inv_leggings_mithril.png",
-		groups = {armor_legs=20, armor_heal=12, armor_use=50},
-		wear = 0,
-	})
-	minetest.register_tool("3d_armor:boots_mithril", {
-		description = "Mithril Boots",
-		inventory_image = "3d_armor_inv_boots_mithril.png",
-		groups = {armor_feet=15, armor_heal=12, armor_use=50},
-		wear = 0,
-	})
-end
-
-if ARMOR_MATERIALS.crystal then
-	minetest.register_tool("3d_armor:helmet_crystal", {
-		description = "Crystal Helmet",
-		inventory_image = "3d_armor_inv_helmet_crystal.png",
-		groups = {armor_head=15, armor_heal=12, armor_use=50, armor_fire=1},
-		wear = 0,
-	})
-	minetest.register_tool("3d_armor:chestplate_crystal", {
-		description = "Crystal Chestplate",
-		inventory_image = "3d_armor_inv_chestplate_crystal.png",
-		groups = {armor_torso=20, armor_heal=12, armor_use=50, armor_fire=1},
-		wear = 0,
-	})
-	minetest.register_tool("3d_armor:leggings_crystal", {
-		description = "Crystal Leggings",
-		inventory_image = "3d_armor_inv_leggings_crystal.png",
-		groups = {armor_legs=20, armor_heal=12, armor_use=50, armor_fire=1},
-		wear = 0,
-	})
-	minetest.register_tool("3d_armor:boots_crystal", {
-		description = "Crystal Boots",
-		inventory_image = "3d_armor_inv_boots_crystal.png",
-		groups = {armor_feet=15, armor_heal=12, armor_use=50, physics_speed=1, physics_jump=0.5, armor_fire=1},
-		wear = 0,
-	})
-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},
-		},
-	})
+local S = function(s) return s end
+if minetest.global_exists("intllib") then
+	S = intllib.Getter()
 end
+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")
+
+-- Legacy Config Support
+
+local input = io.open(modpath.."/armor.conf", "r")
+if input then
+	dofile(modpath.."/armor.conf")
+	input:close()
+	input = nil
+end
+input = io.open(worldpath.."/armor.conf", "r")
+if input then
+	dofile(worldpath.."/armor.conf")
+	input:close()
+	input = nil
+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.setting_get("armor_"..name)
+	if type(config) == "number" then
+		setting = tonumber(setting)
+	elseif type(config) == "boolean" then
+		setting = minetest.setting_getbool("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
+
+dofile(modpath.."/armor.lua")
+
+-- Mod Compatibility
+
+if minetest.get_modpath("technic") then
+	armor.formspec = armor.formspec..
+		"label[5,2.5;"..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
+
+-- Armor Initialization
+
+armor.formspec = armor.formspec..
+	"label[5,1;"..S("Level")..": armor_level]"..
+	"label[5,1.5;"..S("Heal")..":  armor_attr_heal]"
+if armor.config.fire_protect then
+	armor.formspec = armor.formspec.."label[5,2;"..S("Fire")..":  armor_fire]"
+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").." "..def.description.." "..
+			S("got destroyed").."!")
+	end
+end)
+
+local function init_player_armor(player)
+	local name = player:get_player_name()
+	local player_inv = player:get_inventory()
+	local pos = player:getpos()
+	if not name or not player_inv or not pos then
+		return false
+	end
+	local armor_inv = minetest.create_detached_inventory(name.."_armor", {
+		on_put = function(inv, listname, index, stack, player)
+			player:get_inventory():set_stack(listname, index, stack)
+			armor:run_callbacks("on_equip", player, index, stack)
+			armor:set_player_armor(player)
+		end,
+		on_take = function(inv, listname, index, stack, player)
+			player:get_inventory():set_stack(listname, index, nil)
+			armor:run_callbacks("on_unequip", player, index, stack)
+			armor:set_player_armor(player)
+		end,
+		on_move = function(inv, from_list, from_index, to_list, to_index, count, player)
+			local plaver_inv = player:get_inventory()
+			local stack = inv:get_stack(to_list, to_index)
+			player_inv:set_stack(to_list, to_index, stack)
+			player_inv:set_stack(from_list, from_index, nil)
+			armor:set_player_armor(player)
+		end,
+		allow_put = function(inv, listname, index, stack, player)
+			local def = stack:get_definition() or {}
+			local allowed = 0
+			for _, element in pairs(armor.elements) do
+				if def.groups["armor_"..element] then
+					allowed = 1
+					for i = 1, 6 do
+						local item = inv:get_stack("armor", i):get_name()
+						if minetest.get_item_group(item, "armor_"..element) > 0 then
+							return 0
+						end
+					end
+				end
+			end
+			return allowed
+		end,
+		allow_take = function(inv, listname, index, stack, player)
+			return stack:get_count()
+		end,
+		allow_move = function(inv, from_list, from_index, to_list, to_index, count, player)
+			return count
+		end,
+	}, name)
+	armor_inv:set_size("armor", 6)
+	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)
+		armor:run_callbacks("on_equip", player, i, stack)
+	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..".png",
+		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(player)
+	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
+	for field, _ in pairs(fields) do
+		if string.find(field, "skins_set") then
+			minetest.after(0, function(player)
+				local skin = armor:get_player_skin(name)
+				armor.textures[name].skin = skin..".png"
+				armor:set_player_armor(player)
+			end, player)
+		end
+	end
+end)
+
+minetest.register_on_joinplayer(function(player)
+	default.player_set_model(player, "3d_armor_character.b3d")
+	minetest.after(0, function(player)
+		if init_player_armor(player) == false then
+			pending_players[player] = 0
+		end
+	end, player)
+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, player_inv = armor:get_valid_player(player, "[on_dieplayer]")
+		if not name then
+			return
+		end
+		local drop = {}
+		for i=1, player_inv:get_size("armor") do
+			local stack = player_inv:get_stack("armor", i)
+			if stack:get_count() > 0 then
+				table.insert(drop, stack)
+				armor:set_inventory_stack(player, i, nil)
+				armor:run_callbacks("on_unequip", player, i, stack)
+			end
+		end
+		armor:set_player_armor(player)
+		local pos = player:getpos()
+		if pos and armor.config.destroy == false then
+			minetest.after(armor.config.bones_delay, function()
+				local meta = nil
+				local maxp = vector.add(pos, 8)
+				local minp = vector.subtract(pos, 8)
+				local bones = minetest.find_nodes_in_area(minp, maxp, {"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)
+	if player and hp_change < 0 then
+		local name = player:get_player_name()
+		if name then
+			local heal = armor.def[name].heal
+			heal = heal * armor.config.heal_multiplier
+			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", "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 breating, 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 ("[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:getpos()
+			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
diff --git a/3d_armor_ip/LICENSE.txt b/3d_armor_ip/LICENSE.txt
new file mode 100644
index 0000000..6b58a7a
--- /dev/null
+++ b/3d_armor_ip/LICENSE.txt
@@ -0,0 +1,5 @@
+[mod] 3d Armor integration to inventory plus [3d_armor_ip]
+==========================================================
+
+License Source Code: (C) 2012-2017 Stuart Jones - LGPL v2.1
+
diff --git a/3d_armor_ip/depends.txt b/3d_armor_ip/depends.txt
new file mode 100644
index 0000000..e96293b
--- /dev/null
+++ b/3d_armor_ip/depends.txt
@@ -0,0 +1,2 @@
+3d_armor
+inventory_plus?
diff --git a/3d_armor_ip/description.txt b/3d_armor_ip/description.txt
new file mode 100644
index 0000000..01e1b54
--- /dev/null
+++ b/3d_armor_ip/description.txt
@@ -0,0 +1 @@
+Adds 3d_armor page to the inventory plus
diff --git a/3d_armor_ip/init.lua b/3d_armor_ip/init.lua
new file mode 100644
index 0000000..59c21c3
--- /dev/null
+++ b/3d_armor_ip/init.lua
@@ -0,0 +1,34 @@
+if not minetest.global_exists("inventory_plus") then
+	minetest.log("warning", "3d_armor_ip: Mod loaded but unused.")
+	return
+end
+
+armor.formspec = "size[8,8.5]button[6,0;2,0.5;main;Back]"..armor.formspec
+armor:register_on_update(function(player)
+	local name = player:get_player_name()
+	local formspec = armor:get_armor_formspec(name, true)
+	local page = player:get_inventory_formspec()
+	if page:find("detached:"..name.."_armor") then
+		inventory_plus.set_inventory_formspec(player, formspec)
+	end
+end)
+
+if minetest.get_modpath("crafting") then
+	inventory_plus.get_formspec = function(player, page)
+	end
+end
+
+minetest.register_on_joinplayer(function(player)
+	inventory_plus.register_button(player,"armor", "Armor")
+end)
+
+minetest.register_on_player_receive_fields(function(player, formname, fields)
+	if fields.armor then
+		local name = armor:get_valid_player(player, "[on_player_receive_fields]")
+		if not name then
+			return
+		end
+		local formspec = armor:get_armor_formspec(name, true)
+		inventory_plus.set_inventory_formspec(player, formspec)
+	end
+end)
diff --git a/3d_armor_sfinv/LICENSE.txt b/3d_armor_sfinv/LICENSE.txt
new file mode 100644
index 0000000..538b950
--- /dev/null
+++ b/3d_armor_sfinv/LICENSE.txt
@@ -0,0 +1,5 @@
+[mod] 3d Armor sfinv integration [3d_armor_sfinv]
+=================================================
+
+License Source Code: (C) 2012-2017 Stuart Jones - LGPL v2.1
+
diff --git a/hazmat_suit/depends.txt b/3d_armor_sfinv/depends.txt
similarity index 52%
copy from hazmat_suit/depends.txt
copy to 3d_armor_sfinv/depends.txt
index c83abc0..c7beeda 100644
--- a/hazmat_suit/depends.txt
+++ b/3d_armor_sfinv/depends.txt
@@ -1,2 +1,2 @@
 3d_armor
-technic
+sfinv?
diff --git a/3d_armor_sfinv/description.txt b/3d_armor_sfinv/description.txt
new file mode 100644
index 0000000..0ef2ae9
--- /dev/null
+++ b/3d_armor_sfinv/description.txt
@@ -0,0 +1 @@
+Adds 3d_armor page to the sfinv inventory
diff --git a/3d_armor_sfinv/init.lua b/3d_armor_sfinv/init.lua
new file mode 100644
index 0000000..ede9007
--- /dev/null
+++ b/3d_armor_sfinv/init.lua
@@ -0,0 +1,18 @@
+if not minetest.global_exists("sfinv") then
+	minetest.log("warning", "3d_armor_sfinv: Mod loaded but unused.")
+	return
+end
+
+sfinv.register_page("3d_armor:armor", {
+	title = "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)
diff --git a/3d_armor_stand/init.lua b/3d_armor_stand/init.lua
index 7fb5c3c..8ebc851 100644
--- a/3d_armor_stand/init.lua
+++ b/3d_armor_stand/init.lua
@@ -1,3 +1,7 @@
+local S = function(s) return s end
+if minetest.global_exists("intllib") then
+	S = intllib.Getter()
+end
 local armor_stand_formspec = "size[8,7]" ..
 	default.gui_bg ..
 	default.gui_bg_img ..
@@ -128,7 +132,7 @@ local function remove_hidden_node(pos)
 end
 
 minetest.register_node("3d_armor_stand:top", {
-	description = "Armor stand top",
+	description = S("Armor stand top"),
 	paramtype = "light",
 	drawtype = "plantlike",
 	sunlight_propagates = true,
@@ -143,7 +147,7 @@ minetest.register_node("3d_armor_stand:top", {
 })
 
 minetest.register_node("3d_armor_stand:armor_stand", {
-	description = "Armor stand",
+	description = S("Armor stand"),
 	drawtype = "mesh",
 	mesh = "3d_armor_stand.obj",
 	tiles = {"3d_armor_stand.png"},
@@ -211,7 +215,7 @@ minetest.register_node("3d_armor_stand:armor_stand", {
 })
 
 minetest.register_node("3d_armor_stand:locked_armor_stand", {
-	description = "Locked Armor stand",
+	description = S("Locked Armor stand"),
 	drawtype = "mesh",
 	mesh = "3d_armor_stand.obj",
 	tiles = {"3d_armor_stand_locked.png"},
diff --git a/3d_armor_ui/LICENSE.txt b/3d_armor_ui/LICENSE.txt
new file mode 100644
index 0000000..50859b0
--- /dev/null
+++ b/3d_armor_ui/LICENSE.txt
@@ -0,0 +1,5 @@
+[mod] 3d Armor integration to unified inventory [3d_armor_ui]
+=============================================================
+
+License Source Code: (C) 2012-2017 Stuart Jones - LGPL v2.1
+
diff --git a/3d_armor_ui/depends.txt b/3d_armor_ui/depends.txt
new file mode 100644
index 0000000..cf4ccf9
--- /dev/null
+++ b/3d_armor_ui/depends.txt
@@ -0,0 +1,2 @@
+3d_armor
+unified_inventory?
diff --git a/3d_armor_ui/description.txt b/3d_armor_ui/description.txt
new file mode 100644
index 0000000..873f876
--- /dev/null
+++ b/3d_armor_ui/description.txt
@@ -0,0 +1 @@
+Adds 3d_armor page to the unified inventory
diff --git a/3d_armor_ui/init.lua b/3d_armor_ui/init.lua
new file mode 100644
index 0000000..763e731
--- /dev/null
+++ b/3d_armor_ui/init.lua
@@ -0,0 +1,51 @@
+if not minetest.global_exists("unified_inventory") then
+	minetest.log("warning", "3d_armor_ui: Mod loaded but unused.")
+	return
+end
+local S = function(s) return s end
+if minetest.global_exists("intllib") then
+	S = intllib.Getter()
+end
+
+if unified_inventory.sfinv_compat_layer then
+	return
+end
+
+armor:register_on_update(function(player)
+	local name = player:get_player_name()
+	if unified_inventory.current_page[name] == "armor" then
+		unified_inventory.set_inventory_formspec(player, "armor")
+	end
+end)
+
+unified_inventory.register_button("armor", {
+	type = "image",
+	image = "inventory_plus_armor.png",
+})
+
+unified_inventory.register_page("armor", {
+	get_formspec = function(player, perplayer_formspec)
+		local fy = perplayer_formspec.formspec_y
+		local name = player:get_player_name()
+		if armor.def[name].init_time == 0 then
+			return {formspec="label[0,0;Armor not initialized!]"}
+		end
+		local formspec = "background[0.06,"..fy..";7.92,7.52;3d_armor_ui_form.png]"..
+			"label[0,0;Armor]"..
+			"list[detached:"..name.."_armor;armor;0,"..fy..";2,3;]"..
+			"image[2.5,"..(fy - 0.25)..";2,4;"..armor.textures[name].preview.."]"..
+			"label[5.0,"..(fy + 0.0)..";"..S("Level")..": "..armor.def[name].level.."]"..
+			"label[5.0,"..(fy + 0.5)..";"..S("Heal")..":  "..armor.def[name].heal.."]"..
+			"listring[current_player;main]"..
+			"listring[detached:"..name.."_armor;armor]"
+		if armor.config.fire_protect then
+			formspec = formspec.."label[5.0,"..(fy + 1.0)..";"..
+				S("Fire")..":  "..armor.def[name].fire.."]"
+		end
+		if minetest.global_exists("technic") then
+			formspec = formspec.."label[5.0,"..(fy + 1.5)..";"..
+				S("Radiation")..":  "..armor.def[name].groups["radiation"].."]"
+		end
+		return {formspec=formspec}
+	end,
+})
diff --git a/README.md b/README.md
index 42cd0d4..443c70b 100644
--- a/README.md
+++ b/README.md
@@ -1,4 +1,4 @@
-Modpack - 3d Armor [0.4.8]
+Modpack - 3d Armor [0.4.9]
 ==========================
 
 ### Table of Contents
@@ -19,14 +19,12 @@ Modpack - 3d Armor [0.4.8]
 [mod] Visible Player Armor [3d_armor]
 -------------------------------------
 
-Minetest Version: 0.4.13
+Minetest Version: 0.4.15
 
 Game: minetest_game and many derivatives
 
 Depends: default
 
-Recommends: inventory_plus or unified_inventory (use only one)
-
 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.
 
@@ -38,7 +36,11 @@ Fire protection has been added by TenPlus1 and in use when ethereal mod is found
 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 player skins [skins] by Zeg9 and Player Textures [player_textures] by PilzAdam
+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.
@@ -75,7 +77,6 @@ Depends: 3d_armor, technic
 Adds hazmat suit to 3d_armor. It protects rather well from fire (if enabled in configuration) and radiation*, and it has built-in oxygen supply.
 
 Requires technic mod.
-*Requires patched version of [technic mod](https://github.com/minetest-technic/technic/pull/275)
 
 [mod] 3d Armor Stand [3d_armor_stand]
 -------------------------------------
diff --git a/hazmat_suit/depends.txt b/hazmat_suit/depends.txt
index c83abc0..773b3fe 100644
--- a/hazmat_suit/depends.txt
+++ b/hazmat_suit/depends.txt
@@ -1,2 +1,2 @@
 3d_armor
-technic
+technic?
diff --git a/hazmat_suit/init.lua b/hazmat_suit/init.lua
index 9e84aef..df1d74e 100644
--- a/hazmat_suit/init.lua
+++ b/hazmat_suit/init.lua
@@ -1,70 +1,50 @@
-local part_count = 4
-
-local level = 35
-local heal = 20
-local use = 1000
-local fire = 4
-local water = 1
-local radiation = 50
-
-if minetest.get_modpath("shields") then
-	level = level / 0.9
+if not minetest.get_modpath("technic") then
+	minetest.log("warning", "hazmat_suit: Mod loaded but unused.")
+	return
 end
-
-if part_count == #armor.elements then
-	level = level / 1.1
+local S = function(s) return s end
+if minetest.global_exists("intllib") then
+	S = intllib.Getter()
 end
 
-level = math.floor(level / part_count)
-heal = math.floor(heal / part_count)
-fire = math.floor(fire / part_count)
-radiation = math.floor(radiation / part_count)
-
 minetest.register_craftitem("hazmat_suit:helmet_hazmat", {
-		description = "Hazmat Helmet",
+		description = S("Hazmat Helmet"),
 		inventory_image = "hazmat_suit_inv_helmet_hazmat.png",
 		stack_max = 1,
 })
 
 minetest.register_craftitem("hazmat_suit:chestplate_hazmat", {
-		description = "Hazmat Chestplate",
+		description = S("Hazmat Chestplate"),
 		inventory_image = "hazmat_suit_inv_chestplate_hazmat.png",
 		stack_max = 1,
 })
 
 minetest.register_craftitem("hazmat_suit:sleeve_hazmat", {
-		description = "Hazmat Sleeve",
+		description = S("Hazmat Sleeve"),
 		inventory_image = "hazmat_suit_inv_sleeve_hazmat.png",
 		stack_max = 1,
 })
 
 minetest.register_craftitem("hazmat_suit:leggings_hazmat", {
-		description = "Hazmat Leggins",
+		description = S("Hazmat Leggins"),
 		inventory_image = "hazmat_suit_inv_leggings_hazmat.png",
 		stack_max = 1,
 })
 
 minetest.register_craftitem("hazmat_suit:boots_hazmat", {
-		description = "Hazmat Boots",
+		description = S("Hazmat Boots"),
 		inventory_image = "hazmat_suit_inv_boots_hazmat.png",
 		stack_max = 1,
 })
 
-minetest.register_tool("hazmat_suit:suit_hazmat", {
-	description = "Hazmat Suit",
+armor:register_armor("hazmat_suit:suit_hazmat", {
+	description = S("Hazmat Suit"),
 	inventory_image = "hazmat_suit_inv_suit_hazmat.png",
-	groups = {
-		armor_head = level,
-		armor_torso = level,
-		armor_legs = level,
-		armor_feet = level,
-		armor_heal = heal,
-		armor_use = use,
-		armor_fire = fire,
-		armor_water = water,
-		armor_radiation = radiation,
-	},
-	wear = 0,
+	groups = {armor_head=1, armor_torso=1, armor_legs=1, armor_feet=1,
+		armor_heal=20, armor_fire=4, armor_water=1, armor_use=1000,
+		physics_jump=-0.1, physics_speed=-0.2, physics_gravity=0.1},
+	armor_groups = {fleshy=35, radiation=50},
+	damage_groups = {cracky=3, snappy=3, choppy=2, crumbly=2, level=1},
 })
 
 minetest.register_craft({
diff --git a/shields/init.lua b/shields/init.lua
index ccc86a5..3128eff 100644
--- a/shields/init.lua
+++ b/shields/init.lua
@@ -1,30 +1,75 @@
+local S = function(s) return s end
+if minetest.global_exists("intllib") then
+	S = intllib.Getter()
+end
 local use_moreores = minetest.get_modpath("moreores")
+local function play_sound_effect(player, name)
+	if player then
+		local pos = player:getpos()
+		if pos then
+			minetest.sound_play({
+				pos = pos,
+				name = name,
+				max_hear_distance = 10,
+				gain = 0.5,
+			})
+		end
+	end
+end
 
 if minetest.global_exists("armor") and armor.elements then
 	table.insert(armor.elements, "shield")
+	local mult = armor.config.level_multiplier or 1
+	armor.config.level_multiplier = mult * 0.9
 end
 
 -- Regisiter Shields
 
-minetest.register_tool("shields:shield_admin", {
-	description = "Admin Shield",
+armor:register_armor("shields:shield_admin", {
+	description = S("Admin Shield"),
 	inventory_image = "shields_inv_shield_admin.png",
 	groups = {armor_shield=1000, armor_heal=100, armor_use=0, not_in_creative_inventory=1},
-	wear = 0,
+	on_punched = function(player, hitter, time_from_last_punch, tool_capabilities)
+		if type(hitter) == "userdata" then
+			if hitter:is_player() then
+				hitter:set_wielded_item("")
+			end
+			play_sound_effect(player, "default_dig_metal")
+		end
+		return false
+	end,
 })
 
-if ARMOR_MATERIALS.wood then
-	minetest.register_tool("shields:shield_wood", {
-		description = "Wooden Shield",
+minetest.register_alias("adminshield", "shields:shield_admin")
+
+if armor.materials.wood then
+	armor:register_armor("shields:shield_wood", {
+		description = S("Wooden Shield"),
 		inventory_image = "shields_inv_shield_wood.png",
-		groups = {armor_shield=5, armor_heal=0, armor_use=2000},
-		wear = 0,
+		groups = {armor_shield=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},
+		reciprocate_damage = true,
+		on_damage = function(player, index, stack)
+			play_sound_effect(player, "default_wood_footstep")
+		end,
+		on_destroy = function(player, index, stack)
+			play_sound_effect(player, "default_wood_footstep")
+		end,
 	})
-	minetest.register_tool("shields:shield_enhanced_wood", {
-		description = "Enhanced Wood Shield",
+	armor:register_armor("shields:shield_enhanced_wood", {
+		description = S("Enhanced Wood Shield"),
 		inventory_image = "shields_inv_shield_enhanced_wood.png",
-		groups = {armor_shield=8, armor_heal=0, armor_use=1000},
-		wear = 0,
+		groups = {armor_shield=1, armor_heal=0, armor_use=2000},
+		armor_groups = {fleshy=8},
+		damage_groups = {cracky=3, snappy=2, choppy=3, crumbly=2, level=2},
+		reciprocate_damage = true,
+		on_damage = function(player, index, stack)
+			play_sound_effect(player, "default_dig_metal")
+		end,
+		on_destroy = function(player, index, stack)
+			play_sound_effect(player, "default_dug_metal")
+		end,
 	})
 	minetest.register_craft({
 		output = "shields:shield_enhanced_wood",
@@ -36,18 +81,34 @@ if ARMOR_MATERIALS.wood then
 	})
 end
 
-if ARMOR_MATERIALS.cactus then
-	minetest.register_tool("shields:shield_cactus", {
-		description = "Cactus Shield",
+if armor.materials.cactus then
+	armor:register_armor("shields:shield_cactus", {
+		description = S("Cactus Shield"),
 		inventory_image = "shields_inv_shield_cactus.png",
-		groups = {armor_shield=5, armor_heal=0, armor_use=2000},
-		wear = 0,
+		groups = {armor_shield=1, armor_heal=0, armor_use=1000},
+		armor_groups = {fleshy=5},
+		damage_groups = {cracky=3, snappy=3, choppy=2, crumbly=2, level=1},
+		reciprocate_damage = true,
+		on_damage = function(player, index, stack)
+			play_sound_effect(player, "default_wood_footstep")
+		end,
+		on_destroy = function(player, index, stack)
+			play_sound_effect(player, "default_wood_footstep")
+		end,
 	})
-	minetest.register_tool("shields:shield_enhanced_cactus", {
-		description = "Enhanced Cactus Shield",
+	armor:register_armor("shields:shield_enhanced_cactus", {
+		description = S("Enhanced Cactus Shield"),
 		inventory_image = "shields_inv_shield_enhanced_cactus.png",
-		groups = {armor_shield=8, armor_heal=0, armor_use=1000},
-		wear = 0,
+		groups = {armor_shield=1, armor_heal=0, armor_use=1000},
+		armor_groups = {fleshy=8},
+		damage_groups = {cracky=3, snappy=3, choppy=2, crumbly=2, level=2},
+		reciprocate_damage = true,
+		on_damage = function(player, index, stack)
+			play_sound_effect(player, "default_dig_metal")
+		end,
+		on_destroy = function(player, index, stack)
+			play_sound_effect(player, "default_dug_metal")
+		end,
 	})
 	minetest.register_craft({
 		output = "shields:shield_enhanced_cactus",
@@ -59,61 +120,112 @@ if ARMOR_MATERIALS.cactus then
 	})
 end
 
-if ARMOR_MATERIALS.steel then
-	minetest.register_tool("shields:shield_steel", {
-		description = "Steel Shield",
+if armor.materials.steel then
+	armor:register_armor("shields:shield_steel", {
+		description = S("Steel Shield"),
 		inventory_image = "shields_inv_shield_steel.png",
-		groups = {armor_shield=10, armor_heal=0, armor_use=500},
-		wear = 0,
+		groups = {armor_shield=1, armor_heal=0, armor_use=800,
+			physics_speed=-0.03, physics_gravity=0.03},
+		armor_groups = {fleshy=10},
+		damage_groups = {cracky=2, snappy=3, choppy=2, crumbly=1, level=2},
+		reciprocate_damage = true,
+		on_damage = function(player, index, stack)
+			play_sound_effect(player, "default_dig_metal")
+		end,
+		on_destroy = function(player, index, stack)
+			play_sound_effect(player, "default_dug_metal")
+		end,
 	})
 end
 
-if ARMOR_MATERIALS.bronze then
-	minetest.register_tool("shields:shield_bronze", {
-		description = "Bronze Shield",
+if armor.materials.bronze then
+	armor:register_armor("shields:shield_bronze", {
+		description = S("Bronze Shield"),
 		inventory_image = "shields_inv_shield_bronze.png",
-		groups = {armor_shield=10, armor_heal=6, armor_use=250},
-		wear = 0,
+		groups = {armor_shield=1, armor_heal=6, armor_use=400,
+			physics_speed=-0.03, physics_gravity=0.03},
+		armor_groups = {fleshy=10},
+		damage_groups = {cracky=2, snappy=3, choppy=2, crumbly=1, level=2},
+		reciprocate_damage = true,
+		on_damage = function(player, index, stack)
+			play_sound_effect(player, "default_dig_metal")
+		end,
+		on_destroy = function(player, index, stack)
+			play_sound_effect(player, "default_dug_metal")
+		end,
 	})
 end
 
-if ARMOR_MATERIALS.diamond then
-	minetest.register_tool("shields:shield_diamond", {
-		description = "Diamond Shield",
+if armor.materials.diamond then
+	armor:register_armor("shields:shield_diamond", {
+		description = S("Diamond Shield"),
 		inventory_image = "shields_inv_shield_diamond.png",
-		groups = {armor_shield=15, armor_heal=12, armor_use=100},
-		wear = 0,
+		groups = {armor_shield=1, armor_heal=12, armor_use=200},
+		armor_groups = {fleshy=15},
+		damage_groups = {cracky=2, snappy=1, choppy=1, level=3},
+		reciprocate_damage = true,
+		on_damage = function(player, index, stack)
+			play_sound_effect(player, "default_glass_footstep")
+		end,
+		on_destroy = function(player, index, stack)
+			play_sound_effect(player, "default_break_glass")
+		end,
 	})
 end
 
-if ARMOR_MATERIALS.gold then
-	minetest.register_tool("shields:shield_gold", {
-		description = "Gold Shield",
+if armor.materials.gold then
+	armor:register_armor("shields:shield_gold", {
+		description = S("Gold Shield"),
 		inventory_image = "shields_inv_shield_gold.png",
-		groups = {armor_shield=10, armor_heal=6, armor_use=250},
-		wear = 0,
+		groups = {armor_shield=1, armor_heal=6, armor_use=300,
+			physics_speed=-0.04, physics_gravity=0.04},
+		armor_groups = {fleshy=10},
+		damage_groups = {cracky=1, snappy=2, choppy=2, crumbly=3, level=2},
+		reciprocate_damage = true,
+		on_damage = function(player, index, stack)
+			play_sound_effect(player, "default_dig_metal")
+		end,
+		on_destroy = function(player, index, stack)
+			play_sound_effect(player, "default_dug_metal")
+		end,
 	})
 end
 
-if ARMOR_MATERIALS.mithril then
-	minetest.register_tool("shields:shield_mithril", {
-		description = "Mithril Shield",
+if armor.materials.mithril then
+	armor:register_armor("shields:shield_mithril", {
+		description = S("Mithril Shield"),
 		inventory_image = "shields_inv_shield_mithril.png",
-		groups = {armor_shield=15, armor_heal=12, armor_use=50},
-		wear = 0,
+		groups = {armor_shield=1, armor_heal=12, armor_use=100},
+		armor_groups = {fleshy=15},
+		damage_groups = {cracky=2, snappy=1, level=3},
+		reciprocate_damage = true,
+		on_damage = function(player, index, stack)
+			play_sound_effect(player, "default_glass_footstep")
+		end,
+		on_destroy = function(player, index, stack)
+			play_sound_effect(player, "default_break_glass")
+		end,
 	})
 end
 
-if ARMOR_MATERIALS.crystal then
-	minetest.register_tool("shields:shield_crystal", {
-		description = "Crystal Shield",
+if armor.materials.crystal then
+	armor:register_armor("shields:shield_crystal", {
+		description = S("Crystal Shield"),
 		inventory_image = "shields_inv_shield_crystal.png",
-		groups = {armor_shield=15, armor_heal=12, armor_use=50, armor_fire=1},
-		wear = 0,
+		groups = {armor_shield=1, armor_heal=12, armor_use=100, armor_fire=1},
+		armor_groups = {fleshy=15},
+		damage_groups = {cracky=2, snappy=1, level=3},
+		reciprocate_damage = true,
+		on_damage = function(player, index, stack)
+			play_sound_effect(player, "default_glass_footstep")
+		end,
+		on_destroy = function(player, index, stack)
+			play_sound_effect(player, "default_break_glass")
+		end,
 	})
 end
 
-for k, v in pairs(ARMOR_MATERIALS) do
+for k, v in pairs(armor.materials) do
 	minetest.register_craft({
 		output = "shields:shield_"..k,
 		recipe = {
diff --git a/technic_armor/depends.txt b/technic_armor/depends.txt
index 2546a84..9ccefed 100644
--- a/technic_armor/depends.txt
+++ b/technic_armor/depends.txt
@@ -1,3 +1,3 @@
 3d_armor
-technic_worldgen
+technic_worldgen?
 moreores?
diff --git a/technic_armor/init.lua b/technic_armor/init.lua
index e1a663d..b06d7bf 100644
--- a/technic_armor/init.lua
+++ b/technic_armor/init.lua
@@ -1,23 +1,32 @@
+if not minetest.get_modpath("technic_worldgen") then
+	minetest.log("warning", "technic_armor: Mod loaded but unused.")
+	return
+end
+local S = function(s) return s end
+if minetest.global_exists("intllib") then
+	S = intllib.Getter()
+end
+
 local stats = {
-	lead = { name="Lead", material="technic:lead_ingot", armor=1.6, heal=0, use=500, radiation=80*1.1 },
-	brass = { name="Brass", material="technic:brass_ingot", armor=1.8, heal=0, use=650, radiation=43 },
-	cast = { name="Cast Iron", material="technic:cast_iron_ingot", armor=2.5, heal=8, use=200, radiation=40 },
-	carbon = { name="Carbon Steel", material="technic:carbon_steel_ingot", armor=2.7, heal=10, use=100, radiation=40 },
-	stainless = { name="Stainless Steel", material="technic:stainless_steel_ingot", armor=2.7, heal=10, use=75, radiation=40 },
+	lead = { name=S("Lead"), material="technic:lead_ingot", armor=1.6, heal=0, use=500, radiation=80*1.1 },
+	brass = { name=S("Brass"), material="technic:brass_ingot", armor=1.8, heal=0, use=650, radiation=43 },
+	cast = { name=S("Cast Iron"), material="technic:cast_iron_ingot", armor=2.5, heal=8, use=200, radiation=40 },
+	carbon = { name=S("Carbon Steel"), material="technic:carbon_steel_ingot", armor=2.7, heal=10, use=100, radiation=40 },
+	stainless = { name=S("Stainless Steel"), material="technic:stainless_steel_ingot", armor=2.7, heal=10, use=75, radiation=40 },
 }
 if minetest.get_modpath("moreores") then
-	stats.tin = { name="Tin", material="moreores:tin_ingot", armor=1.6, heal=0, use=750, radiation=37 }
-	stats.silver = { name="Silver", material="moreores:silver_ingot", armor=1.8, heal=6, use=650, radiation=53 }
+	stats.tin = { name=S("Tin"), material="moreores:tin_ingot", armor=1.6, heal=0, use=750, radiation=37 }
+	stats.silver = { name=S("Silver"), material="moreores:silver_ingot", armor=1.8, heal=6, use=650, radiation=53 }
 end
 
 local parts = {
-	helmet = { place="head", name="Helmet", level=5, radlevel = 0.10, craft={{1,1,1},{1,0,1}} },
-	chestplate = { place="torso", name="Chestplate", level=8, radlevel = 0.35, craft={{1,0,1},{1,1,1},{1,1,1}} },
-	leggings = { place="legs", name="Leggings", level=7, radlevel = 0.15, craft={{1,1,1},{1,0,1},{1,0,1}} },
-	boots = { place="feet", name="Boots", level=4, radlevel = 0.10, craft={{1,0,1},{1,0,1}} },
+	helmet = { place="head", name=S("Helmet"), level=5, radlevel = 0.10, craft={{1,1,1},{1,0,1}} },
+	chestplate = { place="torso", name=S("Chestplate"), level=8, radlevel = 0.35, craft={{1,0,1},{1,1,1},{1,1,1}} },
+	leggings = { place="legs", name=S("Leggings"), level=7, radlevel = 0.15, craft={{1,1,1},{1,0,1},{1,0,1}} },
+	boots = { place="feet", name=S("Boots"), level=4, radlevel = 0.10, craft={{1,0,1},{1,0,1}} },
 }
 if minetest.get_modpath("shields") then
-	parts.shield = { place="shield", name="Shield", level=5, radlevel=0.00, craft={{1,1,1},{1,1,1},{0,1,0}} }
+	parts.shield = { place="shield", name=S("Shield"), level=5, radlevel=0.00, craft={{1,1,1},{1,1,1},{0,1,0}} }
 end
 
 -- Makes a craft recipe based on a template
diff --git a/wieldview/README.txt b/wieldview/README.txt
index cffae46..ffa5ef0 100644
--- a/wieldview/README.txt
+++ b/wieldview/README.txt
@@ -1,7 +1,7 @@
 [mod] visible wielded items [wieldview]
 =======================================
 
-depends: default, 3d_armor
+Depends on: 3d_armor
 
 Makes hand wielded items visible to other players.
 
@@ -13,3 +13,11 @@ wieldview_update_time = 2
 # Show nodes as tiles, disabled by default
 wieldview_node_tiles = false
 
+
+Info for modders
+################
+
+Wield image transformation: To apply a simple transformation to the item in
+hand, add the group “wieldview_transform” to the item definition. The group
+rating equals one of the numbers used for the [transform texture modifier
+of the Lua API.
diff --git a/wieldview/depends.txt b/wieldview/depends.txt
index 585cc7a..b6cac21 100644
--- a/wieldview/depends.txt
+++ b/wieldview/depends.txt
@@ -1,2 +1 @@
-default
 3d_armor
diff --git a/wieldview/init.lua b/wieldview/init.lua
index 7a5a619..8fcf001 100644
--- a/wieldview/init.lua
+++ b/wieldview/init.lua
@@ -29,8 +29,15 @@ wieldview.get_item_texture = function(self, item)
 				texture = minetest.inventorycube(minetest.registered_items[item].tiles[1])
 			end
 		end
-		if wieldview.transform[item] then
-			texture = texture.."^[transform"..wieldview.transform[item]
+		-- Get item image transformation, first from group, then from transform.lua
+		local transform = minetest.get_item_group(item, "wieldview_transform")
+		if transform == 0 then
+			transform = wieldview.transform[item]
+		end
+		if transform then
+			-- This actually works with groups ratings because transform1, transform2, etc.
+			-- have meaning and transform0 is used for identidy, so it can be ignored
+			texture = texture.."^[transform"..tostring(transform)
 		end
 	end
 	return texture

-- 
Alioth's /usr/local/bin/git-commit-notice on /srv/git.debian.org/git/pkg-games/minetest-mod-3d-armor.git



More information about the Pkg-games-commits mailing list