123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522 |
- -- support for i18n
- local S = armor_i18n.gettext
- local skin_previews = {}
- local use_player_monoids = minetest.global_exists("player_monoids")
- local use_armor_monoid = minetest.global_exists("armor_monoid")
- local use_pova_mod = minetest.get_modpath("pova")
- local armor_def = setmetatable({}, {
- __index = function()
- return setmetatable({
- groups = setmetatable({}, {
- __index = function()
- return 0
- end})
- }, {
- __index = function()
- return 0
- end
- })
- end,
- })
- local armor_textures = setmetatable({}, {
- __index = function()
- return setmetatable({}, {
- __index = function()
- return "blank.png"
- end
- })
- end
- })
- armor = {
- timer = 0,
- elements = {"head", "torso", "legs", "feet"},
- physics = {"jump", "speed", "gravity"},
- attributes = {"heal", "fire", "water", "block"},
- 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",
- },
- fire_nodes = {
- {"default:lava_source", 5, 8},
- {"default:lava_flowing", 5, 8},
- {"nether:lava_source", 5, 8},
- {"fire:basic_flame", 3, 4},
- {"fire:permanent_flame", 3, 4},
- {"epic:permanent_flame", 3, 4},
- {"nether:lava_crust", 3, 4},
- },
- registered_groups = {["fleshy"]=100},
- registered_callbacks = {
- on_update = {},
- on_equip = {},
- on_unequip = {},
- on_damage = {},
- on_destroy = {},
- },
- migrate_old_inventory = true,
- version = "0.4.13",
- }
- 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
- self:run_callbacks("on_update", player)
- end
- armor.set_player_armor = function(self, player)
- local name, armor_inv = self:get_valid_player(player, "[set_player_armor]")
- if not name then
- return
- end
- local state = 0
- local count = 0
- local material = {count=1}
- local preview = armor:get_preview(name)
- local texture = "3d_armor_trans.png"
- local 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 = armor_inv:get_list("armor")
- if type(list) ~= "table" then
- return
- end
- for i, stack in pairs(list) do
- if stack:get_count() == 1 then
- local def = stack:get_definition()
- for _, element in pairs(self.elements) do
- if def.groups["armor_"..element] then
- if def.armor_groups then
- for group, level in pairs(def.armor_groups) do
- if levels[group] then
- levels[group] = levels[group] + level
- end
- end
- else
- local level = def.groups["armor_"..element]
- levels["fleshy"] = levels["fleshy"] + level --Level is 90% of armor_group added value.
- end
- break
- end
- -- DEPRECATED, use armor_groups instead
- if def.groups["armor_radiation"] and levels["radiation"] then
- levels["radiation"] = def.groups["armor_radiation"]
- end
- end
- local item = stack:get_name()
- local tex = def.texture or item:gsub("%:", "_")
- tex = tex:gsub(".png$", "")
- local prev = def.preview or tex.."_preview"
- prev = prev:gsub(".png$", "")
- texture = texture.."^"..tex..".png"
- preview = preview.."^"..prev..".png"
- state = state + stack:get_wear()
- count = count + 1
- for _, phys in pairs(self.physics) do
- local value = def.groups["physics_"..phys] or 0
- physics[phys] = physics[phys] + value
- end
- for _, attr in pairs(self.attributes) do
- local value = def.groups["armor_"..attr] or 0
- attributes[attr] = attributes[attr] + value
- end
- local mat = string.match(item, "%:.+_(.+)$")
- if material.name then
- if material.name == mat then
- material.count = material.count + 1
- end
- else
- material.name = mat
- end
- end
- end
- for group, level in pairs(levels) do
- if level > 0 then
- level = level * armor.config.level_multiplier
- if material.name and material.count == #self.elements then
- level = level * 1.1
- end
- end
- local base = self.registered_groups[group]
- self.def[name].groups[group] = level
- if level > base then
- level = base
- end
- groups[group] = base - level
- change[group] = groups[group] / base
- end
- for _, attr in pairs(self.attributes) do
- local mult = attr == "heal" and self.config.heal_multiplier or 1
- self.def[name][attr] = attributes[attr] * mult
- end
- for _, phys in pairs(self.physics) do
- self.def[name][phys] = physics[phys]
- end
- if use_armor_monoid then
- armor_monoid.monoid:add_change(player, change, "3d_armor:armor")
- else
- player:set_armor_groups(groups)
- end
- if use_player_monoids then
- player_monoids.speed:add_change(player, physics.speed,
- "3d_armor:physics")
- player_monoids.jump:add_change(player, physics.jump,
- "3d_armor:physics")
- player_monoids.gravity:add_change(player, physics.gravity,
- "3d_armor:physics")
- elseif use_pova_mod then
- -- only add the changes, not the default 1.0 for each physics setting
- pova.add_override(name, "3d_armor", {
- speed = physics.speed - 1,
- jump = physics.jump - 1,
- gravity = physics.gravity - 1,
- })
- pova.do_override(player)
- else
- 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)
- end
- armor.punch = function(self, player, hitter, time_from_last_punch, tool_capabilities)
- local name, armor_inv = self:get_valid_player(player, "[punch]")
- if not name then
- return
- end
- local state = 0
- local count = 0
- local recip = true
- local default_groups = {cracky=3, snappy=3, choppy=3, crumbly=3, level=1}
- local list = armor_inv:get_list("armor")
- for i, stack in pairs(list) do
- if stack:get_count() == 1 then
- local 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 and hitter == "water" then
- damage = minetest.get_item_group(name, "armor_water") > 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, index, stack)
- self:set_inventory_stack(player, index, stack)
- if stack:get_count() == 0 then
- self:run_callbacks("on_unequip", player, index, old_stack)
- self:run_callbacks("on_destroy", player, index, old_stack)
- self:set_player_armor(player)
- end
- end
- armor.get_player_skin = function(self, name)
- if (self.skin_mod == "skins" or self.skin_mod == "simple_skins") and skins.skins[name] then
- return skins.skins[name]..".png"
- elseif self.skin_mod == "u_skins" and u_skins.u_skins[name] then
- return u_skins.u_skins[name]..".png"
- elseif self.skin_mod == "wardrobe" and wardrobe.playerSkins and wardrobe.playerSkins[name] then
- return wardrobe.playerSkins[name]
- elseif self.skin_mod == "custom_skin" then
- return custom_skin.texture[name]
- end
- return armor.default_skin..".png"
- end
- armor.add_preview = function(self, preview)
- skin_previews[preview] = true
- end
- armor.get_preview = function(self, name)
- local preview = string.gsub(armor:get_player_skin(name), ".png", "_preview.png")
- if skin_previews[preview] then
- return preview
- end
- return "character_preview.png"
- end
- armor.get_armor_formspec = function(self, name, listring)
- if armor.def[name].init_time == 0 then
- return "label[0,0;Armor not initialized!]"
- end
- local formspec = armor.formspec..
- "list[detached:"..name.."_armor;armor;0,0.5;2,3;]"
- if listring == true then
- formspec = formspec.."listring[current_player;main]"..
- "listring[detached:"..name.."_armor;armor]"
- end
- formspec = formspec:gsub("armor_preview", armor.textures[name].preview)
- formspec = formspec:gsub("armor_level", armor.def[name].level)
- for _, attr in pairs(self.attributes) do
- formspec = formspec:gsub("armor_attr_"..attr, armor.def[name][attr])
- end
- for group, _ in pairs(self.registered_groups) do
- formspec = formspec:gsub("armor_group_"..group,
- armor.def[name].groups[group])
- end
- return formspec
- end
- armor.get_element = function(self, item_name)
- for _, element in pairs(armor.elements) do
- if minetest.get_item_group(item_name, "armor_"..element) > 0 then
- return element
- end
- end
- end
- armor.serialize_inventory_list = function(self, list)
- local list_table = {}
- for _, stack in ipairs(list) do
- table.insert(list_table, stack:to_string())
- end
- return minetest.serialize(list_table)
- end
- armor.deserialize_inventory_list = function(self, list_string)
- local list_table = minetest.deserialize(list_string)
- local list = {}
- for _, stack in ipairs(list_table or {}) do
- table.insert(list, ItemStack(stack))
- end
- return list
- end
- armor.load_armor_inventory = function(self, player)
- local _, inv = self:get_valid_player(player, "[load_armor_inventory]")
- if inv then
- local armor_list_string = player:get_attribute("3d_armor_inventory")
- if armor_list_string then
- inv:set_list("armor",
- self:deserialize_inventory_list(armor_list_string))
- return true
- end
- end
- end
- armor.save_armor_inventory = function(self, player)
- local _, inv = self:get_valid_player(player, "[save_armor_inventory]")
- if inv then
- player:set_attribute("3d_armor_inventory",
- self:serialize_inventory_list(inv:get_list("armor")))
- end
- end
- armor.update_inventory = function(self, player)
- -- DEPRECATED: Legacy inventory support
- end
- armor.set_inventory_stack = function(self, player, i, stack)
- local _, inv = self:get_valid_player(player, "[set_inventory_stack]")
- if inv then
- inv:set_stack("armor", i, stack)
- self:save_armor_inventory(player)
- end
- end
- armor.get_valid_player = function(self, player, msg)
- msg = msg or ""
- if not player then
- minetest.log("warning", S("3d_armor: Player reference is nil @1", msg))
- return
- end
- local name = player:get_player_name()
- if not name then
- minetest.log("warning", S("3d_armor: Player name is nil @1", msg))
- return
- end
- local inv = minetest.get_inventory({type="detached", name=name.."_armor"})
- if not inv then
- minetest.log("warning", S("3d_armor: Detached armor inventory is nil @1", msg))
- return
- end
- return name, inv
- end
- armor.drop_armor = function(pos, stack)
- local node = minetest.get_node_or_nil(pos)
- if node then
- local obj = minetest.add_item(pos, stack)
- if obj then
- obj:setvelocity({x=math.random(-1, 1), y=5, z=math.random(-1, 1)})
- end
- end
- end
|