mirror of
https://git.minetest.land/MineClone2/MineClone2.git
synced 2024-11-28 05:43:43 +01:00
Merge pull request 'Rewrite armor + new damage system' (#1555) from damage into master
Reviewed-on: https://git.minetest.land/MineClone2/MineClone2/pulls/1555
This commit is contained in:
commit
79aac4c494
164
mods/CORE/mcl_damage/init.lua
Normal file
164
mods/CORE/mcl_damage/init.lua
Normal file
@ -0,0 +1,164 @@
|
||||
mcl_damage = {
|
||||
modifiers = {},
|
||||
damage_callbacks = {},
|
||||
death_callbacks = {},
|
||||
types = {
|
||||
in_fire = {is_fire = true},
|
||||
lightning_bolt = {is_lightning = true},
|
||||
on_fire = {is_fire = true, bypasses_armor = true},
|
||||
lava = {is_fire = true},
|
||||
hot_floor = {is_fire = true},
|
||||
in_wall = {bypasses_armor = true},
|
||||
drown = {bypasses_armor = true},
|
||||
starve = {bypasses_armor = true, bypasses_magic = true},
|
||||
cactus = {},
|
||||
fall = {bypasses_armor = true},
|
||||
fly_into_wall = {bypasses_armor = true}, -- unused
|
||||
out_of_world = {bypasses_armor = true, bypasses_magic = true, bypasses_invulnerability = true},
|
||||
generic = {bypasses_armor = true},
|
||||
magic = {is_magic = true, bypasses_armor = true},
|
||||
dragon_breath = {is_magic = true, bypasses_armor = true}, -- this is only used for dragon fireball; dragon fireball does not actually deal impact damage tho, so this is unreachable
|
||||
wither = {bypasses_armor = true}, -- unused
|
||||
wither_skull = {is_magic = true, is_explosion = true}, -- this is non-MC but a workaround to get the proper death message
|
||||
anvil = {},
|
||||
falling_node = {}, -- this is falling_block in MC
|
||||
mob = {},
|
||||
player = {},
|
||||
arrow = {is_projectile = true},
|
||||
fireball = {is_projectile = true, is_fire = true},
|
||||
thorns = {is_magic = true},
|
||||
explosion = {is_explosion = true},
|
||||
cramming = {bypasses_armor = true}, -- unused
|
||||
fireworks = {is_explosion = true}, -- unused
|
||||
}
|
||||
}
|
||||
|
||||
function mcl_damage.register_modifier(func, priority)
|
||||
table.insert(mcl_damage.modifiers, {func = func, priority = priority or 0})
|
||||
end
|
||||
|
||||
function mcl_damage.register_on_damage(func)
|
||||
table.insert(mcl_damage.damage_callbacks, func)
|
||||
end
|
||||
|
||||
function mcl_damage.register_on_death(func)
|
||||
table.insert(mcl_damage.death_callbacks, func)
|
||||
end
|
||||
|
||||
function mcl_damage.run_modifiers(obj, damage, reason)
|
||||
for _, modf in ipairs(mcl_damage.modifiers) do
|
||||
damage = modf.func(obj, damage, reason) or damage
|
||||
if damage == 0 then
|
||||
return 0
|
||||
end
|
||||
end
|
||||
|
||||
return damage
|
||||
end
|
||||
|
||||
local function run_callbacks(funcs, ...)
|
||||
for _, func in pairs(funcs) do
|
||||
func(...)
|
||||
end
|
||||
end
|
||||
|
||||
function mcl_damage.run_damage_callbacks(obj, damage, reason)
|
||||
run_callbacks(mcl_damage.damage_callbacks, obj, damage, reason)
|
||||
end
|
||||
|
||||
function mcl_damage.run_death_callbacks(obj, reason)
|
||||
run_callbacks(mcl_damage.death_callbacks, obj, reason)
|
||||
end
|
||||
|
||||
function mcl_damage.from_punch(mcl_reason, object)
|
||||
mcl_reason.direct = object
|
||||
local luaentity = mcl_reason.direct:get_luaentity()
|
||||
if luaentity then
|
||||
if luaentity._is_arrow then
|
||||
mcl_reason.type = "arrow"
|
||||
elseif luaentity._is_fireball then
|
||||
mcl_reason.type = "fireball"
|
||||
elseif luaentity._cmi_is_mob then
|
||||
mcl_reason.type = "mob"
|
||||
end
|
||||
mcl_reason.source = mcl_reason.source or luaentity._source_object
|
||||
else
|
||||
mcl_reason.type = "player"
|
||||
end
|
||||
end
|
||||
|
||||
function mcl_damage.finish_reason(mcl_reason)
|
||||
mcl_reason.source = mcl_reason.source or mcl_reason.direct
|
||||
mcl_reason.flags = mcl_damage.types[mcl_reason.type]
|
||||
end
|
||||
|
||||
function mcl_damage.from_mt(mt_reason)
|
||||
if mt_reason._mcl_chached_reason then
|
||||
return mt_reason._mcl_chached_reason
|
||||
end
|
||||
|
||||
local mcl_reason
|
||||
|
||||
if mt_reason._mcl_reason then
|
||||
mcl_reason = mt_reason._mcl_reason
|
||||
else
|
||||
mcl_reason = {type = "generic"}
|
||||
|
||||
if mt_reason._mcl_type then
|
||||
mcl_reason.type = mt_reason._mcl_type
|
||||
elseif mt_reason.type == "fall" then
|
||||
mcl_reason.type = "fall"
|
||||
elseif mt_reason.type == "drown" then
|
||||
mcl_reason.type = "drown"
|
||||
elseif mt_reason.type == "punch" then
|
||||
mcl_damage.from_punch(mcl_reason, mt_reason.object)
|
||||
elseif mt_reason.type == "node_damage" and mt_reason.node then
|
||||
if minetest.get_item_group(mt_reason.node, "fire") > 0 then
|
||||
mcl_reason.type = "in_fire"
|
||||
end
|
||||
if minetest.get_item_group(mt_reason.node, "lava") > 0 then
|
||||
mcl_reason.type = "lava"
|
||||
end
|
||||
end
|
||||
|
||||
for key, value in pairs(mt_reason) do
|
||||
if key:find("_mcl_") == 1 then
|
||||
mcl_reason[key:sub(6, #key)] = value
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
mcl_damage.finish_reason(mcl_reason)
|
||||
mt_reason._mcl_cached_reason = mcl_reason
|
||||
|
||||
return mcl_reason
|
||||
end
|
||||
|
||||
function mcl_damage.register_type(name, def)
|
||||
mcl_damage.types[name] = def
|
||||
end
|
||||
|
||||
minetest.register_on_player_hpchange(function(player, hp_change, mt_reason)
|
||||
if hp_change < 0 then
|
||||
if player:get_hp() <= 0 then
|
||||
return 0
|
||||
end
|
||||
hp_change = -mcl_damage.run_modifiers(player, -hp_change, mcl_damage.from_mt(mt_reason))
|
||||
end
|
||||
return hp_change
|
||||
end, true)
|
||||
|
||||
minetest.register_on_player_hpchange(function(player, hp_change, mt_reason)
|
||||
if hp_change < 0 then
|
||||
mcl_damage.run_damage_callbacks(player, -hp_change, mcl_damage.from_mt(mt_reason))
|
||||
end
|
||||
end, false)
|
||||
|
||||
minetest.register_on_dieplayer(function(player, mt_reason)
|
||||
mcl_damage.run_death_callbacks(player, mcl_damage.from_mt(mt_reason))
|
||||
end)
|
||||
|
||||
minetest.register_on_mods_loaded(function()
|
||||
table.sort(mcl_damage.modifiers, function(a, b) return a.priority < b.priority end)
|
||||
end)
|
||||
|
3
mods/CORE/mcl_damage/mod.conf
Normal file
3
mods/CORE/mcl_damage/mod.conf
Normal file
@ -0,0 +1,3 @@
|
||||
name = mcl_damage
|
||||
author = Fleckenstein
|
||||
description = Minecraft-like damage reason system
|
@ -12,7 +12,6 @@ under the LGPLv2.1 license.
|
||||
|
||||
mcl_explosions = {}
|
||||
|
||||
local mod_death_messages = minetest.get_modpath("mcl_death_messages") ~= nil
|
||||
local mod_fire = minetest.get_modpath("mcl_fire") ~= nil
|
||||
local CONTENT_FIRE = minetest.get_content_id("mcl_fire:fire")
|
||||
|
||||
@ -150,7 +149,8 @@ end
|
||||
-- raydirs - The directions for each ray
|
||||
-- radius - The maximum distance each ray will go
|
||||
-- info - Table containing information about explosion
|
||||
-- puncher - object that punches other objects (optional)
|
||||
-- direct - direct source object of the damage (optional)
|
||||
-- source - indirect source object of the damage (optional)
|
||||
--
|
||||
-- Values in info:
|
||||
-- drop_chance - The chance that destroyed nodes will drop their items
|
||||
@ -165,7 +165,7 @@ end
|
||||
-- Note that this function has been optimized, it contains code which has been
|
||||
-- inlined to avoid function calls and unnecessary table creation. This was
|
||||
-- measured to give a significant performance increase.
|
||||
local function trace_explode(pos, strength, raydirs, radius, info, puncher)
|
||||
local function trace_explode(pos, strength, raydirs, radius, info, direct, source)
|
||||
local vm = get_voxel_manip()
|
||||
|
||||
local emin, emax = vm:read_from_map(vector.subtract(pos, radius),
|
||||
@ -247,7 +247,7 @@ local function trace_explode(pos, strength, raydirs, radius, info, puncher)
|
||||
local ent = obj:get_luaentity()
|
||||
|
||||
-- Ignore items to lower lag
|
||||
if obj:is_player() or (ent and ent.name ~= '__builtin.item') then
|
||||
if (obj:is_player() or (ent and ent.name ~= '__builtin.item')) and obj:get_hp() > 0 then
|
||||
local opos = obj:get_pos()
|
||||
local collisionbox = nil
|
||||
|
||||
@ -321,7 +321,6 @@ local function trace_explode(pos, strength, raydirs, radius, info, puncher)
|
||||
impact = 0
|
||||
end
|
||||
local damage = math.floor((impact * impact + impact) * 7 * strength + 1)
|
||||
local source = puncher or obj
|
||||
|
||||
local sleep_formspec_doesnt_close_mt53 = false
|
||||
if obj:is_player() then
|
||||
@ -333,26 +332,22 @@ local function trace_explode(pos, strength, raydirs, radius, info, puncher)
|
||||
sleep_formspec_doesnt_close_mt53 = true
|
||||
end
|
||||
end
|
||||
if mod_death_messages then
|
||||
mcl_death_messages.player_damage(obj, S("@1 was caught in an explosion.", name))
|
||||
end
|
||||
if rawget(_G, "armor") and armor.last_damage_types then
|
||||
armor.last_damage_types[name] = "explosion"
|
||||
end
|
||||
end
|
||||
|
||||
if sleep_formspec_doesnt_close_mt53 then
|
||||
minetest.after(0.3, function(obj, damage, impact, punch_dir) -- 0.2 is minimum delay for closing old formspec and open died formspec -- TODO: REMOVE THIS IN THE FUTURE
|
||||
if not obj then return end
|
||||
obj:punch(obj, 10, { damage_groups = { full_punch_interval = 1, fleshy = damage, knockback = impact * 20.0 } }, punch_dir)
|
||||
obj:add_velocity(vector.multiply(punch_dir, impact * 20))
|
||||
end, obj, damage, impact, vector.new(punch_dir))
|
||||
else
|
||||
obj:punch(source, 10, { damage_groups = { full_punch_interval = 1, fleshy = damage, knockback = impact * 20.0 } }, punch_dir)
|
||||
minetest.after(0.3, function() -- 0.2 is minimum delay for closing old formspec and open died formspec -- TODO: REMOVE THIS IN THE FUTURE
|
||||
if not obj:is_player() then
|
||||
return
|
||||
end
|
||||
|
||||
mcl_util.deal_damage(obj, damage, {type = "explosion", direct = direct, source = source})
|
||||
|
||||
if obj:is_player() then
|
||||
obj:add_velocity(vector.multiply(punch_dir, impact * 20))
|
||||
elseif ent.tnt_knockback then
|
||||
end)
|
||||
else
|
||||
mcl_util.deal_damage(obj, damage, {type = "explosion", direct = direct, source = source})
|
||||
|
||||
if obj:is_player() or ent.tnt_knockback then
|
||||
obj:add_velocity(vector.multiply(punch_dir, impact * 20))
|
||||
end
|
||||
end
|
||||
@ -422,7 +417,8 @@ end
|
||||
-- pos - The position where the explosion originates from
|
||||
-- strength - The blast strength of the explosion (a TNT explosion uses 4)
|
||||
-- info - Table containing information about explosion
|
||||
-- puncher - object that is reported as source of punches/damage (optional)
|
||||
-- direct - direct source object of the damage (optional)
|
||||
-- source - indirect source object of the damage (optional)
|
||||
--
|
||||
-- Values in info:
|
||||
-- drop_chance - If specified becomes the drop chance of all nodes in the
|
||||
@ -436,7 +432,7 @@ end
|
||||
-- griefing - If true, the explosion will destroy nodes (default: true)
|
||||
-- grief_protected - If true, the explosion will also destroy nodes which have
|
||||
-- been protected (default: false)
|
||||
function mcl_explosions.explode(pos, strength, info, puncher)
|
||||
function mcl_explosions.explode(pos, strength, info, direct, source)
|
||||
if info == nil then
|
||||
info = {}
|
||||
end
|
||||
@ -465,7 +461,7 @@ function mcl_explosions.explode(pos, strength, info, puncher)
|
||||
info.drop_chance = 0
|
||||
end
|
||||
|
||||
trace_explode(pos, strength, shape, radius, info, puncher)
|
||||
trace_explode(pos, strength, shape, radius, info, direct, source)
|
||||
|
||||
if info.particles then
|
||||
add_particles(pos, radius)
|
||||
|
@ -418,3 +418,120 @@ function mcl_util.get_color(colorstr)
|
||||
return colorstr, hex
|
||||
end
|
||||
end
|
||||
|
||||
function mcl_util.call_on_rightclick(itemstack, player, pointed_thing)
|
||||
-- Call on_rightclick if the pointed node defines it
|
||||
if pointed_thing and pointed_thing.type == "node" then
|
||||
local pos = pointed_thing.under
|
||||
local node = minetest.get_node(pos)
|
||||
if player and not player:get_player_control().sneak then
|
||||
local nodedef = minetest.registered_nodes[node.name]
|
||||
local on_rightclick = nodedef and nodedef.on_rightclick
|
||||
if on_rightclick then
|
||||
return on_rightclick(pos, node, player, itemstack, pointed_thing) or itemstack
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
function mcl_util.calculate_durability(itemstack)
|
||||
local unbreaking_level = mcl_enchanting.get_enchantment(itemstack, "unbreaking")
|
||||
local armor_uses = minetest.get_item_group(itemstack:get_name(), "mcl_armor_uses")
|
||||
|
||||
local uses
|
||||
|
||||
if armor_uses > 0 then
|
||||
uses = armor_uses
|
||||
if unbreaking_level > 0 then
|
||||
uses = uses / (0.6 + 0.4 / (unbreaking_level + 1))
|
||||
end
|
||||
else
|
||||
local def = itemstack:get_definition()
|
||||
if def then
|
||||
local fixed_uses = def._mcl_uses
|
||||
if fixed_uses then
|
||||
uses = fixed_uses
|
||||
if unbreaking_level > 0 then
|
||||
uses = uses * (unbreaking_level + 1)
|
||||
end
|
||||
end
|
||||
end
|
||||
if not uses then
|
||||
local toolcaps = itemstack:get_tool_capabilities()
|
||||
local groupcaps = toolcaps.groupcaps
|
||||
for _, v in pairs(groupcaps) do
|
||||
uses = v.uses
|
||||
break
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
return uses or 0
|
||||
end
|
||||
|
||||
function mcl_util.use_item_durability(itemstack, n)
|
||||
local uses = mcl_util.calculate_durability(itemstack)
|
||||
itemstack:add_wear(65535 / uses * n)
|
||||
end
|
||||
|
||||
function mcl_util.deal_damage(target, damage, mcl_reason)
|
||||
local luaentity = target:get_luaentity()
|
||||
|
||||
if luaentity then
|
||||
if luaentity.deal_damage then
|
||||
luaentity:deal_damage(damage, mcl_reason or {type = "generic"})
|
||||
return
|
||||
elseif luaentity._cmi_is_mob then
|
||||
-- local puncher = mcl_reason and mcl_reason.direct or target
|
||||
-- target:punch(puncher, 1.0, {full_punch_interval = 1.0, damage_groups = {fleshy = damage}}, vector.direction(puncher:get_pos(), target:get_pos()), damage)
|
||||
luaentity.health = luaentity.health - damage
|
||||
return
|
||||
end
|
||||
end
|
||||
|
||||
target:set_hp(target:get_hp() - damage, {_mcl_reason = mcl_reason})
|
||||
end
|
||||
|
||||
function mcl_util.get_hp(obj)
|
||||
local luaentity = obj:get_luaentity()
|
||||
|
||||
if luaentity and luaentity._cmi_is_mob then
|
||||
return luaentity.health
|
||||
else
|
||||
return obj:get_hp()
|
||||
end
|
||||
end
|
||||
|
||||
function mcl_util.get_inventory(object, create)
|
||||
if object:is_player() then
|
||||
return object:get_inventory()
|
||||
else
|
||||
local luaentity = object:get_luaentity()
|
||||
local inventory = luaentity.inventory
|
||||
|
||||
if create and not inventory and luaentity.create_inventory then
|
||||
inventory = luaentity:create_inventory()
|
||||
end
|
||||
|
||||
return inventory
|
||||
end
|
||||
end
|
||||
|
||||
function mcl_util.get_wielded_item(object)
|
||||
if object:is_player() then
|
||||
return object:get_wielded_item()
|
||||
else
|
||||
-- ToDo: implement getting wielditems from mobs as soon as mobs have wielditems
|
||||
return ItemStack()
|
||||
end
|
||||
end
|
||||
|
||||
function mcl_util.get_object_name(object)
|
||||
if object:is_player() then
|
||||
return object:get_player_name()
|
||||
else
|
||||
local luaentity = object:get_luaentity()
|
||||
|
||||
return luaentity.nametag and luaentity.nametag ~= "" and luaentity.nametag or luaentity.description or luaentity.name
|
||||
end
|
||||
end
|
||||
|
@ -35,7 +35,7 @@ function mcl_burning.get_touching_nodes(obj, nodenames, storage)
|
||||
return nodes
|
||||
end
|
||||
|
||||
function mcl_burning.set_on_fire(obj, burn_time, reason)
|
||||
function mcl_burning.set_on_fire(obj, burn_time)
|
||||
if obj:get_hp() < 0 then
|
||||
return
|
||||
end
|
||||
@ -47,26 +47,26 @@ function mcl_burning.set_on_fire(obj, burn_time, reason)
|
||||
return
|
||||
end
|
||||
|
||||
if obj:is_player() and minetest.is_creative_enabled(obj:get_player_name()) then
|
||||
burn_time = 0
|
||||
else
|
||||
local max_fire_prot_lvl = 0
|
||||
local inv = mcl_util.get_inventory(obj)
|
||||
local armor_list = inv and inv:get_list("armor")
|
||||
|
||||
if obj:is_player() then
|
||||
if minetest.is_creative_enabled(obj:get_player_name()) then
|
||||
burn_time = burn_time / 100
|
||||
end
|
||||
|
||||
local inv = obj:get_inventory()
|
||||
|
||||
for i = 2, 5 do
|
||||
local stack = inv:get_stack("armor", i)
|
||||
|
||||
if armor_list then
|
||||
for _, stack in pairs(armor_list) do
|
||||
local fire_prot_lvl = mcl_enchanting.get_enchantment(stack, "fire_protection")
|
||||
max_fire_prot_lvl = math.max(max_fire_prot_lvl, fire_prot_lvl)
|
||||
if fire_prot_lvl > max_fire_prot_lvl then
|
||||
max_fire_prot_lvl = fire_prot_lvl
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
if max_fire_prot_lvl > 0 then
|
||||
burn_time = burn_time - math.floor(burn_time * max_fire_prot_lvl * 0.15)
|
||||
end
|
||||
end
|
||||
|
||||
if not storage.burn_time or burn_time >= storage.burn_time then
|
||||
if obj:is_player() and not storage.fire_hud_id then
|
||||
@ -79,7 +79,6 @@ function mcl_burning.set_on_fire(obj, burn_time, reason)
|
||||
})
|
||||
end
|
||||
storage.burn_time = burn_time
|
||||
storage.burn_reason = reason
|
||||
storage.fire_damage_timer = 0
|
||||
|
||||
local fire_entity = minetest.add_entity(obj:get_pos(), "mcl_burning:fire")
|
||||
@ -120,7 +119,6 @@ function mcl_burning.extinguish(obj)
|
||||
mcl_burning.storage[obj] = {}
|
||||
else
|
||||
storage.burn_time = nil
|
||||
storage.burn_reason = nil
|
||||
storage.fire_damage_timer = nil
|
||||
end
|
||||
end
|
||||
@ -140,36 +138,9 @@ function mcl_burning.tick(obj, dtime, storage)
|
||||
storage.fire_damage_timer = 0
|
||||
|
||||
local luaentity = obj:get_luaentity()
|
||||
local is_mob = luaentity and luaentity._cmi_is_mob
|
||||
local hp = is_mob and luaentity.health or obj:get_hp()
|
||||
|
||||
if hp > 0 then
|
||||
local do_damage = true
|
||||
|
||||
if obj:is_player() then
|
||||
if mcl_potions.player_has_effect(obj, "fire_proof") then
|
||||
do_damage = false
|
||||
else
|
||||
local name = obj:get_player_name()
|
||||
armor.last_damage_types[name] = "fire"
|
||||
local deathmsg = S("@1 burned to death.", name)
|
||||
if storage.reason then
|
||||
deathmsg = S("@1 was burned by @2.", name, storage.reason)
|
||||
end
|
||||
mcl_death_messages.player_damage(obj, deathmsg)
|
||||
end
|
||||
elseif luaentity.fire_damage_resistant then
|
||||
do_damage = false
|
||||
end
|
||||
|
||||
if do_damage then
|
||||
local new_hp = hp - 1
|
||||
if is_mob then
|
||||
luaentity.health = new_hp
|
||||
else
|
||||
obj:set_hp(new_hp)
|
||||
end
|
||||
end
|
||||
if not luaentity or not luaentity.fire_damage_resistant then
|
||||
mcl_util.deal_damage(obj, 1, {type = "on_fire"})
|
||||
end
|
||||
end
|
||||
end
|
||||
|
@ -1,9 +1,6 @@
|
||||
local S = minetest.get_translator("mcl_falling_nodes")
|
||||
local dmes = minetest.get_modpath("mcl_death_messages") ~= nil
|
||||
local has_mcl_armor = minetest.get_modpath("mcl_armor")
|
||||
|
||||
local is_creative_enabled = minetest.is_creative_enabled
|
||||
|
||||
local get_falling_depth = function(self)
|
||||
if not self._startpos then
|
||||
-- Fallback
|
||||
@ -23,80 +20,31 @@ local deal_falling_damage = function(self, dtime)
|
||||
-- Fallback
|
||||
self._startpos = pos
|
||||
end
|
||||
local objs = minetest.get_objects_inside_radius(pos, 1)
|
||||
for _,v in ipairs(objs) do
|
||||
if v:is_player() then
|
||||
local hp = v:get_hp()
|
||||
local name = v:get_player_name()
|
||||
if hp ~= 0 then
|
||||
if not self._hit_players then
|
||||
self._hit_players = {}
|
||||
end
|
||||
local hit = false
|
||||
for _,v in ipairs(self._hit_players) do
|
||||
if name == v then
|
||||
hit = true
|
||||
end
|
||||
end
|
||||
if not hit then
|
||||
table.insert(self._hit_players, name)
|
||||
self._hit = self._hit or {}
|
||||
for _, obj in ipairs(minetest.get_objects_inside_radius(pos, 1)) do
|
||||
if mcl_util.get_hp(obj) > 0 and not self._hit[obj] then
|
||||
self._hit[obj] = true
|
||||
local way = self._startpos.y - pos.y
|
||||
local damage = (way - 1) * 2
|
||||
damage = math.min(40, math.max(0, damage))
|
||||
if damage >= 1 then
|
||||
hp = hp - damage
|
||||
if hp < 0 then
|
||||
hp = 0
|
||||
end
|
||||
-- Reduce damage if wearing a helmet
|
||||
local inv = v:get_inventory()
|
||||
local inv = mcl_util.get_inventory(obj)
|
||||
if inv then
|
||||
local helmet = inv:get_stack("armor", 2)
|
||||
if has_mcl_armor and not helmet:is_empty() then
|
||||
hp = hp/4*3
|
||||
if not is_creative_enabled(name) then
|
||||
helmet:add_wear(65535/helmet:get_definition().groups.mcl_armor_uses) --TODO: be sure damage is exactly like mc (informations are missing in the mc wiki)
|
||||
if minetest.get_item_group(helmet:get_name(), "combat_armor") > 0 then
|
||||
damage = damage / 4 * 3
|
||||
mcl_util.use_item_durability(helmet, 1)
|
||||
inv:set_stack("armor", 2, helmet)
|
||||
end
|
||||
end
|
||||
local msg
|
||||
local deathmsg, dmg_type
|
||||
if minetest.get_item_group(self.node.name, "anvil") ~= 0 then
|
||||
msg = S("@1 was smashed by a falling anvil.", v:get_player_name())
|
||||
dmg_type = "anvil"
|
||||
else
|
||||
msg = S("@1 was smashed by a falling block.", v:get_player_name())
|
||||
end
|
||||
if dmes then
|
||||
mcl_death_messages.player_damage(v, msg)
|
||||
end
|
||||
v:set_hp(hp, { type = "punch", from = "mod" })
|
||||
end
|
||||
end
|
||||
end
|
||||
else
|
||||
local hp = v:get_luaentity().health
|
||||
if hp and hp ~= 0 then
|
||||
if not self._hit_mobs then
|
||||
self._hit_mobs = {}
|
||||
end
|
||||
local hit = false
|
||||
for _,mob in ipairs(self._hit_mobs) do
|
||||
if v == mob then
|
||||
hit = true
|
||||
end
|
||||
end
|
||||
--TODO: reduce damage for mobs then they will be able to wear armor
|
||||
if not hit then
|
||||
table.insert(self._hit_mobs, v)
|
||||
local way = self._startpos.y - pos.y
|
||||
local damage = (way - 1) * 2
|
||||
damage = math.min(40, math.max(0, damage))
|
||||
if damage >= 1 then
|
||||
hp = hp - damage
|
||||
if hp < 0 then
|
||||
hp = 0
|
||||
end
|
||||
v:get_luaentity().health = hp
|
||||
end
|
||||
dmg_type = "falling_node"
|
||||
end
|
||||
mcl_util.deal_damage(obj, damage, {type = dmg_type})
|
||||
end
|
||||
end
|
||||
end
|
||||
|
@ -177,7 +177,8 @@ local function object_in_range(self, object)
|
||||
local factor
|
||||
-- Apply view range reduction for special player armor
|
||||
if object:is_player() and mod_armor then
|
||||
factor = armor:get_mob_view_range_factor(object, self.name)
|
||||
local factors = mcl_armor.player_view_range_factors[object]
|
||||
factor = factors and factors[self.name]
|
||||
end
|
||||
-- Distance check
|
||||
local dist
|
||||
@ -3770,6 +3771,7 @@ minetest.register_entity(name, {
|
||||
use_texture_alpha = def.use_texture_alpha,
|
||||
stepheight = def.stepheight or 0.6,
|
||||
name = name,
|
||||
description = def.description,
|
||||
type = def.type,
|
||||
attack_type = def.attack_type,
|
||||
fly = def.fly,
|
||||
|
@ -516,8 +516,6 @@ end
|
||||
|
||||
-- Evoker
|
||||
if c("totem") then
|
||||
local hud_totem = {}
|
||||
|
||||
-- Totem of Undying
|
||||
minetest.register_craftitem("mobs_mc:totem", {
|
||||
description = S("Totem of Undying"),
|
||||
@ -527,66 +525,8 @@ if c("totem") then
|
||||
inventory_image = "mcl_totems_totem.png",
|
||||
wield_image = "mcl_totems_totem.png",
|
||||
stack_max = 1,
|
||||
groups = {combat_item=1},
|
||||
})
|
||||
|
||||
minetest.register_on_leaveplayer(function(player)
|
||||
hud_totem[player:get_player_name()] = nil
|
||||
end)
|
||||
|
||||
-- Save the player from death when holding totem of undying in hand
|
||||
minetest.register_on_player_hpchange(function(player, hp_change)
|
||||
local hp = player:get_hp()
|
||||
-- Fatal damage?
|
||||
if hp + hp_change <= 0 then
|
||||
local wield = player:get_wielded_item()
|
||||
if wield:get_name() == "mobs_mc:totem" then
|
||||
local ppos = player:get_pos()
|
||||
local pnname = minetest.get_node(ppos).name
|
||||
-- Some exceptions when _not_ to save the player
|
||||
for n=1, #mobs_mc.misc.totem_fail_nodes do
|
||||
if pnname == mobs_mc.misc.totem_fail_nodes[n] then
|
||||
return hp_change
|
||||
end
|
||||
end
|
||||
-- Reset breath as well
|
||||
if player:get_breath() < 11 then
|
||||
player:set_breath(10)
|
||||
end
|
||||
if not minetest.is_creative_enabled(player:get_player_name()) then
|
||||
wield:take_item()
|
||||
player:set_wielded_item(wield)
|
||||
end
|
||||
-- Effects
|
||||
minetest.sound_play({name = "mcl_totems_totem", gain=1}, {pos=ppos, max_hear_distance=16}, true)
|
||||
|
||||
-- Big totem overlay
|
||||
if not hud_totem[player:get_player_name()] then
|
||||
hud_totem[player:get_player_name()] = player:hud_add({
|
||||
hud_elem_type = "image",
|
||||
text = "mcl_totems_totem.png",
|
||||
position = { x=0.5, y=1 },
|
||||
scale = { x=17, y=17 },
|
||||
offset = { x=0, y=-178 },
|
||||
z_index = 100,
|
||||
})
|
||||
minetest.after(3, function(name)
|
||||
local player = minetest.get_player_by_name(name)
|
||||
if player and player:is_player() then
|
||||
local name = player:get_player_name()
|
||||
if hud_totem[name] then
|
||||
player:hud_remove(hud_totem[name])
|
||||
hud_totem[name] = nil
|
||||
end
|
||||
end
|
||||
end, player:get_player_name())
|
||||
end
|
||||
|
||||
-- Set HP to exactly 1
|
||||
return -hp + 1
|
||||
end
|
||||
end
|
||||
return hp_change
|
||||
end, true)
|
||||
end
|
||||
|
||||
-- Rotten flesh
|
||||
|
@ -3,6 +3,7 @@
|
||||
local S = minetest.get_translator("mobs_mc")
|
||||
|
||||
mobs:register_mob("mobs_mc:bat", {
|
||||
description = S("Bat"),
|
||||
type = "animal",
|
||||
spawn_class = "ambient",
|
||||
can_despawn = true,
|
||||
|
@ -11,6 +11,7 @@ local S = minetest.get_translator("mobs_mc")
|
||||
|
||||
|
||||
mobs:register_mob("mobs_mc:blaze", {
|
||||
description = S("Blaze"),
|
||||
type = "monster",
|
||||
spawn_class = "hostile",
|
||||
hp_min = 20,
|
||||
@ -147,13 +148,11 @@ mobs:register_arrow("mobs_mc:blaze_fireball", {
|
||||
visual_size = {x = 0.3, y = 0.3},
|
||||
textures = {"mcl_fire_fire_charge.png"},
|
||||
velocity = 15,
|
||||
_is_fireball = true,
|
||||
|
||||
-- Direct hit, no fire... just plenty of pain
|
||||
hit_player = function(self, player)
|
||||
if rawget(_G, "armor") and armor.last_damage_types then
|
||||
armor.last_damage_types[player:get_player_name()] = "fireball"
|
||||
end
|
||||
mcl_burning.set_on_fire(player, 5, "blaze")
|
||||
mcl_burning.set_on_fire(player, 5)
|
||||
player:punch(self.object, 1.0, {
|
||||
full_punch_interval = 1.0,
|
||||
damage_groups = {fleshy = 5},
|
||||
|
@ -9,6 +9,7 @@ local S = minetest.get_translator("mobs_mc")
|
||||
|
||||
|
||||
mobs:register_mob("mobs_mc:chicken", {
|
||||
description = S("Chicken"),
|
||||
type = "animal",
|
||||
spawn_class = "passive",
|
||||
|
||||
|
@ -3,6 +3,7 @@
|
||||
local S = minetest.get_translator("mobs_mc")
|
||||
|
||||
local cow_def = {
|
||||
description = S("Cow"),
|
||||
type = "animal",
|
||||
spawn_class = "passive",
|
||||
hp_min = 10,
|
||||
@ -81,7 +82,7 @@ mobs:register_mob("mobs_mc:cow", cow_def)
|
||||
|
||||
-- Mooshroom
|
||||
local mooshroom_def = table.copy(cow_def)
|
||||
|
||||
mooshroom_def.description = S("Mooshroom")
|
||||
mooshroom_def.mesh = "mobs_mc_cow.b3d"
|
||||
mooshroom_def.textures = { {"mobs_mc_mooshroom.png", "mobs_mc_mushroom_red.png"}, {"mobs_mc_mooshroom_brown.png", "mobs_mc_mushroom_brown.png" } }
|
||||
mooshroom_def.on_rightclick = function(self, clicker)
|
||||
|
@ -130,6 +130,7 @@ mobs:register_mob("mobs_mc:creeper", {
|
||||
})
|
||||
|
||||
mobs:register_mob("mobs_mc:creeper_charged", {
|
||||
description = S("Creeper"),
|
||||
type = "monster",
|
||||
spawn_class = "hostile",
|
||||
hp_min = 20,
|
||||
|
@ -5,6 +5,7 @@
|
||||
local S = minetest.get_translator("mobs_mc")
|
||||
|
||||
mobs:register_mob("mobs_mc:enderdragon", {
|
||||
description = S("Ender Dragon"),
|
||||
type = "monster",
|
||||
spawn_class = "hostile",
|
||||
pathfinding = 1,
|
||||
|
@ -190,6 +190,7 @@ end
|
||||
local mobs_griefing = minetest.settings:get_bool("mobs_griefing") ~= false
|
||||
|
||||
mobs:register_mob("mobs_mc:enderman", {
|
||||
description = S("Enderman"),
|
||||
type = "monster",
|
||||
spawn_class = "passive",
|
||||
passive = true,
|
||||
|
@ -5,6 +5,7 @@
|
||||
local S = minetest.get_translator("mobs_mc")
|
||||
|
||||
mobs:register_mob("mobs_mc:endermite", {
|
||||
description = S("Endermite"),
|
||||
type = "monster",
|
||||
spawn_class = "hostile",
|
||||
passive = false,
|
||||
|
@ -11,6 +11,7 @@ local S = minetest.get_translator("mobs_mc")
|
||||
|
||||
|
||||
mobs:register_mob("mobs_mc:ghast", {
|
||||
description = S("Ghast"),
|
||||
type = "monster",
|
||||
spawn_class = "hostile",
|
||||
pathfinding = 1,
|
||||
@ -97,11 +98,9 @@ mobs:register_arrow("mobs_mc:fireball", {
|
||||
textures = {"mcl_fire_fire_charge.png"},
|
||||
velocity = 15,
|
||||
collisionbox = {-.5, -.5, -.5, .5, .5, .5},
|
||||
_is_fireball = true,
|
||||
|
||||
hit_player = function(self, player)
|
||||
if rawget(_G, "armor") and armor.last_damage_types then
|
||||
armor.last_damage_types[player:get_player_name()] = "fireball"
|
||||
end
|
||||
player:punch(self.object, 1.0, {
|
||||
full_punch_interval = 1.0,
|
||||
damage_groups = {fleshy = 6},
|
||||
|
@ -5,6 +5,7 @@
|
||||
local S = minetest.get_translator("mobs_mc")
|
||||
|
||||
mobs:register_mob("mobs_mc:guardian", {
|
||||
description = S("Guardian"),
|
||||
type = "monster",
|
||||
spawn_class = "hostile",
|
||||
hp_min = 30,
|
||||
|
@ -7,6 +7,7 @@
|
||||
local S = minetest.get_translator("mobs_mc")
|
||||
|
||||
mobs:register_mob("mobs_mc:guardian_elder", {
|
||||
description = S("Elder Guardian"),
|
||||
type = "monster",
|
||||
spawn_class = "hostile",
|
||||
hp_min = 80,
|
||||
|
@ -83,6 +83,7 @@ end
|
||||
|
||||
-- Horse
|
||||
local horse = {
|
||||
description = S("Horse"),
|
||||
type = "animal",
|
||||
spawn_class = "passive",
|
||||
visual = "mesh",
|
||||
@ -418,6 +419,7 @@ mobs:register_mob("mobs_mc:horse", horse)
|
||||
|
||||
-- Skeleton horse
|
||||
local skeleton_horse = table.copy(horse)
|
||||
skeleton_horse.description = S("Skeleton Horse")
|
||||
skeleton_horse.breath_max = -1
|
||||
skeleton_horse.armor = {undead = 100, fleshy = 100}
|
||||
skeleton_horse.textures = {{"blank.png", "mobs_mc_horse_skeleton.png", "blank.png"}}
|
||||
@ -440,6 +442,7 @@ mobs:register_mob("mobs_mc:skeleton_horse", skeleton_horse)
|
||||
|
||||
-- Zombie horse
|
||||
local zombie_horse = table.copy(horse)
|
||||
zombie_horse.description = S("Zombie Horse")
|
||||
zombie_horse.breath_max = -1
|
||||
zombie_horse.armor = {undead = 100, fleshy = 100}
|
||||
zombie_horse.textures = {{"blank.png", "mobs_mc_horse_zombie.png", "blank.png"}}
|
||||
@ -464,6 +467,7 @@ mobs:register_mob("mobs_mc:zombie_horse", zombie_horse)
|
||||
-- Donkey
|
||||
local d = 0.86 -- donkey scale
|
||||
local donkey = table.copy(horse)
|
||||
donkey.description = S("Donkey")
|
||||
donkey.textures = {{"blank.png", "mobs_mc_donkey.png", "blank.png"}}
|
||||
donkey.animation = {
|
||||
speed_normal = 25,
|
||||
@ -494,6 +498,7 @@ mobs:register_mob("mobs_mc:donkey", donkey)
|
||||
-- Mule
|
||||
local m = 0.94
|
||||
local mule = table.copy(donkey)
|
||||
mule.description = S("Mule")
|
||||
mule.textures = {{"blank.png", "mobs_mc_mule.png", "blank.png"}}
|
||||
mule.visual_size = { x=horse.visual_size.x*m, y=horse.visual_size.y*m }
|
||||
mule.sounds = table.copy(donkey.sounds)
|
||||
|
@ -12,6 +12,7 @@ local S = minetest.get_translator("mobs_mc")
|
||||
|
||||
|
||||
mobs:register_mob("mobs_mc:iron_golem", {
|
||||
description = S("Iron Golem"),
|
||||
type = "npc",
|
||||
spawn_class = "passive",
|
||||
passive = true,
|
||||
|
@ -25,6 +25,7 @@ local carpets = {
|
||||
}
|
||||
|
||||
mobs:register_mob("mobs_mc:llama", {
|
||||
description = S("Llama"),
|
||||
type = "animal",
|
||||
spawn_class = "passive",
|
||||
hp_min = 15,
|
||||
|
@ -27,6 +27,7 @@ end
|
||||
|
||||
-- Ocelot
|
||||
local ocelot = {
|
||||
description = S("Ocelot"),
|
||||
type = "animal",
|
||||
spawn_class = "passive",
|
||||
can_despawn = true,
|
||||
@ -102,6 +103,7 @@ mobs:register_mob("mobs_mc:ocelot", ocelot)
|
||||
|
||||
-- Cat
|
||||
local cat = table.copy(ocelot)
|
||||
cat.description = S("Cat")
|
||||
cat.textures = {{"mobs_mc_cat_black.png"}, {"mobs_mc_cat_red.png"}, {"mobs_mc_cat_siamese.png"}}
|
||||
cat.can_despawn = false
|
||||
cat.owner = ""
|
||||
|
@ -12,6 +12,7 @@ local S = minetest.get_translator("mobs_mc")
|
||||
|
||||
|
||||
mobs:register_mob("mobs_mc:parrot", {
|
||||
description = S("Parrot"),
|
||||
type = "npc",
|
||||
spawn_class = "passive",
|
||||
pathfinding = 1,
|
||||
|
@ -3,6 +3,7 @@
|
||||
local S = minetest.get_translator("mobs_mc")
|
||||
|
||||
mobs:register_mob("mobs_mc:pig", {
|
||||
description = S("Pig"),
|
||||
type = "animal",
|
||||
spawn_class = "passive",
|
||||
runaway = true,
|
||||
|
@ -8,6 +8,7 @@ local S = minetest.get_translator("mobs_mc")
|
||||
|
||||
|
||||
mobs:register_mob("mobs_mc:polar_bear", {
|
||||
description = S("Polar Bear"),
|
||||
type = "animal",
|
||||
spawn_class = "passive",
|
||||
runaway = false,
|
||||
|
@ -3,6 +3,7 @@
|
||||
local S = minetest.get_translator("mobs_mc")
|
||||
|
||||
local rabbit = {
|
||||
description = S("Rabbit"),
|
||||
type = "animal",
|
||||
spawn_class = "passive",
|
||||
passive = true,
|
||||
@ -83,6 +84,7 @@ mobs:register_mob("mobs_mc:rabbit", rabbit)
|
||||
|
||||
-- The killer bunny (Only with spawn egg)
|
||||
local killer_bunny = table.copy(rabbit)
|
||||
killer_bunny.description = S("Killer Bunny")
|
||||
killer_bunny.type = "monster"
|
||||
killer_bunny.spawn_class = "hostile"
|
||||
killer_bunny.attack_type = "dogfight"
|
||||
|
@ -56,6 +56,7 @@ local gotten_texture = { "blank.png", "mobs_mc_sheep.png" }
|
||||
|
||||
--mcsheep
|
||||
mobs:register_mob("mobs_mc:sheep", {
|
||||
description = S("Sheep"),
|
||||
type = "animal",
|
||||
spawn_class = "passive",
|
||||
hp_min = 8,
|
||||
|
@ -12,6 +12,7 @@ local S = minetest.get_translator("mobs_mc")
|
||||
-- animation 45-80 is transition between passive and attack stance
|
||||
|
||||
mobs:register_mob("mobs_mc:shulker", {
|
||||
description = S("Shulker"),
|
||||
type = "monster",
|
||||
spawn_class = "hostile",
|
||||
attack_type = "shoot",
|
||||
|
@ -5,6 +5,7 @@
|
||||
local S = minetest.get_translator("mobs_mc")
|
||||
|
||||
mobs:register_mob("mobs_mc:silverfish", {
|
||||
description = S("Silverfish"),
|
||||
type = "monster",
|
||||
spawn_class = "hostile",
|
||||
passive = false,
|
||||
|
@ -13,6 +13,7 @@ local mod_bows = minetest.get_modpath("mcl_bows") ~= nil
|
||||
|
||||
|
||||
local skeleton = {
|
||||
description = S("Skeleton"),
|
||||
type = "monster",
|
||||
spawn_class = "hostile",
|
||||
hp_min = 20,
|
||||
@ -109,6 +110,7 @@ mobs:register_mob("mobs_mc:skeleton", skeleton)
|
||||
--###################
|
||||
|
||||
local stray = table.copy(skeleton)
|
||||
stray.description = S("Stray")
|
||||
stray.mesh = "mobs_mc_skeleton.b3d"
|
||||
stray.textures = {
|
||||
{
|
||||
|
@ -10,6 +10,7 @@ local S = minetest.get_translator("mobs_mc")
|
||||
--###################
|
||||
|
||||
mobs:register_mob("mobs_mc:witherskeleton", {
|
||||
description = S("Wither Skeleton"),
|
||||
type = "monster",
|
||||
spawn_class = "hostile",
|
||||
hp_min = 20,
|
||||
|
@ -56,6 +56,7 @@ end
|
||||
|
||||
-- Slime
|
||||
local slime_big = {
|
||||
description = S("Slime"),
|
||||
type = "monster",
|
||||
spawn_class = "hostile",
|
||||
pathfinding = 1,
|
||||
@ -291,6 +292,7 @@ smax)
|
||||
|
||||
-- Magma cube
|
||||
local magma_cube_big = {
|
||||
description = S("Magma Cube"),
|
||||
type = "monster",
|
||||
spawn_class = "hostile",
|
||||
hp_min = 16,
|
||||
|
@ -21,6 +21,7 @@ local gotten_texture = {
|
||||
}
|
||||
|
||||
mobs:register_mob("mobs_mc:snowman", {
|
||||
description = S("Snow Golem"),
|
||||
type = "npc",
|
||||
spawn_class = "passive",
|
||||
passive = true,
|
||||
|
@ -13,6 +13,7 @@ local S = minetest.get_translator("mobs_mc")
|
||||
-- Spider by AspireMint (fishyWET (CC-BY-SA 3.0 license for texture)
|
||||
|
||||
local spider = {
|
||||
description = S("Spider"),
|
||||
type = "monster",
|
||||
spawn_class = "hostile",
|
||||
passive = false,
|
||||
@ -72,6 +73,7 @@ mobs:register_mob("mobs_mc:spider", spider)
|
||||
|
||||
-- Cave spider
|
||||
local cave_spider = table.copy(spider)
|
||||
cave_spider.description = S("Cave Spider")
|
||||
cave_spider.textures = { {"mobs_mc_cave_spider.png^(mobs_mc_spider_eyes.png^[makealpha:0,0,0)"} }
|
||||
-- TODO: Poison damage
|
||||
-- TODO: Revert damage to 2
|
||||
|
@ -7,6 +7,7 @@
|
||||
local S = minetest.get_translator("mobs_mc")
|
||||
|
||||
mobs:register_mob("mobs_mc:squid", {
|
||||
description = S("Squid"),
|
||||
type = "animal",
|
||||
spawn_class = "water",
|
||||
can_despawn = true,
|
||||
|
@ -10,6 +10,7 @@ local S = minetest.get_translator("mobs_mc")
|
||||
--###################
|
||||
|
||||
mobs:register_mob("mobs_mc:vex", {
|
||||
description = S("Vex"),
|
||||
type = "monster",
|
||||
spawn_class = "hostile",
|
||||
pathfinding = 1,
|
||||
|
@ -927,6 +927,7 @@ end)
|
||||
--[=======[ MOB REGISTRATION AND SPAWNING ]=======]
|
||||
|
||||
mobs:register_mob("mobs_mc:villager", {
|
||||
description = S("Villager"),
|
||||
type = "npc",
|
||||
spawn_class = "passive",
|
||||
hp_min = 20,
|
||||
|
@ -12,6 +12,7 @@ local S = minetest.get_translator("mobs_mc")
|
||||
local pr = PseudoRandom(os.time()*666)
|
||||
|
||||
mobs:register_mob("mobs_mc:evoker", {
|
||||
description = S("Evoker"),
|
||||
type = "monster",
|
||||
spawn_class = "hostile",
|
||||
physical = true,
|
||||
|
@ -7,6 +7,7 @@ local S = minetest.get_translator("mobs_mc")
|
||||
local mod_bows = minetest.get_modpath("mcl_bows") ~= nil
|
||||
|
||||
mobs:register_mob("mobs_mc:illusioner", {
|
||||
description = S("Illusioner"),
|
||||
type = "monster",
|
||||
spawn_class = "hostile",
|
||||
attack_type = "shoot",
|
||||
|
@ -11,6 +11,7 @@ local S = minetest.get_translator("mobs_mc")
|
||||
|
||||
|
||||
mobs:register_mob("mobs_mc:vindicator", {
|
||||
description = S("Vindicator"),
|
||||
type = "monster",
|
||||
spawn_class = "hostile",
|
||||
physical = false,
|
||||
|
@ -26,6 +26,7 @@ local professions = {
|
||||
}
|
||||
|
||||
mobs:register_mob("mobs_mc:villager_zombie", {
|
||||
description = S("Zombie Villager"),
|
||||
type = "monster",
|
||||
spawn_class = "hostile",
|
||||
hp_min = 20,
|
||||
|
@ -13,6 +13,7 @@ local S = minetest.get_translator("mobs_mc")
|
||||
|
||||
|
||||
mobs:register_mob("mobs_mc:witch", {
|
||||
description = S("Witch"),
|
||||
type = "monster",
|
||||
spawn_class = "hostile",
|
||||
hp_min = 26,
|
||||
|
@ -10,6 +10,7 @@ local S = minetest.get_translator("mobs_mc")
|
||||
--###################
|
||||
|
||||
mobs:register_mob("mobs_mc:wither", {
|
||||
description = S("Wither"),
|
||||
type = "monster",
|
||||
spawn_class = "hostile",
|
||||
hp_max = 300,
|
||||
|
@ -19,6 +19,7 @@ end
|
||||
|
||||
-- Wolf
|
||||
local wolf = {
|
||||
description = S("Wolf"),
|
||||
type = "animal",
|
||||
spawn_class = "passive",
|
||||
can_despawn = true,
|
||||
|
@ -46,6 +46,7 @@ table.insert(drops_zombie, {
|
||||
})
|
||||
|
||||
local zombie = {
|
||||
description = S("Zombie"),
|
||||
type = "monster",
|
||||
spawn_class = "hostile",
|
||||
hp_min = 20,
|
||||
@ -102,6 +103,7 @@ mobs:register_mob("mobs_mc:zombie", zombie)
|
||||
-- A smaller and more dangerous variant of the zombie
|
||||
|
||||
local baby_zombie = table.copy(zombie)
|
||||
baby_zombie.description = S("Baby Zombie")
|
||||
baby_zombie.collisionbox = {-0.25, -0.01, -0.25, 0.25, 0.94, 0.25}
|
||||
baby_zombie.xp_min = 12
|
||||
baby_zombie.xp_max = 12
|
||||
@ -115,6 +117,7 @@ mobs:register_mob("mobs_mc:baby_zombie", baby_zombie)
|
||||
-- Husk.
|
||||
-- Desert variant of the zombie
|
||||
local husk = table.copy(zombie)
|
||||
husk.description = S("Husk")
|
||||
husk.textures = {
|
||||
{
|
||||
"mobs_mc_empty.png", -- armor
|
||||
@ -132,6 +135,7 @@ mobs:register_mob("mobs_mc:husk", husk)
|
||||
-- Baby husk.
|
||||
-- A smaller and more dangerous variant of the husk
|
||||
local baby_husk = table.copy(husk)
|
||||
baby_husk.description = S("Baby Husk")
|
||||
baby_husk.collisionbox = {-0.25, -0.01, -0.25, 0.25, 0.94, 0.25}
|
||||
baby_husk.xp_min = 12
|
||||
baby_husk.xp_max = 12
|
||||
|
@ -11,6 +11,7 @@ local S = minetest.get_translator("mobs_mc")
|
||||
|
||||
|
||||
local pigman = {
|
||||
description = S("Zombie Pigman"),
|
||||
-- type="animal", passive=false: This combination is needed for a neutral mob which becomes hostile, if attacked
|
||||
type = "animal",
|
||||
passive = false,
|
||||
@ -94,6 +95,7 @@ mobs:register_mob("mobs_mc:pigman", pigman)
|
||||
-- A smaller and more dangerous variant of the pigman
|
||||
|
||||
local baby_pigman = table.copy(pigman)
|
||||
baby_pigman.description = S("Baby Zombie Pigman")
|
||||
baby_pigman.collisionbox = {-0.25, -0.01, -0.25, 0.25, 0.94, 0.25}
|
||||
baby_pigman.xp_min = 13
|
||||
baby_pigman.xp_max = 13
|
||||
|
@ -11,7 +11,6 @@ of the license, or (at your option) any later version.
|
||||
|
||||
local S = minetest.get_translator("lightning")
|
||||
|
||||
local has_mcl_death_msg = minetest.get_modpath("mcl_death_messages")
|
||||
local get_connected_players = minetest.get_connected_players
|
||||
local line_of_sight = minetest.line_of_sight
|
||||
local get_node = minetest.get_node
|
||||
@ -139,22 +138,14 @@ lightning.strike = function(pos)
|
||||
for o=1, #objs do
|
||||
local obj = objs[o]
|
||||
local lua = obj:get_luaentity()
|
||||
if obj:is_player() then
|
||||
-- Player damage
|
||||
if has_mcl_death_msg then
|
||||
mcl_death_messages.player_damage(obj, S("@1 was struck by lightning.", obj:get_player_name()))
|
||||
end
|
||||
obj:set_hp(obj:get_hp()-5, { type = "punch", from = "mod" })
|
||||
-- Mobs
|
||||
elseif lua and lua._cmi_is_mob then
|
||||
-- pig → zombie pigman (no damage)
|
||||
if lua.name == "mobs_mc:pig" then
|
||||
if lua and lua.name == "mobs_mc:pig" then
|
||||
local rot = obj:get_yaw()
|
||||
obj:remove()
|
||||
obj = add_entity(pos2, "mobs_mc:pigman")
|
||||
obj:set_yaw(rot)
|
||||
-- mooshroom: toggle color red/brown (no damage)
|
||||
elseif lua.name == "mobs_mc:mooshroom" then
|
||||
elseif lua and lua.name == "mobs_mc:mooshroom" then
|
||||
if lua.base_texture[1] == "mobs_mc_mooshroom.png" then
|
||||
lua.base_texture = { "mobs_mc_mooshroom_brown.png", "mobs_mc_mushroom_brown.png" }
|
||||
else
|
||||
@ -162,7 +153,7 @@ lightning.strike = function(pos)
|
||||
end
|
||||
obj:set_properties({textures = lua.base_texture})
|
||||
-- villager → witch (no damage)
|
||||
elseif lua.name == "mobs_mc:villager" then
|
||||
elseif lua and lua.name == "mobs_mc:villager" then
|
||||
-- Witches are incomplete, this code is unused
|
||||
-- TODO: Enable this code when witches are working.
|
||||
--[[
|
||||
@ -172,15 +163,14 @@ lightning.strike = function(pos)
|
||||
obj:set_yaw(rot)
|
||||
]]
|
||||
-- charged creeper
|
||||
elseif lua.name == "mobs_mc:creeper" then
|
||||
elseif lua and lua.name == "mobs_mc:creeper" then
|
||||
local rot = obj:get_yaw()
|
||||
obj:remove()
|
||||
obj = add_entity(pos2, "mobs_mc:creeper_charged")
|
||||
obj:set_yaw(rot)
|
||||
-- Other mobs: Just damage
|
||||
-- Other objects: Just damage
|
||||
else
|
||||
obj:set_hp(obj:get_hp()-5, { type = "punch", from = "mod" })
|
||||
end
|
||||
mcl_util.deal_damage(obj, 5, {type = "lightning_bolt"})
|
||||
end
|
||||
end
|
||||
|
||||
|
@ -2,5 +2,4 @@ name = lightning
|
||||
author = sofar
|
||||
description = A mod that adds thunder and lightning effects.
|
||||
depends = mcl_fire
|
||||
optional_depends = mcl_death_messages
|
||||
|
||||
|
@ -5,7 +5,6 @@ local pos_to_dim = mcl_worlds.pos_to_dimension
|
||||
local dim_change = mcl_worlds.dimension_change
|
||||
local is_in_void = mcl_worlds.is_in_void
|
||||
local get_spawn_pos = mcl_spawn.get_player_spawn_pos
|
||||
local death_msg = mcl_death_messages.player_damage
|
||||
local send_chat = minetest.chat_send_player
|
||||
local get_connected = minetest.get_connected_players
|
||||
|
||||
@ -40,7 +39,6 @@ minetest.register_on_mods_loaded(function()
|
||||
end
|
||||
self._void_timer = 0
|
||||
|
||||
local pos = obj:get_pos()
|
||||
local void, void_deadly = is_in_void(pos)
|
||||
if void_deadly then
|
||||
local ent = obj:get_luaentity()
|
||||
@ -80,8 +78,7 @@ minetest.register_globalstep(function(dtime)
|
||||
elseif enable_damage and not is_immortal then
|
||||
-- Damage enabled, not immortal: Deal void damage (4 HP / 0.5 seconds)
|
||||
if player:get_hp() > 0 then
|
||||
death_msg(player, S("@1 fell into the endless void.", player:get_player_name()))
|
||||
player:set_hp(player:get_hp() - VOID_DAMAGE)
|
||||
mcl_util.deal_damage(player, VOID_DAMAGE, {type = "out_of_world"})
|
||||
end
|
||||
end
|
||||
end
|
||||
|
@ -1,4 +1,4 @@
|
||||
name = mcl_void_damage
|
||||
author = Wuzzy
|
||||
description = Deal damage to entities stuck in the deep void
|
||||
depends = mcl_worlds, mcl_death_messages
|
||||
depends = mcl_worlds
|
||||
|
@ -1,307 +1,247 @@
|
||||
local S = minetest.get_translator("mcl_death_messages")
|
||||
local N = function(s) return s end
|
||||
local C = minetest.colorize
|
||||
|
||||
local color_skyblue = mcl_colors.AQUA
|
||||
|
||||
local function get_tool_name(item)
|
||||
local name = item:get_meta():get_string("name")
|
||||
if name ~= "" then
|
||||
return name
|
||||
end
|
||||
local def = item:get_definition()
|
||||
return def._tt_original_description or def.description
|
||||
end
|
||||
|
||||
mcl_death_messages = {}
|
||||
|
||||
-- Death messages
|
||||
local msgs = {
|
||||
["arrow"] = {
|
||||
N("@1 was fatally hit by an arrow."),
|
||||
N("@1 has been killed by an arrow."),
|
||||
mcl_death_messages = {
|
||||
assist = {},
|
||||
messages = {
|
||||
in_fire = {
|
||||
_translator = S,
|
||||
plain = "@1 went up in flames",
|
||||
assist = "@1 walked into fire whilst fighting @2",
|
||||
},
|
||||
["arrow_name"] = {
|
||||
N("@1 was shot by @2 using [@3]"),
|
||||
lightning_bolt = {
|
||||
_translator = S,
|
||||
plain = "@1 was struck by lightning",
|
||||
assist = "@1 was struck by lightning whilst fighting @2",
|
||||
},
|
||||
["arrow_skeleton"] = {
|
||||
N("@1 was shot by Skeleton."),
|
||||
on_fire = {
|
||||
_translator = S,
|
||||
plain = "@1 burned to death",
|
||||
assist = "@1 was burnt to a crisp whilst fighting @2",
|
||||
},
|
||||
["arrow_stray"] = {
|
||||
N("@1 was shot by Stray."),
|
||||
lava = {
|
||||
_translator = S,
|
||||
plain = "@1 tried to swim in lava",
|
||||
assist = "@1 tried to swim in lava to escape @2"
|
||||
},
|
||||
["arrow_illusioner"] = {
|
||||
N("@1 was shot by Illusioner."),
|
||||
hot_floor = {
|
||||
_translator = S,
|
||||
plain = "@1 discovered the floor was lava",
|
||||
assist = "@1 walked into danger zone due to @2",
|
||||
},
|
||||
["arrow_mob"] = {
|
||||
N("@1 was shot."),
|
||||
in_wall = {
|
||||
_translator = S,
|
||||
plain = "@1 suffocated in a wall",
|
||||
assist = "@1 suffocated in a wall whilst fighting @2",
|
||||
},
|
||||
["drown"] = {
|
||||
N("@1 forgot to breathe."),
|
||||
N("@1 drowned."),
|
||||
N("@1 ran out of oxygen."),
|
||||
drown = {
|
||||
_translator = S,
|
||||
plain = "@1 drowned",
|
||||
assist = "@1 drowned whilst trying to escape @2",
|
||||
},
|
||||
["murder"] = {
|
||||
N("@1 was slain by @2 using [@3]"),
|
||||
starve = {
|
||||
_translator = S,
|
||||
plain = "@1 starved to death",
|
||||
assist = "@1 starved to death whilst fighting @2",
|
||||
},
|
||||
["murder_hand"] = {
|
||||
N("@1 was slain by @2"),
|
||||
cactus = {
|
||||
_translator = S,
|
||||
plain = "@1 was pricked to death",
|
||||
assist = "@1 walked into a cactus whilst trying to escape @2",
|
||||
},
|
||||
["murder_any"] = {
|
||||
N("@1 was killed."),
|
||||
fall = {
|
||||
_translator = S,
|
||||
plain = "@1 hit the ground too hard",
|
||||
assist = "@1 hit the ground too hard whilst trying to escape @2",
|
||||
-- "@1 fell from a high place" -- for fall distance > 5 blocks
|
||||
-- "@1 fell while climbing"
|
||||
-- "@1 fell off some twisting vines"
|
||||
-- "@1 fell off some weeping vines"
|
||||
-- "@1 fell off some vines"
|
||||
-- "@1 fell off scaffolding"
|
||||
-- "@1 fell off a ladder"
|
||||
},
|
||||
["mob_kill"] = {
|
||||
N("@1 was slain by a mob."),
|
||||
fly_into_wall = {
|
||||
_translator = S,
|
||||
plain = "@1 experienced kinetic energy",
|
||||
assist = "@1 experienced kinetic energy whilst trying to escape @2",
|
||||
},
|
||||
["blaze_fireball"] = {
|
||||
N("@1 was burned to death by a Blaze's fireball."),
|
||||
N("@1 was fireballed by a Blaze"),
|
||||
out_of_world = {
|
||||
_translator = S,
|
||||
plain = "@1 fell out of the world",
|
||||
assist = "@1 didn't want to live in the same world as @2",
|
||||
},
|
||||
["fire_charge"] = {
|
||||
N("@1 was burned by a fire charge."),
|
||||
generic = {
|
||||
_translator = S,
|
||||
plain = "@1 died",
|
||||
assist = "@1 died because of @2",
|
||||
},
|
||||
["ghast_fireball"] = {
|
||||
N("A Ghast scared @1 to death."),
|
||||
N("@1 has been fireballed by a Ghast."),
|
||||
magic = {
|
||||
_translator = S,
|
||||
plain = "@1 was killed by magic",
|
||||
assist = "@1 was killed by magic whilst trying to escape @2",
|
||||
killer = "@1 was killed by @2 using magic",
|
||||
item = "@1 was killed by @2 using @3",
|
||||
},
|
||||
["fall"] = {
|
||||
N("@1 fell from a high cliff."),
|
||||
N("@1 took fatal fall damage."),
|
||||
N("@1 fell victim to gravity."),
|
||||
N("@1 hit the ground too hard.")
|
||||
dragon_breath = {
|
||||
_translator = S,
|
||||
plain = "@1 was roasted in dragon breath",
|
||||
killer = "@1 was roasted in dragon breath by @2",
|
||||
},
|
||||
wither = {
|
||||
_translator = S,
|
||||
plain = "@1 withered away",
|
||||
escape = "@1 withered away whilst fighting @2",
|
||||
},
|
||||
wither_skull = {
|
||||
_translator = S,
|
||||
plain = "@1 was killed by magic",
|
||||
killer = "@1 was shot by a skull from @2",
|
||||
},
|
||||
anvil = {
|
||||
_translator = S,
|
||||
plain = "@1 was squashed by a falling anvil",
|
||||
escape = "@1 was squashed by a falling anvil whilst fighting @2",
|
||||
},
|
||||
falling_node = {
|
||||
_translator = S,
|
||||
plain = "@1 was squashed by a falling block",
|
||||
assist = "@1 was squashed by a falling block whilst fighting @2",
|
||||
},
|
||||
mob = {
|
||||
_translator = S,
|
||||
killer = "@1 was slain by @2",
|
||||
item = "@1 was slain by @2 using @3",
|
||||
},
|
||||
player = {
|
||||
_translator = S,
|
||||
killer = "@1 was slain by @2",
|
||||
item = "@1 was slain by @2 using @3"
|
||||
},
|
||||
arrow = {
|
||||
_translator = S,
|
||||
killer = "@1 was shot by @2",
|
||||
item = "@1 was shot by @2 using @3",
|
||||
},
|
||||
fireball = {
|
||||
_translator = S,
|
||||
killer = "@1 was fireballed by @2",
|
||||
item = "@1 was fireballed by @2 using @3",
|
||||
},
|
||||
thorns = {
|
||||
_translator = S,
|
||||
killer = "@1 was killed trying to hurt @2",
|
||||
item = "@1 was killed by @3 trying to hurt @2", -- yes, the order is intentional: @1 @3 @2
|
||||
},
|
||||
explosion = {
|
||||
_translator = S,
|
||||
plain = "@1 blew up",
|
||||
killer = "@1 was blown up by @2",
|
||||
item = "@1 was blown up by @2 using @3",
|
||||
-- "@1 was killed by [Intentional Game Design]" -- for exploding bed in nether or end
|
||||
},
|
||||
cramming = {
|
||||
_translator = S,
|
||||
plain = "@1 was squished too much",
|
||||
assist = "@1 was squashed by @2", -- surprisingly "escape" is actually the correct subtype
|
||||
},
|
||||
fireworks = {
|
||||
_translator = S,
|
||||
plain = "@1 went off with a bang",
|
||||
item = "@1 went off with a bang due to a firework fired from @3 by @2", -- order is intentional
|
||||
},
|
||||
-- Missing snowballs: The Minecraft wiki mentions them but the MC source code does not.
|
||||
},
|
||||
|
||||
["other"] = {
|
||||
N("@1 died."),
|
||||
}
|
||||
}
|
||||
|
||||
local mobkills = {
|
||||
["mobs_mc:zombie"] = N("@1 was slain by Zombie."),
|
||||
["mobs_mc:baby_zombie"] = N("@1 was slain by Baby Zombie."),
|
||||
["mobs_mc:blaze"] = N("@1 was burnt to a crisp while fighting Blaze."),
|
||||
["mobs_mc:slime"] = N("@1 was slain by Slime."),
|
||||
["mobs_mc:witch"] = N("@1 was slain by Witch using magic."),
|
||||
["mobs_mc:magma_cube_tiny"] = N("@1 was slain by Magma Cube."),
|
||||
["mobs_mc:magma_cube_small"] = N("@1 was slain by Magma Cube."),
|
||||
["mobs_mc:magma_cube_big"] = N("@1 was slain by Magma Cube."),
|
||||
["mobs_mc:wolf"] = N("@1 was slain by Wolf."),
|
||||
["mobs_mc:cat"] = N("@1 was slain by Cat."),
|
||||
["mobs_mc:ocelot"] = N("@1 was slain by Ocelot."),
|
||||
["mobs_mc:enderdragon"] = N("@1 was slain by Enderdragon."),
|
||||
["mobs_mc:wither"] = N("@1 was slain by Wither."),
|
||||
["mobs_mc:enderman"] = N("@1 was slain by Enderman."),
|
||||
["mobs_mc:endermite"] = N("@1 was slain by Endermite."),
|
||||
["mobs_mc:ghast"] = N("@1 was fireballed by a Ghast."),
|
||||
["mobs_mc:guardian_elder"] = N("@1 was slain by Elder Guardian."),
|
||||
["mobs_mc:guardian"] = N("@1 was slain by Guardian."),
|
||||
["mobs_mc:iron_golem"] = N("@1 was slain by Iron Golem."),
|
||||
["mobs_mc:polar_bear"] = N("@1 was slain by Polar Bear."),
|
||||
["mobs_mc:killer_bunny"] = N("@1 was slain by Killer Bunny."),
|
||||
["mobs_mc:shulker"] = N("@1 was slain by Shulker."),
|
||||
["mobs_mc:silverfish"] = N("@1 was slain by Silverfish."),
|
||||
["mobs_mc:skeleton"] = N("@1 was shot by Skeleton."),
|
||||
["mobs_mc:stray"] = N("@1 was shot by Stray."),
|
||||
["mobs_mc:slime_tiny"] = N("@1 was slain by Slime."),
|
||||
["mobs_mc:slime_small"] = N("@1 was slain by Slime."),
|
||||
["mobs_mc:slime_big"] = N("@1 was slain by Slime."),
|
||||
["mobs_mc:spider"] = N("@1 was slain by Spider."),
|
||||
["mobs_mc:cave_spider"] = N("@1 was slain by Cave Spider."),
|
||||
["mobs_mc:vex"] = N("@1 was slain by Vex."),
|
||||
["mobs_mc:evoker"] = N("@1 was slain by Evoker."),
|
||||
["mobs_mc:illusioner"] = N("@1 was slain by Illusioner."),
|
||||
["mobs_mc:vindicator"] = N("@1 was slain by Vindicator."),
|
||||
["mobs_mc:villager_zombie"] = N("@1 was slain by Zombie Villager."),
|
||||
["mobs_mc:husk"] = N("@1 was slain by Husk."),
|
||||
["mobs_mc:baby_husk"] = N("@1 was slain by Baby Husk."),
|
||||
["mobs_mc:pigman"] = N("@1 was slain by Zombie Pigman."),
|
||||
["mobs_mc:baby_pigman"] = N("@1 was slain by Baby Zombie Pigman."),
|
||||
}
|
||||
|
||||
-- Select death message
|
||||
local dmsg = function(mtype, ...)
|
||||
local r = math.random(1, #msgs[mtype])
|
||||
return S(msgs[mtype][r], ...)
|
||||
local function get_item_killer_message(obj, messages, reason)
|
||||
if messages.item then
|
||||
local wielded = mcl_util.get_wielded_item(reason.source)
|
||||
local itemname = wielded:get_meta():get_string("name")
|
||||
if itemname ~= "" then
|
||||
itemname = "[" .. itemname .. "]"
|
||||
if mcl_enchanting.is_enchanted(wielded:get_name()) then
|
||||
itemname = minetest.colorize(mcl_colors.AQUA, itemname)
|
||||
end
|
||||
return messages._translator(messages.item, mcl_util.get_object_name(obj), mcl_util.get_object_name(reason.source), itemname)
|
||||
end
|
||||
|
||||
-- Select death message for death by mob
|
||||
local mmsg = function(mtype, ...)
|
||||
if mobkills[mtype] then
|
||||
return S(mobkills[mtype], ...)
|
||||
else
|
||||
return dmsg("mob_kill", ...)
|
||||
end
|
||||
end
|
||||
|
||||
local last_damages = { }
|
||||
|
||||
minetest.register_on_dieplayer(function(player, reason)
|
||||
-- Death message
|
||||
local message = minetest.settings:get_bool("mcl_showDeathMessages") --Maybe cache the setting?
|
||||
if message == nil then
|
||||
message = true
|
||||
local function get_plain_killer_message(obj, messages, reason)
|
||||
return messages.killer and messages._translator(messages.killer, mcl_util.get_object_name(obj), mcl_util.get_object_name(reason.source))
|
||||
end
|
||||
if message then
|
||||
local name = player:get_player_name()
|
||||
if not name then
|
||||
|
||||
local function get_killer_message(obj, messages, reason)
|
||||
return reason.source and (get_item_killer_message(obj, messages, reason) or get_plain_killer_message(obj, messages, reason))
|
||||
end
|
||||
|
||||
local function get_assist_message(obj, messages, reason)
|
||||
if messages.assist and mcl_death_messages.assist[obj] then
|
||||
return messages._translator(messages.assist, mcl_util.get_object_name(obj), mcl_death_messages.assist[obj].name)
|
||||
end
|
||||
end
|
||||
|
||||
local function get_plain_message(obj, messages, reason)
|
||||
if messages.plain then
|
||||
return messages._translator(messages.plain, mcl_util.get_object_name(obj))
|
||||
end
|
||||
end
|
||||
|
||||
local function get_fallback_message(obj, messages, reason)
|
||||
return "mcl_death_messages.messages." .. reason.type .. " " .. mcl_util.get_object_name(obj)
|
||||
end
|
||||
|
||||
local function fallback_translator(s)
|
||||
return s
|
||||
end
|
||||
|
||||
mcl_damage.register_on_death(function(obj, reason)
|
||||
if not minetest.settings:get_bool("mcl_showDeathMessages", true) then
|
||||
return
|
||||
end
|
||||
local msg
|
||||
if last_damages[name] then
|
||||
-- custom message
|
||||
msg = last_damages[name].message
|
||||
elseif reason.type == "node_damage" then
|
||||
local pos = player:get_pos()
|
||||
-- Check multiple nodes because players occupy multiple nodes
|
||||
-- (we add one additional node because the check may fail if the player was
|
||||
-- just barely touching the node with the head)
|
||||
local posses = { pos, {x=pos.x,y=pos.y+1,z=pos.z}, {x=pos.x,y=pos.y+2,z=pos.z}}
|
||||
local highest_damage = 0
|
||||
local highest_damage_def = nil
|
||||
-- Show message for node that dealt the most damage
|
||||
for p=1, #posses do
|
||||
local def = minetest.registered_nodes[minetest.get_node(posses[p]).name]
|
||||
local dmg = def.damage_per_second
|
||||
if dmg and dmg > highest_damage then
|
||||
highest_damage = dmg
|
||||
highest_damage_def = def
|
||||
end
|
||||
end
|
||||
if highest_damage_def and highest_damage_def._mcl_node_death_message then
|
||||
local field = highest_damage_def._mcl_node_death_message
|
||||
local field_msg
|
||||
if type(field) == "table" then
|
||||
field_msg = field[math.random(1, #field)]
|
||||
else
|
||||
field_msg = field
|
||||
end
|
||||
local textdomain
|
||||
if highest_damage_def.mod_origin then
|
||||
textdomain = highest_damage_def.mod_origin
|
||||
else
|
||||
textdomain = "mcl_death_messages"
|
||||
end
|
||||
-- We assume the textdomain of the death message in the node definition
|
||||
-- equals the modname.
|
||||
msg = minetest.translate(textdomain, field_msg, name)
|
||||
end
|
||||
elseif reason.type == "drown" then
|
||||
msg = dmsg("drown", name)
|
||||
elseif reason.type == "punch" then
|
||||
-- Punches
|
||||
local hitter = reason.object
|
||||
|
||||
-- Player was slain by potions
|
||||
if not hitter then return end
|
||||
local send_to
|
||||
|
||||
local hittername, hittertype, hittersubtype, shooter
|
||||
local hitter_toolname = get_tool_name(hitter:get_wielded_item())
|
||||
if obj:is_player() then
|
||||
send_to = true
|
||||
end -- ToDo: add mob death messages for owned mobs, only send to owner (sent_to = "player name")
|
||||
|
||||
-- Custom message
|
||||
if last_damages[name] then
|
||||
msg = last_damages[name].message
|
||||
-- Unknown hitter
|
||||
elseif hitter == nil then
|
||||
msg = dmsg("murder_any", name)
|
||||
-- Player
|
||||
elseif hitter:is_player() then
|
||||
hittername = hitter:get_player_name()
|
||||
if hittername ~= nil then
|
||||
if hitter_toolname == "" then
|
||||
msg = dmsg("murder_hand", name, hittername)
|
||||
|
||||
if send_to then
|
||||
local messages = mcl_death_messages.messages[reason.type] or {}
|
||||
messages._translator = messages._translator or fallback_translator
|
||||
|
||||
local message =
|
||||
get_killer_message(obj, messages, reason) or
|
||||
get_assist_message(obj, messages, reason) or
|
||||
get_plain_message(obj, messages, reason) or
|
||||
get_fallback_message(obj, messages, reason)
|
||||
|
||||
if send_to == true then
|
||||
minetest.chat_send_all(message)
|
||||
else
|
||||
msg = dmsg("murder", name, hittername, C(color_skyblue, hitter_toolname))
|
||||
minetest.chat_send_player(send_to, message)
|
||||
end
|
||||
else
|
||||
msg = dmsg("murder_any", name)
|
||||
end
|
||||
-- Mob (according to Common Mob Interface)
|
||||
elseif hitter:get_luaentity()._cmi_is_mob then
|
||||
if hitter:get_luaentity().nametag and hitter:get_luaentity().nametag ~= "" then
|
||||
hittername = hitter:get_luaentity().nametag
|
||||
end
|
||||
hittersubtype = hitter:get_luaentity().name
|
||||
if hittername then
|
||||
msg = dmsg("murder_hand", name, hittername)
|
||||
elseif hittersubtype ~= nil and hittersubtype ~= "" then
|
||||
msg = mmsg(hittersubtype, name)
|
||||
else
|
||||
msg = dmsg("murder_any", name)
|
||||
end
|
||||
-- Arrow
|
||||
elseif hitter:get_luaentity().name == "mcl_bows:arrow_entity" or hitter:get_luaentity().name == "mobs_mc:arrow_entity" and not killed_by_potion then
|
||||
local shooter
|
||||
if hitter:get_luaentity()._shooter then
|
||||
shooter = hitter:get_luaentity()._shooter
|
||||
end
|
||||
local is_mob = false
|
||||
local s_ent = shooter and shooter:get_luaentity()
|
||||
if shooter == nil then
|
||||
msg = dmsg("arrow", name)
|
||||
elseif shooter:is_player() then
|
||||
msg = dmsg("arrow_name", name, shooter:get_player_name(), C(color_skyblue, get_tool_name(shooter:get_wielded_item())))
|
||||
elseif s_ent and s_ent._cmi_is_mob then
|
||||
if s_ent.nametag ~= "" then
|
||||
msg = dmsg("arrow_name", name, shooter:get_player_name(), get_tool_name(shooter:get_wielded_item()))
|
||||
elseif s_ent.name == "mobs_mc:skeleton" then
|
||||
msg = dmsg("arrow_skeleton", name)
|
||||
elseif s_ent.name == "mobs_mc:stray" then
|
||||
msg = dmsg("arrow_stray", name)
|
||||
elseif s_ent.name == "mobs_mc:illusioner" then
|
||||
msg = dmsg("arrow_illusioner", name)
|
||||
else
|
||||
msg = dmsg("arrow_mob", name)
|
||||
end
|
||||
else
|
||||
msg = dmsg("arrow", name)
|
||||
end
|
||||
-- Blaze fireball
|
||||
elseif hitter:get_luaentity().name == "mobs_mc:blaze_fireball" then
|
||||
if hitter:get_luaentity()._shot_from_dispenser then
|
||||
msg = dmsg("fire_charge", name)
|
||||
else
|
||||
msg = dmsg("blaze_fireball", name)
|
||||
end
|
||||
-- Ghast fireball
|
||||
elseif hitter:get_luaentity().name == "mobs_monster:fireball" then
|
||||
msg = dmsg("ghast_fireball", name)
|
||||
end
|
||||
-- Falling
|
||||
elseif reason.type == "fall" then
|
||||
msg = dmsg("fall", name)
|
||||
-- Other
|
||||
elseif reason.type == "set_hp" then
|
||||
if last_damages[name] then
|
||||
msg = last_damages[name].message
|
||||
end
|
||||
end
|
||||
if not msg then
|
||||
msg = dmsg("other", name)
|
||||
end
|
||||
minetest.chat_send_all(msg)
|
||||
last_damages[name] = nil
|
||||
end
|
||||
end)
|
||||
|
||||
-- dmg_sequence_number is used to discard old damage events
|
||||
local dmg_sequence_number = 0
|
||||
local start_damage_reset_countdown = function (player, sequence_number)
|
||||
minetest.after(1, function(playername, sequence_number)
|
||||
if last_damages[playername] and last_damages[playername].sequence_number == sequence_number then
|
||||
last_damages[playername] = nil
|
||||
mcl_damage.register_on_damage(function(obj, damage, reason)
|
||||
if obj:get_hp() - damage > 0 then
|
||||
if reason.source then
|
||||
mcl_death_messages.assist[obj] = {name = mcl_util.get_object_name(reason.source), timeout = 5}
|
||||
else
|
||||
mcl_death_messages.assist[obj] = nil
|
||||
end
|
||||
end, player:get_player_name(), sequence_number)
|
||||
end
|
||||
end)
|
||||
|
||||
-- Send a custom death mesage when damaging a player via set_hp or punch.
|
||||
-- To be called directly BEFORE damaging a player via set_hp or punch.
|
||||
-- The next time the player dies due to a set_hp, the message will be shown.
|
||||
-- The player must die via set_hp within 0.1 seconds, otherwise the message will be discarded.
|
||||
function mcl_death_messages.player_damage(player, message)
|
||||
last_damages[player:get_player_name()] = { message = message, sequence_number = dmg_sequence_number }
|
||||
start_damage_reset_countdown(player, dmg_sequence_number)
|
||||
dmg_sequence_number = dmg_sequence_number + 1
|
||||
if dmg_sequence_number >= 65535 then
|
||||
dmg_sequence_number = 0
|
||||
minetest.register_globalstep(function(dtime)
|
||||
local new_assist = {}
|
||||
|
||||
for obj, tbl in pairs(mcl_death_messages.assist) do
|
||||
tbl.timeout = tbl.timeout - dtime
|
||||
if (obj:is_player() or obj:get_luaentity()) and tbl.timeout > 0 then
|
||||
new_assist[obj] = tbl
|
||||
end
|
||||
end
|
||||
end)
|
||||
|
@ -1,59 +1,58 @@
|
||||
# textdomain: mcl_death_messages
|
||||
@1 was fatally hit by an arrow.=@1 wurde tödlich von einem Pfeil getroffen.
|
||||
@1 has been killed by an arrow.=@1 wurde von einem Pfeil getötet.
|
||||
@1 was shot by an arrow from @2.=@1 wurde mit einem Pfeil von @2 abgeschossen.
|
||||
@1 was shot by an arrow from a skeleton.=@1 wurde von einem Skelett mit Pfeil und Bogen abgeschossen.
|
||||
@1 was shot by an arrow from a stray.=@1 wurde von einem Eiswanderer mit Pfeil und Bogen abgeschossen.
|
||||
@1 was shot by an arrow from an illusioner.=@1 wurde von einem Illusionisten mit Pfeil und Bogen abgeschossen.
|
||||
@1 was shot by an arrow.=@1 wurde mit einem Pfeil abgeschossen.
|
||||
@1 forgot to breathe.=@1 vergaß, zu atmen.
|
||||
@1 drowned.=@1 ertrank.
|
||||
@1 ran out of oxygen.=@1 ging die Luft aus.
|
||||
@1 was killed by @2.=@1 wurde von @2 getötet.
|
||||
@1 was killed.=@1 wurde getötet.
|
||||
@1 was killed by a mob.=@1 wurde von einem Mob getötet.
|
||||
@1 was burned to death by a blaze's fireball.=@1 wurde von einem Feuerball einer Lohe zu Tode verbrannt.
|
||||
@1 was killed by a fireball from a blaze.=@1 wurde von einem Feuerball einer Lohe getötet.
|
||||
@1 was burned by a fire charge.=@1 wurde von einer Feuerkugel verbrannt.
|
||||
A ghast scared @1 to death.=Ein Ghast hat @1 zu Tode erschrocken.
|
||||
@1 has been fireballed by a ghast.=@1 wurde von einem Ghast mit einer Feuerkugel abgeschossen.
|
||||
@1 fell from a high cliff.=@1 stürzte von einer hohen Klippe.
|
||||
@1 took fatal fall damage.=@1 nahm tödlichen Fallschaden.
|
||||
@1 fell victim to gravity.=@1 fiel der Schwerkraft zum Opfer.
|
||||
@1 died.=@1 starb.
|
||||
@1 was killed by a zombie.=@1 wurde von einem Zombie getötet.
|
||||
@1 was killed by a baby zombie.=@1 wurde von einem Zombiebaby getötet.
|
||||
@1 was killed by a blaze.=@1 wurde von einer Lohe getötet.
|
||||
@1 was killed by a slime.=@1 wurde von einem Schleim getötet.
|
||||
@1 was killed by a witch.=@1 wurde von einer Hexe getötet.
|
||||
@1 was killed by a magma cube.=@1 wurde von einem Magmakubus getötet.
|
||||
@1 was killed by a wolf.=@1 wurde von einem Wolf getötet.
|
||||
@1 was killed by a cat.=@1 wurde von einer Katze getötet.
|
||||
@1 was killed by an ocelot.=@1 wurde von einem Ozelot getötet.
|
||||
@1 was killed by an ender dragon.=@1 wurde von einem Enderdrachen getötet.
|
||||
@1 was killed by a wither.=@1 wurde von einem Wither getötet.
|
||||
@1 was killed by an enderman.=@1 wurde von einem Enderman getötet.
|
||||
@1 was killed by an endermite.=@1 wurde von einer Endermilbe getötet.
|
||||
@1 was killed by a ghast.=@1 wurde von einem Ghast getötet.
|
||||
@1 was killed by an elder guardian.=@1 wurde von einem Großen Wächter getötet.
|
||||
@1 was killed by a guardian.=@1 wurde von einem Wächter getötet.
|
||||
@1 was killed by an iron golem.=@1 wurde von einem Eisengolem getötet.
|
||||
@1 was killed by a polar_bear.=@1 wurde von einem Eisbären getötet.
|
||||
@1 was killed by a killer bunny.=@1 wurde von einem Killerkaninchen getötet.
|
||||
@1 was killed by a shulker.=@1 wurde von einem Schulker getötet.
|
||||
@1 was killed by a silverfish.=@1 wurde von einem Silberfischchen getötet.
|
||||
@1 was killed by a skeleton.=@1 wurde von einem Skelett getötet.
|
||||
@1 was killed by a stray.=@1 wurde von einem Eiswanderer getötet.
|
||||
@1 was killed by a slime.=@1 wurde von einem Schleim getötet.
|
||||
@1 was killed by a spider.=@1 wurde von einer Spinne getötet.
|
||||
@1 was killed by a cave spider.=@1 wurde von einer Höhlenspinne getötet.
|
||||
@1 was killed by a vex.=@1 wurde von einem Plagegeist getötet.
|
||||
@1 was killed by an evoker.=@1 wurde von einem Magier getötet.
|
||||
@1 was killed by an illusioner.=@1 wurde von einem Illusionisten getötet.
|
||||
@1 was killed by a vindicator.=@1 wurde von einem Diener getötet.
|
||||
@1 was killed by a zombie villager.=@1 wurde von einem Dorfbewohnerzombie getötet.
|
||||
@1 was killed by a husk.=@1 wurde von einem Wüstenzombie getötet.
|
||||
@1 was killed by a baby husk.=@1 wurde von einem Wüstenzombiebaby getötet.
|
||||
@1 was killed by a zombie pigman.=@1 wurde von einem Schweinezombie getötet.
|
||||
@1 was killed by a baby zombie pigman.=@1 wurde von einem Schweinezombiebaby getötet.
|
||||
@1 was slain by @2.=
|
||||
@1 went up in flames=@1 ging in Flammen auf
|
||||
@1 walked into fire whilst fighting @2=@1 ist während eines Kampfes mit @2 in ein Feuer gelaufen
|
||||
@1 was struck by lightning=@1 wurde von einem Blitz erschlagen
|
||||
@1 was struck by lightning whilst fighting @2=@1 wurde während eines Kampfes mit @2 von einem Blitz erschlagen
|
||||
@1 burned to death=@1 ist verbrannt
|
||||
@1 was burnt to a crisp whilst fighting @2=@1 ist während eines Kampfes mit @2 verbrannt
|
||||
@1 tried to swim in lava=@1 hat versucht, in Lava zu schwimmen
|
||||
@1 tried to swim in lava to escape @2=@1 hat versucht, in Lava zu schwimmen, um @2 zu entkommen
|
||||
@1 discovered the floor was lava=@1 hat festgestellt, dass der Boden Lava ist
|
||||
@1 walked into danger zone due to @2=@1 ist wegen @2 in eine Gefahrenzone gelaufen
|
||||
@1 suffocated in a wall=@1 ist in einer Mauer erstickt
|
||||
@1 suffocated in a wall whilst fighting @2=@1 ist während eines Kampfes mit @2 in einer Mauer erstickt
|
||||
@1 drowned=@1 ist ertrunken
|
||||
@1 drowned whilst trying to escape @2=@1 ist während dem Versuch, @2 zu entkommen, ertrunken
|
||||
@1 starved to death=@1 ist verhungert
|
||||
@1 starved to death whilst fighting @2=@1 ist während eines Kampfes mit @2 verhungert
|
||||
@1 was pricked to death=@1 wurde zu Tode gestochen
|
||||
@1 walked into a cactus whilst trying to escape @2=@1 ist während dem Versuch, @2 zu entkommen, in einen Kaktus gelaufen
|
||||
@1 hit the ground too hard=@1 ist zu hart auf dem Boden aufgetroffen
|
||||
@1 hit the ground too hard whilst trying to escape @2=@1 ist während dem Versuch, @2 zu entkommen, zu hart auf dem Boden aufgetroffen
|
||||
@1 experienced kinetic energy=@1 hat kinetische Energie erfahren
|
||||
@1 experienced kinetic energy whilst trying to escape @2=@1 hat während dem Versuch, @2 zu entkommen, kinetische Energie erfahren
|
||||
@1 fell out of the world=@1 ist aus der Welt gefallen
|
||||
@1 didn't want to live in the same world as @2=@1 wollte nicht in der gleichen Welt wie @2 leben
|
||||
@1 died=@1 ist gestorben
|
||||
@1 died because of @2=@1 ist wegen @2 gestorben
|
||||
@1 was killed by magic=@1 wurde von Magie getötet
|
||||
@1 was killed by magic whilst trying to escape @2=@1 wurde während dem Versuch, @2 zu entkommen, von Magie getötet
|
||||
@1 was killed by @2 using magic=@1 wurde von @2 mit Magie getötet
|
||||
@1 was killed by @2 using @3=@1 wurde von @2 mit @3 getötet
|
||||
@1 was roasted in dragon breath=@1 wurde in Drachenatem geröstet
|
||||
@1 was roasted in dragon breath by @2=@1 wurde in Drachenatem von @2 geröstet
|
||||
@1 withered away=@1 ist davon gewithert
|
||||
@1 withered away whilst fighting @2=@1 ist während einem Kampf mit @2 davon gewithert
|
||||
@1 was killed by magic=@1 wurde von Magie getötet
|
||||
@1 was shot by a skull from @2=@1 wurde von einem Schädel von @2 erschossen
|
||||
@1 was squashed by a falling anvil=@1 wurde von einem fallenden Amboss erquetscht
|
||||
@1 was squashed by a falling anvil whilst fighting @2=@1 wurde während einem Kampf mit @2 von einem fallenden Amboss erquetscht
|
||||
@1 was squashed by a falling block=@1 wurde von einem fallenden Block erquetscht
|
||||
@1 was squashed by a falling block whilst fighting @2=@1 wurde während einem Kampf mit @2 von einem fallenden Block erquetscht
|
||||
@1 was slain by @2=@1 wurde von @2 erschlagen
|
||||
@1 was slain by @2 using @3=@1 wurde von @2 mit @3 erschlagen
|
||||
@1 was slain by @2=@1 wurde von @2 erschlagen
|
||||
@1 was slain by @2 using @3=@1 wurde von @2 mit @3 erschlagen
|
||||
@1 was shot by @2=@1 wurde von @2 erschossen
|
||||
@1 was shot by @2 using @3=@1 wurde von @2 mit @3 erschossen
|
||||
@1 was fireballed by @2=@1 wurde von @2 gefeuerballt
|
||||
@1 was fireballed by @2 using @3=@1 wurde von @2 mit @3 gefeuerballt
|
||||
@1 was killed trying to hurt @2=@1 ist bei dem Versuch, @2 zu verletzten gestorben
|
||||
@1 was killed by @3 trying to hurt @2=@1 ist bei dem Versuch, @2 zu verletzten, von @3 getötet worden
|
||||
@1 blew up=@1 ist gesprengt worden
|
||||
@1 was blown up by @2=@1 wurde von @2 gesprengt
|
||||
@1 was blown up by @2 using @3=@1 wurde von @2 mit @3 gesprengt
|
||||
@1 was squished too much=@1 war zu gequetscht
|
||||
@1 was squashed by @2=@1 wurde von @2 erquetscht
|
||||
@1 went off with a bang=@1 ging mit einem Knall ab
|
||||
@1 went off with a bang due to a firework fired from @3 by @2=@1 ging mit einem Knall wegen eines Feuerwerks, das mit @3 von @2 gefeuert wurde, ab
|
||||
|
@ -1,59 +1,58 @@
|
||||
# textdomain: mcl_death_messages
|
||||
@1 was fatally hit by an arrow.=
|
||||
@1 has been killed with an arrow.=
|
||||
@1 was shot by an arrow from @2.=
|
||||
@1 was shot by an arrow from a skeleton.=
|
||||
@1 was shot by an arrow from a stray.=
|
||||
@1 was shot by an arrow from an illusioner.=
|
||||
@1 was shot by an arrow.=
|
||||
@1 forgot to breathe.=
|
||||
@1 drowned.=
|
||||
@1 ran out of oxygen.=
|
||||
@1 was killed by @2.=
|
||||
@1 was killed.=
|
||||
@1 was killed by a mob.=
|
||||
@1 was burned to death by a blaze's fireball.=
|
||||
@1 was killed by a fireball from a blaze.=
|
||||
@1 was burned by a fire charge.=
|
||||
A ghast scared @1 to death.=
|
||||
@1 has been fireballed by a ghast.=
|
||||
@1 fell from a high cliff.=
|
||||
@1 took fatal fall damage.=
|
||||
@1 fell victim to gravity.=
|
||||
@1 died.=
|
||||
@1 was killed by a zombie.=
|
||||
@1 was killed by a baby zombie.=
|
||||
@1 was killed by a blaze.=
|
||||
@1 was killed by a slime.=
|
||||
@1 was killed by a witch.=
|
||||
@1 was killed by a magma cube.=
|
||||
@1 was killed by a wolf.=
|
||||
@1 was killed by a cat.=
|
||||
@1 was killed by an ocelot.=
|
||||
@1 was killed by an ender dragon.=
|
||||
@1 was killed by a wither.=
|
||||
@1 was killed by an enderman.=
|
||||
@1 was killed by an endermite.=
|
||||
@1 was killed by a ghast.=
|
||||
@1 was killed by an elder guardian.=
|
||||
@1 was killed by a guardian.=
|
||||
@1 was killed by an iron golem.=
|
||||
@1 was killed by a polar_bear.=
|
||||
@1 was killed by a killer bunny.=
|
||||
@1 was killed by a shulker.=
|
||||
@1 was killed by a silverfish.=
|
||||
@1 was killed by a skeleton.=
|
||||
@1 was killed by a stray.=
|
||||
@1 was killed by a slime.=
|
||||
@1 was killed by a spider.=
|
||||
@1 was killed by a cave spider.=
|
||||
@1 was killed by a vex.=
|
||||
@1 was killed by an evoker.=
|
||||
@1 was killed by an illusioner.=
|
||||
@1 was killed by a vindicator.=
|
||||
@1 was killed by a zombie villager.=
|
||||
@1 was killed by a husk.=
|
||||
@1 was killed by a baby husk.=
|
||||
@1 was killed by a zombie pigman.=
|
||||
@1 was killed by a baby zombie pigman.=
|
||||
@1 was slain by @2.=
|
||||
@1 went up in flames=
|
||||
@1 walked into fire whilst fighting @2=
|
||||
@1 was struck by lightning=
|
||||
@1 was struck by lightning whilst fighting @2=
|
||||
@1 burned to death=
|
||||
@1 was burnt to a crisp whilst fighting @2=
|
||||
@1 tried to swim in lava=
|
||||
@1 tried to swim in lava to escape @2=
|
||||
@1 discovered the floor was lava=
|
||||
@1 walked into danger zone due to @2=
|
||||
@1 suffocated in a wall=
|
||||
@1 suffocated in a wall whilst fighting @2=
|
||||
@1 drowned=
|
||||
@1 drowned whilst trying to escape @2=
|
||||
@1 starved to death=
|
||||
@1 starved to death whilst fighting @2=
|
||||
@1 was pricked to death=
|
||||
@1 walked into a cactus whilst trying to escape @2=
|
||||
@1 hit the ground too hard=
|
||||
@1 hit the ground too hard whilst trying to escape @2=
|
||||
@1 experienced kinetic energy=
|
||||
@1 experienced kinetic energy whilst trying to escape @2=
|
||||
@1 fell out of the world=
|
||||
@1 didn't want to live in the same world as @2=
|
||||
@1 died=
|
||||
@1 died because of @2=
|
||||
@1 was killed by magic=
|
||||
@1 was killed by magic whilst trying to escape @2=
|
||||
@1 was killed by @2 using magic=
|
||||
@1 was killed by @2 using @3=
|
||||
@1 was roasted in dragon breath=
|
||||
@1 was roasted in dragon breath by @2=
|
||||
@1 withered away=
|
||||
@1 withered away whilst fighting @2=
|
||||
@1 was killed by magic=
|
||||
@1 was shot by a skull from @2=
|
||||
@1 was squashed by a falling anvil=
|
||||
@1 was squashed by a falling anvil whilst fighting @2=
|
||||
@1 was squashed by a falling block=
|
||||
@1 was squashed by a falling block whilst fighting @2=
|
||||
@1 was slain by @2=
|
||||
@1 was slain by @2 using @3=
|
||||
@1 was slain by @2=
|
||||
@1 was slain by @2 using @3=
|
||||
@1 was shot by @2=
|
||||
@1 was shot by @2 using @3=
|
||||
@1 was fireballed by @2=
|
||||
@1 was fireballed by @2 using @3=
|
||||
@1 was killed trying to hurt @2=
|
||||
@1 was killed by @3 trying to hurt @2=
|
||||
@1 blew up=
|
||||
@1 was blown up by @2=
|
||||
@1 was blown up by @2 using @3=
|
||||
@1 was squished too much=
|
||||
@1 was squashed by @2=
|
||||
@1 went off with a bang=
|
||||
@1 went off with a bang due to a firework fired from @3 by @2=
|
||||
|
@ -263,34 +263,7 @@ function mcl_experience.add_experience(player, experience)
|
||||
local can = final_candidates[math.random(#final_candidates)]
|
||||
local stack, list, index, wear = can.stack, can.list, can.index, can.wear
|
||||
local unbreaking_level = mcl_enchanting.get_enchantment(stack, "unbreaking")
|
||||
local uses
|
||||
local armor_uses = minetest.get_item_group(stack:get_name(), "mcl_armor_uses")
|
||||
if armor_uses > 0 then
|
||||
uses = armor_uses
|
||||
if unbreaking_level > 0 then
|
||||
uses = uses / (0.6 + 0.4 / (unbreaking_level + 1))
|
||||
end
|
||||
else
|
||||
local def = stack:get_definition()
|
||||
if def then
|
||||
local fixed_uses = def._mcl_uses
|
||||
if fixed_uses then
|
||||
uses = fixed_uses
|
||||
if unbreaking_level > 0 then
|
||||
uses = uses * (unbreaking_level + 1)
|
||||
end
|
||||
end
|
||||
end
|
||||
if not uses then
|
||||
local toolcaps = stack:get_tool_capabilities()
|
||||
local groupcaps = toolcaps.groupcaps
|
||||
for _, v in pairs(groupcaps) do
|
||||
uses = v.uses
|
||||
break
|
||||
end
|
||||
end
|
||||
end
|
||||
uses = uses or 0
|
||||
local uses = mcl_util.calculate_durability(itemstack)
|
||||
local multiplier = 2 * 65535 / uses
|
||||
local repair = experience * multiplier
|
||||
local new_wear = wear - repair
|
||||
|
@ -1,9 +1,5 @@
|
||||
local S = minetest.get_translator("mcl_hbarmor")
|
||||
|
||||
if (not armor) or (not armor.def) then
|
||||
minetest.log("error", "[mcl_hbarmor] Outdated mcl_armor version. Please update your version of mcl_armor!")
|
||||
end
|
||||
|
||||
local mcl_hbarmor = {}
|
||||
|
||||
-- HUD statbar values
|
||||
@ -60,11 +56,8 @@ end
|
||||
hb.register_hudbar("armor", 0xFFFFFF, S("Armor"), { icon = "hbarmor_icon.png", bgicon = "hbarmor_bgicon.png", bar = "hbarmor_bar.png" }, 0, 0, 20, mcl_hbarmor.autohide)
|
||||
|
||||
function mcl_hbarmor.get_armor(player)
|
||||
if not player or not armor.def then
|
||||
return false
|
||||
end
|
||||
local name = player:get_player_name()
|
||||
local pts = armor:get_armor_points(player)
|
||||
local pts = player:get_meta():get_int("mcl_armor:armor_points")
|
||||
if not pts then
|
||||
return false
|
||||
else
|
||||
|
@ -7,7 +7,6 @@ local players = {}
|
||||
-- Containing all the items for each Creative Mode tab
|
||||
local inventory_lists = {}
|
||||
|
||||
local show_armor = minetest.get_modpath("mcl_armor") ~= nil
|
||||
local mod_player = minetest.get_modpath("mcl_player") ~= nil
|
||||
|
||||
-- Create tables
|
||||
@ -334,23 +333,7 @@ mcl_inventory.set_creative_formspec = function(player, start_i, pagenum, inv_siz
|
||||
if minetest.settings:get_bool("3d_player_preview", true) then
|
||||
player_preview = mcl_player.get_player_formspec_model(player, 3.9, 1.4, 1.2333, 2.4666, "")
|
||||
else
|
||||
local img, img_player
|
||||
if mod_player then
|
||||
img_player = mcl_player.player_get_preview(player)
|
||||
else
|
||||
img_player = "player.png"
|
||||
end
|
||||
img = img_player
|
||||
player_preview = "image[3.9,1.4;1.2333,2.4666;"..img.."]"
|
||||
if show_armor and armor.textures[playername] and armor.textures[playername].preview then
|
||||
img = armor.textures[playername].preview
|
||||
local s1 = img:find("character_preview")
|
||||
if s1 ~= nil then
|
||||
s1 = img:sub(s1+21)
|
||||
img = img_player..s1
|
||||
end
|
||||
player_preview = "image[3.9,1.4;1.2333,2.4666;"..img.."]"
|
||||
end
|
||||
player_preview = "image[3.9,1.4;1.2333,2.4666;"..mcl_player.player_get_preview(player).."]"
|
||||
end
|
||||
|
||||
-- Background images for armor slots (hide if occupied)
|
||||
@ -373,10 +356,10 @@ mcl_inventory.set_creative_formspec = function(player, start_i, pagenum, inv_siz
|
||||
main_list = "list[current_player;main;0,3.75;9,3;9]"..
|
||||
mcl_formspec.get_itemslot_bg(0,3.75,9,3)..
|
||||
-- armor
|
||||
"list[detached:"..playername.."_armor;armor;2.5,1.3;1,1;1]"..
|
||||
"list[detached:"..playername.."_armor;armor;2.5,2.75;1,1;2]"..
|
||||
"list[detached:"..playername.."_armor;armor;5.5,1.3;1,1;3]"..
|
||||
"list[detached:"..playername.."_armor;armor;5.5,2.75;1,1;4]"..
|
||||
"list[current_player;armor;2.5,1.3;1,1;1]"..
|
||||
"list[current_player;armor;2.5,2.75;1,1;2]"..
|
||||
"list[current_player;armor;5.5,1.3;1,1;3]"..
|
||||
"list[current_player;armor;5.5,2.75;1,1;4]"..
|
||||
mcl_formspec.get_itemslot_bg(2.5,1.3,1,1)..
|
||||
mcl_formspec.get_itemslot_bg(2.5,2.75,1,1)..
|
||||
mcl_formspec.get_itemslot_bg(5.5,1.3,1,1)..
|
||||
|
@ -3,7 +3,6 @@ local F = minetest.formspec_escape
|
||||
|
||||
mcl_inventory = {}
|
||||
|
||||
local show_armor = minetest.get_modpath("mcl_armor") ~= nil
|
||||
local mod_player = minetest.get_modpath("mcl_player") ~= nil
|
||||
local mod_craftguide = minetest.get_modpath("mcl_craftguide") ~= nil
|
||||
|
||||
@ -68,23 +67,7 @@ local function set_inventory(player, armor_change_only)
|
||||
if minetest.settings:get_bool("3d_player_preview", true) then
|
||||
player_preview = mcl_player.get_player_formspec_model(player, 1.0, 0.0, 2.25, 4.5, "")
|
||||
else
|
||||
local img, img_player
|
||||
if mod_player then
|
||||
img_player = mcl_player.player_get_preview(player)
|
||||
else
|
||||
img_player = "player.png"
|
||||
end
|
||||
img = img_player
|
||||
player_preview = "image[0.6,0.2;2,4;"..img.."]"
|
||||
if show_armor and armor.textures[player_name] and armor.textures[player_name].preview then
|
||||
img = armor.textures[player_name].preview
|
||||
local s1 = img:find("character_preview")
|
||||
if s1 ~= nil then
|
||||
s1 = img:sub(s1+21)
|
||||
img = img_player..s1
|
||||
end
|
||||
player_preview = "image[1.1,0.2;2,4;"..img.."]"
|
||||
end
|
||||
player_preview = "image[1.1,0.2;2,4;"..mcl_player.player_get_preview(player).."]"
|
||||
end
|
||||
|
||||
local armor_slots = {"helmet", "chestplate", "leggings", "boots"}
|
||||
@ -99,10 +82,10 @@ local function set_inventory(player, armor_change_only)
|
||||
"background[-0.19,-0.25;9.41,9.49;crafting_formspec_bg.png]"..
|
||||
player_preview..
|
||||
--armor
|
||||
"list[detached:"..player_name.."_armor;armor;0,0;1,1;1]"..
|
||||
"list[detached:"..player_name.."_armor;armor;0,1;1,1;2]"..
|
||||
"list[detached:"..player_name.."_armor;armor;0,2;1,1;3]"..
|
||||
"list[detached:"..player_name.."_armor;armor;0,3;1,1;4]"..
|
||||
"list[current_player;armor;0,0;1,1;1]"..
|
||||
"list[current_player;armor;0,1;1,1;2]"..
|
||||
"list[current_player;armor;0,2;1,1;3]"..
|
||||
"list[current_player;armor;0,3;1,1;4]"..
|
||||
mcl_formspec.get_itemslot_bg(0,0,1,1)..
|
||||
mcl_formspec.get_itemslot_bg(0,1,1,1)..
|
||||
mcl_formspec.get_itemslot_bg(0,2,1,1)..
|
||||
@ -133,10 +116,10 @@ local function set_inventory(player, armor_change_only)
|
||||
"tooltip[__mcl_achievements;"..F(S("Achievements")).."]"..
|
||||
-- for shortcuts
|
||||
"listring[current_player;main]"..
|
||||
"listring[current_player;craft]"..
|
||||
"listring[current_player;armor]"..
|
||||
"listring[current_player;main]" ..
|
||||
"listring[detached:"..player_name.."_armor;armor]"
|
||||
|
||||
"listring[current_player;craft]" ..
|
||||
"listring[current_player;main]"
|
||||
player:set_inventory_formspec(form)
|
||||
end
|
||||
|
||||
@ -176,19 +159,11 @@ minetest.register_on_joinplayer(function(player)
|
||||
player:hud_set_hotbar_image("mcl_inventory_hotbar.png")
|
||||
player:hud_set_hotbar_selected_image("mcl_inventory_hotbar_selected.png")
|
||||
|
||||
if show_armor then
|
||||
local set_player_armor_original = armor.set_player_armor
|
||||
local update_inventory_original = armor.update_inventory
|
||||
armor.set_player_armor = function(self, player)
|
||||
set_player_armor_original(self, player)
|
||||
end
|
||||
armor.update_inventory = function(self, player)
|
||||
update_inventory_original(self, player)
|
||||
local old_update_player = mcl_armor.update_player
|
||||
mcl_armor.update_player = function(player, info)
|
||||
old_update_player(player, info)
|
||||
set_inventory(player, true)
|
||||
end
|
||||
armor:set_player_armor(player)
|
||||
armor:update_inventory(player)
|
||||
end
|
||||
|
||||
-- In Creative Mode, the initial inventory setup is handled in creative.lua
|
||||
if not minetest.is_creative_enabled(player:get_player_name()) then
|
||||
|
@ -136,94 +136,32 @@ local dispenserdef = {
|
||||
-- Hardcoded dispensions --
|
||||
|
||||
-- Armor, mob heads and pumpkins
|
||||
if igroups.armor_head or igroups.armor_torso or igroups.armor_legs or igroups.armor_feet then
|
||||
local armor_type, armor_slot
|
||||
local armor_dispensed = false
|
||||
if igroups.armor_head then
|
||||
armor_type = "armor_head"
|
||||
armor_slot = 2
|
||||
elseif igroups.armor_torso then
|
||||
armor_type = "armor_torso"
|
||||
armor_slot = 3
|
||||
elseif igroups.armor_legs then
|
||||
armor_type = "armor_legs"
|
||||
armor_slot = 4
|
||||
elseif igroups.armor_feet then
|
||||
armor_type = "armor_feet"
|
||||
armor_slot = 5
|
||||
end
|
||||
|
||||
if igroups.armor then
|
||||
local droppos_below = {x = droppos.x, y = droppos.y - 1, z = droppos.z}
|
||||
local dropnode_below = minetest.get_node(droppos_below)
|
||||
-- Put armor on player or armor stand
|
||||
local standpos
|
||||
if dropnode.name == "mcl_armor_stand:armor_stand" then
|
||||
standpos = droppos
|
||||
elseif dropnode_below.name == "mcl_armor_stand:armor_stand" then
|
||||
standpos = droppos_below
|
||||
end
|
||||
if standpos then
|
||||
local dropmeta = minetest.get_meta(standpos)
|
||||
local dropinv = dropmeta:get_inventory()
|
||||
if dropinv:room_for_item(armor_type, dropitem) then
|
||||
dropinv:add_item(armor_type, dropitem)
|
||||
minetest.registered_nodes["mcl_armor_stand:armor_stand"].on_metadata_inventory_put(standpos)
|
||||
stack:take_item()
|
||||
inv:set_stack("main", stack_id, stack)
|
||||
armor:play_equip_sound(dropitem, nil, standpos)
|
||||
armor_dispensed = true
|
||||
end
|
||||
else
|
||||
-- Put armor on nearby player
|
||||
-- First search for player in front of dispenser (check 2 nodes)
|
||||
local objs1 = minetest.get_objects_inside_radius(droppos, 1)
|
||||
local objs2 = minetest.get_objects_inside_radius(droppos_below, 1)
|
||||
local objs_table = {objs1, objs2}
|
||||
local player
|
||||
for oi=1, #objs_table do
|
||||
local objs_inner = objs_table[oi]
|
||||
for o=1, #objs_inner do
|
||||
--[[ First player in list is the lucky one. The other player get nothing :-(
|
||||
If multiple players are close to the dispenser, it can be a bit
|
||||
-- unpredictable on who gets the armor. ]]
|
||||
if objs_inner[o]:is_player() then
|
||||
player = objs_inner[o]
|
||||
break
|
||||
end
|
||||
end
|
||||
if player then
|
||||
break
|
||||
end
|
||||
end
|
||||
-- If player found, add armor
|
||||
if player then
|
||||
local ainv = minetest.get_inventory({type="detached", name=player:get_player_name().."_armor"})
|
||||
local pinv = player:get_inventory()
|
||||
if ainv:get_stack("armor", armor_slot):is_empty() and pinv:get_stack("armor", armor_slot):is_empty() then
|
||||
ainv:set_stack("armor", armor_slot, dropitem)
|
||||
pinv:set_stack("armor", armor_slot, dropitem)
|
||||
armor:set_player_armor(player)
|
||||
armor:update_inventory(player)
|
||||
armor:play_equip_sound(dropitem, player)
|
||||
|
||||
stack:take_item()
|
||||
inv:set_stack("main", stack_id, stack)
|
||||
armor_dispensed = true
|
||||
for _, objs in ipairs({minetest.get_objects_inside_radius(droppos, 1), minetest.get_objects_inside_radius(droppos_below, 1)}) do
|
||||
for _, obj in ipairs(objs) do
|
||||
stack = mcl_armor.equip(stack, obj)
|
||||
if stack:is_empty() then
|
||||
break
|
||||
end
|
||||
end
|
||||
if stack:is_empty() then
|
||||
break
|
||||
end
|
||||
end
|
||||
|
||||
-- Place head or pumpkin as node, if equipping it as armor has failed
|
||||
if not armor_dispensed then
|
||||
if not stack:is_empty() then
|
||||
if igroups.head or iname == "mcl_farming:pumpkin_face" then
|
||||
if dropnodedef.buildable_to then
|
||||
minetest.set_node(droppos, {name = iname, param2 = node.param2})
|
||||
stack:take_item()
|
||||
inv:set_stack("main", stack_id, stack)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
inv:set_stack("main", stack_id, stack)
|
||||
-- Spawn Egg
|
||||
elseif igroups.spawn_egg then
|
||||
-- Spawn mob
|
||||
|
241
mods/ITEMS/mcl_armor/api.lua
Normal file
241
mods/ITEMS/mcl_armor/api.lua
Normal file
@ -0,0 +1,241 @@
|
||||
function mcl_armor.play_equip_sound(stack, obj, pos, unequip)
|
||||
local def = stack:get_definition()
|
||||
local estr = "equip"
|
||||
if unequip then
|
||||
estr = "unequip"
|
||||
end
|
||||
local snd = def.sounds and def.sounds["_mcl_armor_" .. estr]
|
||||
if not snd then
|
||||
-- Fallback sound
|
||||
snd = { name = "mcl_armor_" .. estr .. "_generic" }
|
||||
end
|
||||
if snd then
|
||||
local dist = 8
|
||||
if pos then
|
||||
dist = 16
|
||||
end
|
||||
minetest.sound_play(snd, {object = obj, pos = pos, gain = 0.5, max_hear_distance = dist}, true)
|
||||
end
|
||||
end
|
||||
|
||||
function mcl_armor.on_equip(itemstack, obj)
|
||||
local def = itemstack:get_definition()
|
||||
mcl_armor.play_equip_sound(itemstack, obj)
|
||||
if def._on_equip then
|
||||
def._on_equip(obj, itemstack)
|
||||
end
|
||||
mcl_armor.update(obj)
|
||||
end
|
||||
|
||||
function mcl_armor.on_unequip(itemstack, obj)
|
||||
local def = itemstack:get_definition()
|
||||
mcl_armor.play_equip_sound(itemstack, obj, nil, true)
|
||||
if def._on_unequip then
|
||||
def._on_unequip(obj, itemstack)
|
||||
end
|
||||
mcl_armor.update(obj)
|
||||
end
|
||||
|
||||
function mcl_armor.equip(itemstack, obj, swap)
|
||||
local def = itemstack:get_definition()
|
||||
|
||||
if not def then
|
||||
return itemstack
|
||||
end
|
||||
|
||||
local inv = mcl_util.get_inventory(obj, true)
|
||||
|
||||
if not inv or inv:get_size("armor") == 0 then
|
||||
return itemstack
|
||||
end
|
||||
|
||||
local element = mcl_armor.elements[def._mcl_armor_element or ""]
|
||||
|
||||
if element then
|
||||
local old_stack = inv:get_stack("armor", element.index)
|
||||
|
||||
if swap or old_stack:is_empty() then
|
||||
local new_stack
|
||||
|
||||
if swap then
|
||||
new_stack = itemstack
|
||||
itemstack = old_stack
|
||||
else
|
||||
new_stack = itemstack:take_item()
|
||||
end
|
||||
|
||||
inv:set_stack("armor", element.index, new_stack)
|
||||
mcl_armor.on_equip(new_stack, obj)
|
||||
end
|
||||
end
|
||||
|
||||
return itemstack
|
||||
end
|
||||
|
||||
function mcl_armor.equip_on_use(itemstack, player, pointed_thing)
|
||||
if not player or not player:is_player() then
|
||||
return itemstack
|
||||
end
|
||||
|
||||
local new_stack = mcl_util.call_on_rightclick(itemstack, player, pointed_thing)
|
||||
if new_stack then
|
||||
return new_stack
|
||||
end
|
||||
|
||||
return mcl_armor.equip(itemstack, player)
|
||||
end
|
||||
|
||||
function mcl_armor.register_set(def)
|
||||
local modname = minetest.get_current_modname()
|
||||
local S = minetest.get_translator(modname)
|
||||
local descriptions = def.descriptions or {}
|
||||
local groups = def.groups or {}
|
||||
for name, element in pairs(mcl_armor.elements) do
|
||||
local itemname = element.name .. "_" .. def.name
|
||||
local itemstring = modname .. ":" .. itemname
|
||||
|
||||
local groups = table.copy(groups)
|
||||
groups["armor_" .. name] = 1
|
||||
groups["combat_armor_" .. name] = 1
|
||||
groups.armor = 1
|
||||
groups.combat_armor = 1
|
||||
groups.mcl_armor_points = def.points[name]
|
||||
groups.mcl_armor_toughness = def.toughness
|
||||
groups.mcl_armor_uses = math.floor(def.durability * element.durability) + 1
|
||||
groups.enchantability = def.enchantability
|
||||
|
||||
minetest.register_tool(itemstring, {
|
||||
description = S(def.description .. " " .. (descriptions[name] or element.description)),
|
||||
_doc_items_longdesc = mcl_armor.longdesc,
|
||||
_doc_items_usagehelp = mcl_armor.usage,
|
||||
inventory_image = modname .. "_inv_" .. itemname .. ".png",
|
||||
_repair_material = def.repair_material or def.craft_material,
|
||||
groups = groups,
|
||||
sounds = {
|
||||
_mcl_armor_equip = def.sound_equip or modname .. "_equip_" .. def.name,
|
||||
_mcl_armor_unequip = def.sound_unequip or modname .. "_unequip_" .. def.name,
|
||||
},
|
||||
on_place = mcl_armor.equip_on_use,
|
||||
on_secondary_use = mcl_armor.equip_on_use,
|
||||
_on_equip = def.on_equip,
|
||||
_on_unequip = def.on_unequip,
|
||||
_mcl_armor_element = name,
|
||||
_mcl_armor_texture = modname .. "_" .. itemname .. ".png",
|
||||
_mcl_armor_preview = modname .. "_" .. itemname .. "_preview.png",
|
||||
})
|
||||
|
||||
if def.craft_material then
|
||||
minetest.register_craft({
|
||||
output = itemstring,
|
||||
recipe = element.craft(def.craft_material),
|
||||
})
|
||||
end
|
||||
|
||||
if def.cook_material then
|
||||
minetest.register_craft({
|
||||
type = "cooking",
|
||||
output = def.cook_material,
|
||||
recipe = itemstring,
|
||||
cooktime = 10,
|
||||
})
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
mcl_armor.protection_enchantments = {
|
||||
flags = {},
|
||||
types = {},
|
||||
wildcard = {},
|
||||
}
|
||||
|
||||
function mcl_armor.register_protection_enchantment(def)
|
||||
local prot_def = {id = def.id, factor = def.factor}
|
||||
if def.damage_flag then
|
||||
local tbl = mcl_armor.protection_enchantments.flags[def.damage_flag] or {}
|
||||
table.insert(tbl, prot_def)
|
||||
mcl_armor.protection_enchantments.flags = tbl
|
||||
elseif def.damage_type then
|
||||
local tbl = mcl_armor.protection_enchantments.types[def.damage_type] or {}
|
||||
table.insert(tbl, prot_def)
|
||||
mcl_armor.protection_enchantments.types = tbl
|
||||
else
|
||||
table.insert(mcl_armor.protection_enchantments.wildcard, prot_def)
|
||||
end
|
||||
mcl_enchanting.enchantments[def.id] = {
|
||||
name = def.name,
|
||||
max_level = def.max_level or 4,
|
||||
primary = def.primary or {combat_armor = true},
|
||||
secondary = {},
|
||||
disallow = {},
|
||||
incompatible = def.incompatible or {},
|
||||
weight = def.weight or 5,
|
||||
description = def.description,
|
||||
curse = false,
|
||||
on_enchant = function() end,
|
||||
requires_tool = false,
|
||||
treasure = def.treasure or false,
|
||||
power_range_table = def.power_range_table,
|
||||
inv_combat_tab = true,
|
||||
inv_tool_tab = false,
|
||||
}
|
||||
end
|
||||
|
||||
function mcl_armor.update(obj)
|
||||
local info = {points = 0, view_range_factors = {}}
|
||||
|
||||
local inv = mcl_util.get_inventory(obj)
|
||||
|
||||
if inv then
|
||||
for i = 2, 5 do
|
||||
local itemstack = inv:get_stack("armor", i)
|
||||
|
||||
local itemname = itemstack:get_name()
|
||||
if minetest.registered_aliases[itemname] then
|
||||
itemname = minetest.registered_aliases[itemname]
|
||||
end
|
||||
|
||||
if not itemstack:is_empty() then
|
||||
local def = itemstack:get_definition()
|
||||
|
||||
if def._mcl_armor_texture then
|
||||
info.texture = "(" .. def._mcl_armor_texture .. ")" .. (info.texture and "^" .. info.texture or "")
|
||||
end
|
||||
|
||||
if obj:is_player() and def._mcl_armor_preview then
|
||||
info.preview = "(player.png^[opacity:0^" .. def._mcl_armor_preview .. ")" .. (info.preview and "^" .. info.preview or "" )
|
||||
end
|
||||
|
||||
info.points = info.points + minetest.get_item_group(itemname, "mcl_armor_points")
|
||||
|
||||
local mob_range_mob = def._mcl_armor_mob_range_mob
|
||||
|
||||
if mob_range_mob then
|
||||
local factor = info.view_range_factors[mob_range_mob]
|
||||
|
||||
if factor then
|
||||
if factor > 0 then
|
||||
info.view_range_factors[mob_range_mob] = factor * def._mcl_armor_mob_range_factor
|
||||
end
|
||||
else
|
||||
info.view_range_factors[mob_range_mob] = def._mcl_armor_mob_range_factor
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
info.texture = info.texture or "blank.png"
|
||||
|
||||
if obj:is_player() then
|
||||
info.preview = info.preview or "blank.png"
|
||||
|
||||
mcl_armor.update_player(obj, info)
|
||||
else
|
||||
local luaentity = obj:get_luaentity()
|
||||
|
||||
if luaentity.update_armor then
|
||||
luaentity:update_armor(info)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
@ -1,675 +0,0 @@
|
||||
local ARMOR_INIT_DELAY = 1
|
||||
local ARMOR_INIT_TIMES = 1
|
||||
local ARMOR_BONES_DELAY = 1
|
||||
|
||||
local skin_mod = nil
|
||||
|
||||
local modpath = minetest.get_modpath(minetest.get_current_modname())
|
||||
|
||||
armor = {
|
||||
timer = 0,
|
||||
elements = {"head", "torso", "legs", "feet"},
|
||||
physics = {"jump","speed","gravity"},
|
||||
formspec = "size[8,8.5]image[2,0.75;2,4;armor_preview]"
|
||||
.."list[current_player;main;0,4.5;8,4;]"
|
||||
.."list[current_player;craft;4,1;3,3;]"
|
||||
.."list[current_player;craftpreview;7,2;1,1;]"
|
||||
.."listring[current_player;main]"
|
||||
.."listring[current_player;craft]",
|
||||
textures = {},
|
||||
default_skin = "character",
|
||||
last_damage_types = {},
|
||||
}
|
||||
|
||||
if minetest.get_modpath("mcl_skins") then
|
||||
skin_mod = "mcl_skins"
|
||||
elseif minetest.get_modpath("skins") then
|
||||
skin_mod = "skins"
|
||||
elseif minetest.get_modpath("simple_skins") then
|
||||
skin_mod = "simple_skins"
|
||||
elseif minetest.get_modpath("u_skins") then
|
||||
skin_mod = "u_skins"
|
||||
elseif minetest.get_modpath("wardrobe") then
|
||||
skin_mod = "wardrobe"
|
||||
end
|
||||
|
||||
function armor.on_armor_use(itemstack, user, pointed_thing)
|
||||
if not user or user:is_player() == false then
|
||||
return itemstack
|
||||
end
|
||||
|
||||
-- Call on_rightclick if the pointed node defines it
|
||||
if pointed_thing.type == "node" then
|
||||
local node = minetest.get_node(pointed_thing.under)
|
||||
if user and not user:get_player_control().sneak then
|
||||
if minetest.registered_nodes[node.name] and minetest.registered_nodes[node.name].on_rightclick then
|
||||
return minetest.registered_nodes[node.name].on_rightclick(pointed_thing.under, node, user, itemstack) or itemstack
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
local name, player_inv, armor_inv = armor:get_valid_player(user, "[on_armor_use]")
|
||||
if not name then
|
||||
return itemstack
|
||||
end
|
||||
|
||||
local def = itemstack:get_definition()
|
||||
local slot
|
||||
if def.groups and def.groups.armor_head then
|
||||
slot = 2
|
||||
elseif def.groups and def.groups.armor_torso then
|
||||
slot = 3
|
||||
elseif def.groups and def.groups.armor_legs then
|
||||
slot = 4
|
||||
elseif def.groups and def.groups.armor_feet then
|
||||
slot = 5
|
||||
end
|
||||
|
||||
if slot then
|
||||
local itemstack_single = ItemStack(itemstack)
|
||||
itemstack_single:set_count(1)
|
||||
local itemstack_slot = armor_inv:get_stack("armor", slot)
|
||||
if itemstack_slot:is_empty() then
|
||||
armor_inv:set_stack("armor", slot, itemstack_single)
|
||||
player_inv:set_stack("armor", slot, itemstack_single)
|
||||
armor:set_player_armor(user)
|
||||
armor:update_inventory(user)
|
||||
armor:play_equip_sound(itemstack_single, user)
|
||||
itemstack:take_item()
|
||||
elseif itemstack:get_count() <= 1 and not mcl_enchanting.has_enchantment(itemstack_slot, "curse_of_binding") then
|
||||
armor_inv:set_stack("armor", slot, itemstack_single)
|
||||
player_inv:set_stack("armor", slot, itemstack_single)
|
||||
armor:set_player_armor(user)
|
||||
armor:update_inventory(user)
|
||||
armor:play_equip_sound(itemstack_single, user)
|
||||
itemstack = ItemStack(itemstack_slot)
|
||||
end
|
||||
end
|
||||
|
||||
return itemstack
|
||||
end
|
||||
|
||||
armor.def = {
|
||||
count = 0,
|
||||
}
|
||||
|
||||
armor.update_player_visuals = function(self, player)
|
||||
if not player then
|
||||
return
|
||||
end
|
||||
|
||||
local wielditem = player:get_wielded_item()
|
||||
local def = wielditem:get_definition()
|
||||
if def and def._mcl_toollike_wield then
|
||||
player:set_bone_position("Wield_Item", vector.new(0,3.9,1.3), vector.new(90,0,0))
|
||||
elseif string.find(wielditem:get_name(), "mcl_bows:bow") then
|
||||
player:set_bone_position("Wield_Item", vector.new(.5,4.5,-1.6), vector.new(90,0,20))
|
||||
else
|
||||
player:set_bone_position("Wield_Item", vector.new(-1.5,4.9,1.8), vector.new(135,0,90))
|
||||
end
|
||||
|
||||
local name = player:get_player_name()
|
||||
if self.textures[name] then
|
||||
mcl_player.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 = armor:get_valid_player(player, "[set_player_armor]")
|
||||
if not name then
|
||||
return
|
||||
end
|
||||
local armor_texture = "blank.png"
|
||||
local armor_level = 0
|
||||
local mcl_armor_points = 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
|
||||
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 minetest.registered_aliases[item] then
|
||||
item = minetest.registered_aliases[item]
|
||||
end
|
||||
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("%:", "_")
|
||||
local enchanted_addition = (mcl_enchanting.is_enchanted(item) and mcl_enchanting.overlay or "")
|
||||
table.insert(textures, "("..texture..".png"..enchanted_addition..")")
|
||||
preview = "(player.png^[opacity:0^"..texture.."_preview.png"..enchanted_addition..")"..(preview and "^"..preview or "")
|
||||
armor_level = armor_level + level
|
||||
items = items + 1
|
||||
mcl_armor_points = mcl_armor_points + (def.groups["mcl_armor_points"] 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
|
||||
preview = (armor:get_preview(name) or "character_preview.png")..(preview and "^"..preview or "")
|
||||
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
|
||||
if #textures > 0 then
|
||||
armor_texture = table.concat(textures, "^")
|
||||
end
|
||||
local armor_groups = player:get_armor_groups()
|
||||
armor_groups.fleshy = 100
|
||||
armor_groups.level = nil
|
||||
if armor_level > 0 then
|
||||
armor_groups.level = math.floor(armor_level / 20)
|
||||
armor_groups.fleshy = 100 - armor_level
|
||||
end
|
||||
player:set_armor_groups(armor_groups)
|
||||
-- Physics override intentionally removed because of possible conflicts
|
||||
self.textures[name].armor = armor_texture
|
||||
self.textures[name].preview = preview
|
||||
self.def[name].count = items
|
||||
self.def[name].level = armor_level
|
||||
self.def[name].heal = mcl_armor_points
|
||||
self.def[name].jump = physics_o.jump
|
||||
self.def[name].speed = physics_o.speed
|
||||
self.def[name].gravity = physics_o.gravity
|
||||
self:update_player_visuals(player)
|
||||
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
|
||||
|
||||
armor.get_armor_points = function(self, player)
|
||||
local name, player_inv, armor_inv = armor:get_valid_player(player, "[get_armor_points]")
|
||||
if not name then
|
||||
return nil
|
||||
end
|
||||
local pts = 0
|
||||
for i=1, 6 do
|
||||
local stack = player_inv:get_stack("armor", i)
|
||||
if stack:get_count() > 0 then
|
||||
local p = minetest.get_item_group(stack:get_name(), "mcl_armor_points")
|
||||
if p then
|
||||
pts = pts + p
|
||||
end
|
||||
end
|
||||
end
|
||||
return pts
|
||||
end
|
||||
|
||||
-- Returns a change factor for a mob's view_range for the given player
|
||||
-- or nil, if there's no change. Certain armors (like mob heads) can
|
||||
-- affect the view range of mobs.
|
||||
armor.get_mob_view_range_factor = function(self, player, mob)
|
||||
local name, player_inv, armor_inv = armor:get_valid_player(player, "[get_mob_view_range_factor]")
|
||||
if not name then
|
||||
return
|
||||
end
|
||||
local factor
|
||||
for i=1, 6 do
|
||||
local stack = player_inv:get_stack("armor", i)
|
||||
if stack:get_count() > 0 then
|
||||
local def = stack:get_definition()
|
||||
if def._mcl_armor_mob_range_mob == mob then
|
||||
if not factor then
|
||||
factor = def._mcl_armor_mob_range_factor
|
||||
elseif factor == 0 then
|
||||
return 0
|
||||
else
|
||||
factor = factor * def._mcl_armor_mob_range_factor
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
return factor
|
||||
end
|
||||
|
||||
armor.get_player_skin = function(self, name)
|
||||
local skin = nil
|
||||
if skin_mod == "mcl_skins" then
|
||||
skin = mcl_skins.skins[name]
|
||||
elseif 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
|
||||
end
|
||||
|
||||
armor.get_preview = function(self, name)
|
||||
if skin_mod == "skins" then
|
||||
return armor:get_player_skin(name).."_preview.png"
|
||||
end
|
||||
end
|
||||
|
||||
armor.get_armor_formspec = function(self, name)
|
||||
if not armor.textures[name] then
|
||||
minetest.log("error", "mcl_armor: Player texture["..name.."] is nil [get_armor_formspec]")
|
||||
return ""
|
||||
end
|
||||
if not armor.def[name] then
|
||||
minetest.log("error", "mcl_armor: Armor def["..name.."] is nil [get_armor_formspec]")
|
||||
return ""
|
||||
end
|
||||
local formspec = armor.formspec.."list[detached:"..name.."_armor;armor;0,1;2,3;]"
|
||||
formspec = formspec:gsub("armor_preview", armor.textures[name].preview)
|
||||
formspec = formspec:gsub("armor_level", armor.def[name].level)
|
||||
formspec = formspec:gsub("mcl_armor_points", armor.def[name].heal)
|
||||
return formspec
|
||||
end
|
||||
|
||||
armor.update_inventory = function(self, player)
|
||||
end
|
||||
|
||||
armor.get_valid_player = function(self, player, msg)
|
||||
msg = msg or ""
|
||||
if not player then
|
||||
minetest.log("error", "mcl_armor: Player reference is nil "..msg)
|
||||
return
|
||||
end
|
||||
local name = player:get_player_name()
|
||||
if not name then
|
||||
minetest.log("error", "mcl_armor: Player name is nil "..msg)
|
||||
return
|
||||
end
|
||||
local pos = player:get_pos()
|
||||
local player_inv = player:get_inventory()
|
||||
local armor_inv = minetest.get_inventory({type="detached", name=name.."_armor"})
|
||||
if not pos then
|
||||
minetest.log("error", "mcl_armor: Player position is nil "..msg)
|
||||
return
|
||||
elseif not player_inv then
|
||||
minetest.log("error", "mcl_armor: Player inventory is nil "..msg)
|
||||
return
|
||||
elseif not armor_inv then
|
||||
minetest.log("error", "mcl_armor: Detached armor inventory is nil "..msg)
|
||||
return
|
||||
end
|
||||
return name, player_inv, armor_inv, pos
|
||||
end
|
||||
|
||||
armor.play_equip_sound = function(self, stack, player, pos, unequip)
|
||||
local def = stack:get_definition()
|
||||
local estr = "equip"
|
||||
if unequip then
|
||||
estr = "unequip"
|
||||
end
|
||||
local snd = def.sounds and def.sounds["_mcl_armor_"..estr]
|
||||
if not snd then
|
||||
-- Fallback sound
|
||||
snd = { name = "mcl_armor_"..estr.."_generic" }
|
||||
end
|
||||
if snd then
|
||||
local dist = 8
|
||||
if pos then
|
||||
dist = 16
|
||||
end
|
||||
minetest.sound_play(snd, {object=player, pos=pos, gain=0.5, max_hear_distance=dist}, true)
|
||||
end
|
||||
end
|
||||
|
||||
-- Register Player Model
|
||||
|
||||
mcl_player.player_register_model("mcl_armor_character.b3d", {
|
||||
animation_speed = 30,
|
||||
textures = {
|
||||
armor.default_skin..".png",
|
||||
"blank.png",
|
||||
"blank.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},
|
||||
sneak_stand = {x=222, y=302},
|
||||
sneak_mine = {x=346, y=365},
|
||||
sneak_walk = {x=304, y=323},
|
||||
sneak_walk_mine = {x=325, y=344},
|
||||
swim_walk = {x=368, y=387},
|
||||
swim_walk_mine = {x=389, y=408},
|
||||
swim_stand = {x=434, y=434},
|
||||
swim_mine = {x=411, y=430},
|
||||
run_walk = {x=440, y=459},
|
||||
run_walk_mine = {x=461, y=480},
|
||||
sit_mount = {x=484, y=484},
|
||||
die = {x=498, y=498},
|
||||
fly = {x=502, y=581},
|
||||
},
|
||||
})
|
||||
|
||||
mcl_player.player_register_model("mcl_armor_character_female.b3d", {
|
||||
animation_speed = 30,
|
||||
textures = {
|
||||
armor.default_skin..".png",
|
||||
"blank.png",
|
||||
"blank.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},
|
||||
sneak_stand = {x=222, y=302},
|
||||
sneak_mine = {x=346, y=365},
|
||||
sneak_walk = {x=304, y=323},
|
||||
sneak_walk_mine = {x=325, y=344},
|
||||
swim_walk = {x=368, y=387},
|
||||
swim_walk_mine = {x=389, y=408},
|
||||
swim_stand = {x=434, y=434},
|
||||
swim_mine = {x=411, y=430},
|
||||
run_walk = {x=440, y=459},
|
||||
run_walk_mine = {x=461, y=480},
|
||||
sit_mount = {x=484, y=484},
|
||||
die = {x=498, y=498},
|
||||
fly = {x=502, y=581},
|
||||
},
|
||||
})
|
||||
|
||||
-- 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 then
|
||||
return
|
||||
end
|
||||
if fields.armor then
|
||||
return
|
||||
end
|
||||
for field, _ in pairs(fields) do
|
||||
if string.find(field, "skins_set") then
|
||||
minetest.after(0, function(name)
|
||||
local player = minetest.get_player_by_name(name)
|
||||
if not player then
|
||||
return
|
||||
end
|
||||
local skin = armor:get_player_skin(name)
|
||||
armor.textures[name].skin = skin..".png"
|
||||
armor:set_player_armor(player)
|
||||
end, player:get_player_name())
|
||||
end
|
||||
end
|
||||
end)
|
||||
|
||||
minetest.register_on_joinplayer(function(player)
|
||||
mcl_player.player_set_model(player, "mcl_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)
|
||||
armor:play_equip_sound(stack, 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)
|
||||
armor:play_equip_sound(stack, player, nil, true)
|
||||
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)
|
||||
armor:play_equip_sound(stack, player)
|
||||
end,
|
||||
allow_put = function(inv, listname, index, stack, player)
|
||||
local iname = stack:get_name()
|
||||
local g
|
||||
local groupcheck
|
||||
if index == 2 then
|
||||
g = minetest.get_item_group(iname, "armor_head")
|
||||
elseif index == 3 then
|
||||
g = minetest.get_item_group(iname, "armor_torso")
|
||||
elseif index == 4 then
|
||||
g = minetest.get_item_group(iname, "armor_legs")
|
||||
elseif index == 5 then
|
||||
g = minetest.get_item_group(iname, "armor_feet")
|
||||
end
|
||||
-- Minor FIXME: If player attempts to place stack into occupied slot, this is rejected.
|
||||
-- It would be better if 1 item is placed in exchanged for the item in the slot.
|
||||
if g ~= 0 and g ~= nil and (inv:get_stack(listname, index):is_empty() or (inv:get_stack(listname, index):get_name() ~= stack:get_name()) and stack:get_count() <= 1) then
|
||||
return 1
|
||||
else
|
||||
return 0
|
||||
end
|
||||
end,
|
||||
allow_take = function(inv, listname, index, stack, player)
|
||||
if mcl_enchanting.has_enchantment(stack, "curse_of_binding") and not minetest.settings:get_bool("creative") then
|
||||
return 0
|
||||
end
|
||||
return stack:get_count()
|
||||
end,
|
||||
allow_move = function(inv, from_list, from_index, to_list, to_index, count, player)
|
||||
return 0
|
||||
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)
|
||||
end
|
||||
armor.def[name] = {
|
||||
count = 0,
|
||||
level = 0,
|
||||
heal = 0,
|
||||
jump = 1,
|
||||
speed = 1,
|
||||
gravity = 1,
|
||||
}
|
||||
armor.textures[name] = {
|
||||
skin = armor.default_skin..".png",
|
||||
armor = "blank.png",
|
||||
wielditem = "blank.png",
|
||||
preview = armor.default_skin.."_preview.png",
|
||||
}
|
||||
if skin_mod == "mcl_skins" then
|
||||
local skin = mcl_skins.skins[name]
|
||||
if skin then
|
||||
armor.textures[name].skin = skin..".png"
|
||||
end
|
||||
elseif 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
|
||||
if minetest.get_modpath("player_textures") then
|
||||
local filename = minetest.get_modpath("player_textures").."/textures/player_"..name
|
||||
local f = io.open(filename..".png")
|
||||
if f then
|
||||
f:close()
|
||||
armor.textures[name].skin = "player_"..name..".png"
|
||||
end
|
||||
end
|
||||
for i=1, ARMOR_INIT_TIMES do
|
||||
minetest.after(ARMOR_INIT_DELAY * i, function(name)
|
||||
local player = minetest.get_player_by_name(name)
|
||||
if not player then
|
||||
return
|
||||
end
|
||||
armor:set_player_armor(player)
|
||||
end, player:get_player_name())
|
||||
end
|
||||
end)
|
||||
|
||||
minetest.register_on_player_hpchange(function(player, hp_change, reason)
|
||||
local name, player_inv, armor_inv = armor:get_valid_player(player, "[on_hpchange]")
|
||||
if name and hp_change < 0 then
|
||||
local damage_type = armor.last_damage_types[name]
|
||||
armor.last_damage_types[name] = nil
|
||||
|
||||
-- Armor doesn't protect from set_hp (commands like /kill),
|
||||
if reason.type == "set_hp" then
|
||||
return hp_change
|
||||
end
|
||||
|
||||
local regular_reduction = reason.type ~= "drown" and reason.type ~= "fall" and reason.other ~= "harming" and reason.other ~= "poison"
|
||||
|
||||
local heal_max = 0
|
||||
local items = 0
|
||||
local armor_damage = math.max(1, math.floor(math.abs(hp_change)/4))
|
||||
|
||||
local total_points = 0
|
||||
local total_toughness = 0
|
||||
local epf = 0
|
||||
local thorns_damage = 0
|
||||
local thorns_damage_regular = 0
|
||||
for i=1, 6 do
|
||||
local stack = player_inv:get_stack("armor", i)
|
||||
if stack:get_count() > 0 then
|
||||
local enchantments = mcl_enchanting.get_enchantments(stack)
|
||||
local pts = stack:get_definition().groups["mcl_armor_points"] or 0
|
||||
local tough = stack:get_definition().groups["mcl_armor_toughness"] or 0
|
||||
total_points = total_points + pts
|
||||
total_toughness = total_toughness + tough
|
||||
|
||||
local protection_level = enchantments.protection or 0
|
||||
if protection_level > 0 then
|
||||
epf = epf + protection_level * 1
|
||||
end
|
||||
local blast_protection_level = enchantments.blast_protection or 0
|
||||
if blast_protection_level > 0 and damage_type == "explosion" then
|
||||
epf = epf + blast_protection_level * 2
|
||||
end
|
||||
local fire_protection_level = enchantments.fire_protection or 0
|
||||
if fire_protection_level > 0 and (damage_type == "burning" or damage_type == "fireball" or reason.type == "node_damage" and
|
||||
(reason.node == "mcl_fire:fire" or reason.node == "mcl_core:lava_source" or reason.node == "mcl_core:lava_flowing")) then
|
||||
epf = epf + fire_protection_level * 2
|
||||
end
|
||||
local projectile_protection_level = enchantments.projectile_protection or 0
|
||||
if projectile_protection_level and (damage_type == "projectile" or damage_type == "fireball") then
|
||||
epf = epf + projectile_protection_level * 2
|
||||
end
|
||||
local feather_falling_level = enchantments.feather_falling or 0
|
||||
if feather_falling_level and reason.type == "fall" then
|
||||
epf = epf + feather_falling_level * 3
|
||||
end
|
||||
|
||||
local did_thorns_damage = false
|
||||
local thorns_level = enchantments.thorns or 0
|
||||
if thorns_level then
|
||||
if thorns_level > 10 then
|
||||
thorns_damage = thorns_damage + thorns_level - 10
|
||||
did_thorns_damage = true
|
||||
elseif thorns_damage_regular < 4 and thorns_level * 0.15 > math.random() then
|
||||
local thorns_damage_regular_new = math.min(4, thorns_damage_regular + math.random(4))
|
||||
thorns_damage = thorns_damage + thorns_damage_regular_new - thorns_damage_regular
|
||||
thorns_damage_regular = thorns_damage_regular_new
|
||||
did_thorns_damage = true
|
||||
end
|
||||
end
|
||||
|
||||
-- Damage armor
|
||||
local use = stack:get_definition().groups["mcl_armor_uses"] or 0
|
||||
if use > 0 and regular_reduction then
|
||||
local unbreaking_level = enchantments.unbreaking or 0
|
||||
if unbreaking_level > 0 then
|
||||
use = use / (0.6 + 0.4 / (unbreaking_level + 1))
|
||||
end
|
||||
local wear = armor_damage * math.floor(65536/use)
|
||||
if did_thorns_damage then
|
||||
wear = wear * 3
|
||||
end
|
||||
stack:add_wear(wear)
|
||||
end
|
||||
|
||||
local item = stack:get_name()
|
||||
armor_inv:set_stack("armor", i, stack)
|
||||
player_inv:set_stack("armor", i, stack)
|
||||
items = items + 1
|
||||
if stack:get_count() == 0 then
|
||||
armor:set_player_armor(player)
|
||||
armor:update_inventory(player)
|
||||
end
|
||||
end
|
||||
end
|
||||
local damage = math.abs(hp_change)
|
||||
|
||||
if regular_reduction then
|
||||
-- Damage calculation formula (from <https://minecraft.gamepedia.com/Armor#Damage_protection>)
|
||||
damage = damage * (1 - math.min(20, math.max((total_points/5), total_points - damage / (2+(total_toughness/4)))) / 25)
|
||||
end
|
||||
damage = damage * (1 - (math.min(20, epf) / 25))
|
||||
damage = math.floor(damage+0.5)
|
||||
|
||||
if reason.type == "punch" and thorns_damage > 0 then
|
||||
local obj = reason.object
|
||||
if obj then
|
||||
local luaentity = obj:get_luaentity()
|
||||
if luaentity then
|
||||
local shooter = obj._shooter
|
||||
if shooter then
|
||||
obj = shooter
|
||||
end
|
||||
end
|
||||
obj:punch(player, 1.0, {
|
||||
full_punch_interval=1.0,
|
||||
damage_groups = {fleshy = thorns_damage},
|
||||
})
|
||||
end
|
||||
end
|
||||
|
||||
hp_change = -math.abs(damage)
|
||||
|
||||
armor.def[name].count = items
|
||||
armor:update_armor(player)
|
||||
end
|
||||
return hp_change
|
||||
end, true)
|
94
mods/ITEMS/mcl_armor/damage.lua
Normal file
94
mods/ITEMS/mcl_armor/damage.lua
Normal file
@ -0,0 +1,94 @@
|
||||
mcl_damage.register_modifier(function(obj, damage, reason)
|
||||
local flags = reason.flags
|
||||
|
||||
if flags.bypasses_armor and flags.bypasses_magic then
|
||||
return damage
|
||||
end
|
||||
|
||||
local uses = math.max(1, math.floor(damage / 4))
|
||||
|
||||
local points = 0
|
||||
local toughness = 0
|
||||
local enchantment_protection_factor = 0
|
||||
|
||||
local thorns_damage_regular = 0
|
||||
local thorns_damage_irregular = 0
|
||||
local thorns_pieces = {}
|
||||
|
||||
local inv = mcl_util.get_inventory(obj)
|
||||
|
||||
if inv then
|
||||
for name, element in pairs(mcl_armor.elements) do
|
||||
local itemstack = inv:get_stack("armor", element.index)
|
||||
if not itemstack:is_empty() then
|
||||
local itemname = itemstack:get_name()
|
||||
local enchantments = mcl_enchanting.get_enchantments(itemstack)
|
||||
|
||||
if not flags.bypasses_armor then
|
||||
points = points + minetest.get_item_group(itemname, "mcl_armor_points")
|
||||
toughness = toughness + minetest.get_item_group(itemname, "mcl_armor_toughness")
|
||||
|
||||
mcl_util.use_item_durability(itemstack, uses)
|
||||
inv:set_stack("armor", element.index, itemstack)
|
||||
end
|
||||
|
||||
if not flags.bypasses_magic then
|
||||
local function add_enchantments(tbl)
|
||||
if tbl then
|
||||
for _, enchantment in pairs(tbl) do
|
||||
local level = enchantments[enchantment.id]
|
||||
|
||||
if level and level > 0 then
|
||||
enchantment_protection_factor = enchantment_protection_factor + level * enchantment.factor
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
add_enchantments(mcl_armor.protection_enchantments.wildcard)
|
||||
add_enchantments(mcl_armor.protection_enchantments.types[reason.type])
|
||||
|
||||
for flag, value in pairs(flags) do
|
||||
if value then
|
||||
add_enchantments(mcl_armor.protection_enchantments.flags[flag])
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
if reason.source and enchantments.thorns and enchantments.thorns > 0 then
|
||||
local do_irregular_damage = enchantments.thorns > 10
|
||||
|
||||
if do_irregular_damage or thorns_damage_regular < 4 and math.random() < enchantments.thorns * 0.15 then
|
||||
if do_irregular_damage then
|
||||
thorns_damage_irregular = thorns_damage_irregular + throrns_level - 10
|
||||
else
|
||||
thorns_damage_regular = math.min(4, thorns_damage_regular + math.random(4))
|
||||
end
|
||||
end
|
||||
|
||||
table.insert(thorns_pieces, {index = element.index, itemstack = itemstack})
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
-- https://minecraft.gamepedia.com/Armor#Damage_protection
|
||||
damage = damage * (1 - math.min(20, math.max((points / 5), points - damage / (2 + (toughness / 4)))) / 25)
|
||||
|
||||
-- https://minecraft.gamepedia.com/Armor#Enchantments
|
||||
damage = damage * (1 - math.min(20, enchantment_protection_factor) / 25)
|
||||
|
||||
local thorns_damage = thorns_damage_regular + thorns_damage_irregular
|
||||
|
||||
if thorns_damage > 0 and reason.type ~= "thorns" and reason.source ~= obj then
|
||||
mcl_util.deal_damage(reason.source, {type = "thorns", direct = obj})
|
||||
|
||||
local thorns_item = thorns_pieces[math.random(#thorns_pieces)]
|
||||
mcl_util.use_item_durability(thorns_item.itemstack, 2)
|
||||
inv:set_stack("armor", thorns_item.index, thorns_item.itemstack)
|
||||
end
|
||||
|
||||
mcl_armor.update(obj)
|
||||
|
||||
return math.floor(damage + 0.5)
|
||||
end, 0)
|
@ -1,406 +1,68 @@
|
||||
local S = minetest.get_translator("mcl_armor")
|
||||
|
||||
dofile(minetest.get_modpath(minetest.get_current_modname()).."/armor.lua")
|
||||
dofile(minetest.get_modpath(minetest.get_current_modname()).."/alias.lua")
|
||||
|
||||
-- Regisiter Head Armor
|
||||
|
||||
local longdesc = S("This is a piece of equippable armor which reduces the amount of damage you receive.")
|
||||
local usage = S("To equip it, put it on the corresponding armor slot in your inventory menu.")
|
||||
|
||||
minetest.register_tool("mcl_armor:elytra", {
|
||||
description = S("Elytra"),
|
||||
_doc_items_longdesc = longdesc,
|
||||
_doc_items_usagehelp = usage,
|
||||
inventory_image = "mcl_armor_inv_elytra.png",
|
||||
groups = {armor_torso=1, mcl_armor_points=0, mcl_armor_uses=10, enchantability=0},
|
||||
_repair_material = "mcl_mobitems:leather",
|
||||
sounds = {
|
||||
_mcl_armor_equip = "mcl_armor_equip_leather",
|
||||
_mcl_armor_unequip = "mcl_armor_unequip_leather",
|
||||
},
|
||||
on_place = armor.on_armor_use,
|
||||
on_secondary_use = armor.on_armor_use,
|
||||
})
|
||||
|
||||
minetest.register_tool("mcl_armor:helmet_leather", {
|
||||
description = S("Leather Cap"),
|
||||
_doc_items_longdesc = longdesc,
|
||||
_doc_items_usagehelp = usage,
|
||||
inventory_image = "mcl_armor_inv_helmet_leather.png",
|
||||
groups = {armor_head=1, mcl_armor_points=1, mcl_armor_uses=56, enchantability=15},
|
||||
_repair_material = "mcl_mobitems:leather",
|
||||
sounds = {
|
||||
_mcl_armor_equip = "mcl_armor_equip_leather",
|
||||
_mcl_armor_unequip = "mcl_armor_unequip_leather",
|
||||
},
|
||||
on_place = armor.on_armor_use,
|
||||
on_secondary_use = armor.on_armor_use,
|
||||
})
|
||||
|
||||
minetest.register_tool("mcl_armor:helmet_iron", {
|
||||
description = S("Iron Helmet"),
|
||||
_doc_items_longdesc = longdesc,
|
||||
_doc_items_usagehelp = usage,
|
||||
inventory_image = "mcl_armor_inv_helmet_iron.png",
|
||||
groups = {armor_head=1, mcl_armor_points=2, mcl_armor_uses=166, enchantability=9 },
|
||||
_repair_material = "mcl_core:iron_ingot",
|
||||
sounds = {
|
||||
_mcl_armor_equip = "mcl_armor_equip_iron",
|
||||
_mcl_armor_unequip = "mcl_armor_unequip_iron",
|
||||
},
|
||||
|
||||
on_place = armor.on_armor_use,
|
||||
on_secondary_use = armor.on_armor_use,
|
||||
})
|
||||
|
||||
minetest.register_tool("mcl_armor:helmet_gold", {
|
||||
description = S("Golden Helmet"),
|
||||
_doc_items_longdesc = longdesc,
|
||||
_doc_items_usagehelp = usage,
|
||||
inventory_image = "mcl_armor_inv_helmet_gold.png",
|
||||
groups = {armor_head=1, mcl_armor_points=2, mcl_armor_uses=78, enchantability=25 },
|
||||
_repair_material = "mcl_core:gold_ingot",
|
||||
sounds = {
|
||||
_mcl_armor_equip = "mcl_armor_equip_iron",
|
||||
_mcl_armor_unequip = "mcl_armor_unequip_iron",
|
||||
},
|
||||
on_place = armor.on_armor_use,
|
||||
on_secondary_use = armor.on_armor_use,
|
||||
})
|
||||
|
||||
minetest.register_tool("mcl_armor:helmet_diamond",{
|
||||
description = S("Diamond Helmet"),
|
||||
_doc_items_longdesc = longdesc,
|
||||
_doc_items_usagehelp = usage,
|
||||
inventory_image = "mcl_armor_inv_helmet_diamond.png",
|
||||
groups = {armor_head=1, mcl_armor_points=3, mcl_armor_uses=364, mcl_armor_toughness=2, enchantability=10 },
|
||||
_repair_material = "mcl_core:diamond",
|
||||
sounds = {
|
||||
_mcl_armor_equip = "mcl_armor_equip_diamond",
|
||||
_mcl_armor_unequip = "mcl_armor_unequip_diamond",
|
||||
},
|
||||
on_place = armor.on_armor_use,
|
||||
on_secondary_use = armor.on_armor_use,
|
||||
})
|
||||
|
||||
minetest.register_tool("mcl_armor:helmet_chain", {
|
||||
description = S("Chain Helmet"),
|
||||
_doc_items_longdesc = longdesc,
|
||||
_doc_items_usagehelp = usage,
|
||||
inventory_image = "mcl_armor_inv_helmet_chain.png",
|
||||
groups = {armor_head=1, mcl_armor_points=2, mcl_armor_uses=166, enchantability=12 },
|
||||
_repair_material = "mcl_core:iron_ingot",
|
||||
sounds = {
|
||||
_mcl_armor_equip = "mcl_armor_equip_chainmail",
|
||||
_mcl_armor_unequip = "mcl_armor_unequip_chainmail",
|
||||
},
|
||||
on_place = armor.on_armor_use,
|
||||
on_secondary_use = armor.on_armor_use,
|
||||
})
|
||||
|
||||
-- Regisiter Torso Armor
|
||||
|
||||
minetest.register_tool("mcl_armor:chestplate_leather", {
|
||||
description = S("Leather Tunic"),
|
||||
_doc_items_longdesc = longdesc,
|
||||
_doc_items_usagehelp = usage,
|
||||
inventory_image = "mcl_armor_inv_chestplate_leather.png",
|
||||
groups = {armor_torso=1, mcl_armor_points=3, mcl_armor_uses=81, enchantability=15 },
|
||||
_repair_material = "mcl_mobitems:leather",
|
||||
sounds = {
|
||||
_mcl_armor_equip = "mcl_armor_equip_leather",
|
||||
_mcl_armor_unequip = "mcl_armor_unequip_leather",
|
||||
},
|
||||
on_place = armor.on_armor_use,
|
||||
on_secondary_use = armor.on_armor_use,
|
||||
})
|
||||
|
||||
minetest.register_tool("mcl_armor:chestplate_iron", {
|
||||
description = S("Iron Chestplate"),
|
||||
_doc_items_longdesc = longdesc,
|
||||
_doc_items_usagehelp = usage,
|
||||
inventory_image = "mcl_armor_inv_chestplate_iron.png",
|
||||
groups = {armor_torso=1, mcl_armor_points=6, mcl_armor_uses=241, enchantability=9 },
|
||||
_repair_material = "mcl_core:iron_ingot",
|
||||
sounds = {
|
||||
_mcl_armor_equip = "mcl_armor_equip_iron",
|
||||
_mcl_armor_unequip = "mcl_armor_unequip_iron",
|
||||
},
|
||||
on_place = armor.on_armor_use,
|
||||
on_secondary_use = armor.on_armor_use,
|
||||
})
|
||||
|
||||
minetest.register_tool("mcl_armor:chestplate_gold", {
|
||||
description = S("Golden Chestplate"),
|
||||
_doc_items_longdesc = longdesc,
|
||||
_doc_items_usagehelp = usage,
|
||||
inventory_image = "mcl_armor_inv_chestplate_gold.png",
|
||||
groups = {armor_torso=1, mcl_armor_points=5, mcl_armor_uses=113, enchantability=25 },
|
||||
_repair_material = "mcl_core:gold_ingot",
|
||||
sounds = {
|
||||
_mcl_armor_equip = "mcl_armor_equip_iron",
|
||||
_mcl_armor_unequip = "mcl_armor_unequip_iron",
|
||||
},
|
||||
on_place = armor.on_armor_use,
|
||||
on_secondary_use = armor.on_armor_use,
|
||||
})
|
||||
|
||||
minetest.register_tool("mcl_armor:chestplate_diamond",{
|
||||
description = S("Diamond Chestplate"),
|
||||
_doc_items_longdesc = longdesc,
|
||||
_doc_items_usagehelp = usage,
|
||||
inventory_image = "mcl_armor_inv_chestplate_diamond.png",
|
||||
groups = {armor_torso=1, mcl_armor_points=8, mcl_armor_uses=529, mcl_armor_toughness=2, enchantability=10 },
|
||||
_repair_material = "mcl_core:diamond",
|
||||
sounds = {
|
||||
_mcl_armor_equip = "mcl_armor_equip_diamond",
|
||||
_mcl_armor_unequip = "mcl_armor_unequip_diamond",
|
||||
},
|
||||
on_place = armor.on_armor_use,
|
||||
on_secondary_use = armor.on_armor_use,
|
||||
})
|
||||
|
||||
minetest.register_tool("mcl_armor:chestplate_chain", {
|
||||
description = S("Chain Chestplate"),
|
||||
_doc_items_longdesc = longdesc,
|
||||
_doc_items_usagehelp = usage,
|
||||
inventory_image = "mcl_armor_inv_chestplate_chain.png",
|
||||
groups = {armor_torso=1, mcl_armor_points=5, mcl_armor_uses=241, enchantability=12 },
|
||||
_repair_material = "mcl_core:iron_ingot",
|
||||
sounds = {
|
||||
_mcl_armor_equip = "mcl_armor_equip_chainmail",
|
||||
_mcl_armor_unequip = "mcl_armor_unequip_chainmail",
|
||||
},
|
||||
on_place = armor.on_armor_use,
|
||||
on_secondary_use = armor.on_armor_use,
|
||||
})
|
||||
|
||||
-- Regisiter Leg Armor
|
||||
|
||||
minetest.register_tool("mcl_armor:leggings_leather", {
|
||||
description = S("Leather Pants"),
|
||||
_doc_items_longdesc = longdesc,
|
||||
_doc_items_usagehelp = usage,
|
||||
inventory_image = "mcl_armor_inv_leggings_leather.png",
|
||||
groups = {armor_legs=1, mcl_armor_points=2, mcl_armor_uses=76, enchantability=15 },
|
||||
_repair_material = "mcl_mobitems:leather",
|
||||
sounds = {
|
||||
_mcl_armor_equip = "mcl_armor_equip_leather",
|
||||
_mcl_armor_unequip = "mcl_armor_unequip_leather",
|
||||
},
|
||||
on_place = armor.on_armor_use,
|
||||
on_secondary_use = armor.on_armor_use,
|
||||
})
|
||||
|
||||
minetest.register_tool("mcl_armor:leggings_iron", {
|
||||
description = S("Iron Leggings"),
|
||||
_doc_items_longdesc = longdesc,
|
||||
_doc_items_usagehelp = usage,
|
||||
inventory_image = "mcl_armor_inv_leggings_iron.png",
|
||||
groups = {armor_legs=1, mcl_armor_points=5, mcl_armor_uses=226, enchantability=9 },
|
||||
_repair_material = "mcl_core:iron_ingot",
|
||||
sounds = {
|
||||
_mcl_armor_equip = "mcl_armor_equip_iron",
|
||||
_mcl_armor_unequip = "mcl_armor_unequip_iron",
|
||||
},
|
||||
on_place = armor.on_armor_use,
|
||||
on_secondary_use = armor.on_armor_use,
|
||||
})
|
||||
|
||||
minetest.register_tool("mcl_armor:leggings_gold", {
|
||||
description = S("Golden Leggings"),
|
||||
_doc_items_longdesc = longdesc,
|
||||
_doc_items_usagehelp = usage,
|
||||
inventory_image = "mcl_armor_inv_leggings_gold.png",
|
||||
groups = {armor_legs=1, mcl_armor_points=3, mcl_armor_uses=106, enchantability=25 },
|
||||
_repair_material = "mcl_core:gold_ingot",
|
||||
sounds = {
|
||||
_mcl_armor_equip = "mcl_armor_equip_iron",
|
||||
_mcl_armor_unequip = "mcl_armor_unequip_iron",
|
||||
},
|
||||
on_place = armor.on_armor_use,
|
||||
on_secondary_use = armor.on_armor_use,
|
||||
})
|
||||
|
||||
minetest.register_tool("mcl_armor:leggings_diamond",{
|
||||
description = S("Diamond Leggings"),
|
||||
_doc_items_longdesc = longdesc,
|
||||
_doc_items_usagehelp = usage,
|
||||
inventory_image = "mcl_armor_inv_leggings_diamond.png",
|
||||
groups = {armor_legs=1, mcl_armor_points=6, mcl_armor_uses=496, mcl_armor_toughness=2, enchantability=10 },
|
||||
_repair_material = "mcl_core:diamond",
|
||||
sounds = {
|
||||
_mcl_armor_equip = "mcl_armor_equip_diamond",
|
||||
_mcl_armor_unequip = "mcl_armor_unequip_diamond",
|
||||
},
|
||||
on_place = armor.on_armor_use,
|
||||
on_secondary_use = armor.on_armor_use,
|
||||
})
|
||||
|
||||
minetest.register_tool("mcl_armor:leggings_chain", {
|
||||
description = S("Chain Leggings"),
|
||||
_doc_items_longdesc = longdesc,
|
||||
_doc_items_usagehelp = usage,
|
||||
inventory_image = "mcl_armor_inv_leggings_chain.png",
|
||||
groups = {armor_legs=1, mcl_armor_points=4, mcl_armor_uses=226, enchantability=12 },
|
||||
_repair_material = "mcl_core:iron_ingot",
|
||||
sounds = {
|
||||
_mcl_armor_equip = "mcl_armor_equip_chainmail",
|
||||
_mcl_armor_unequip = "mcl_armor_unequip_chainmail",
|
||||
},
|
||||
on_place = armor.on_armor_use,
|
||||
on_secondary_use = armor.on_armor_use,
|
||||
})
|
||||
-- Regisiter Boots
|
||||
|
||||
minetest.register_tool("mcl_armor:boots_leather", {
|
||||
description = S("Leather Boots"),
|
||||
_doc_items_longdesc = longdesc,
|
||||
_doc_items_usagehelp = usage,
|
||||
inventory_image = "mcl_armor_inv_boots_leather.png",
|
||||
groups = {armor_feet=1, mcl_armor_points=1, mcl_armor_uses=66, enchantability=15 },
|
||||
_repair_material = "mcl_mobitems:leather",
|
||||
sounds = {
|
||||
_mcl_armor_equip = "mcl_armor_equip_leather",
|
||||
_mcl_armor_unequip = "mcl_armor_unequip_leather",
|
||||
},
|
||||
on_place = armor.on_armor_use,
|
||||
on_secondary_use = armor.on_armor_use,
|
||||
})
|
||||
|
||||
minetest.register_tool("mcl_armor:boots_iron", {
|
||||
description = S("Iron Boots"),
|
||||
_doc_items_longdesc = longdesc,
|
||||
_doc_items_usagehelp = usage,
|
||||
inventory_image = "mcl_armor_inv_boots_iron.png",
|
||||
groups = {armor_feet=1, mcl_armor_points=2, mcl_armor_uses=196, enchantability=9 },
|
||||
_repair_material = "mcl_core:iron_ingot",
|
||||
sounds = {
|
||||
_mcl_armor_equip = "mcl_armor_equip_iron",
|
||||
_mcl_armor_unequip = "mcl_armor_unequip_iron",
|
||||
},
|
||||
on_place = armor.on_armor_use,
|
||||
on_secondary_use = armor.on_armor_use,
|
||||
})
|
||||
|
||||
minetest.register_tool("mcl_armor:boots_gold", {
|
||||
description = S("Golden Boots"),
|
||||
_doc_items_longdesc = longdesc,
|
||||
_doc_items_usagehelp = usage,
|
||||
inventory_image = "mcl_armor_inv_boots_gold.png",
|
||||
groups = {armor_feet=1, mcl_armor_points=1, mcl_armor_uses=92, enchantability=25 },
|
||||
_repair_material = "mcl_core:gold_ingot",
|
||||
sounds = {
|
||||
_mcl_armor_equip = "mcl_armor_equip_iron",
|
||||
_mcl_armor_unequip = "mcl_armor_unequip_iron",
|
||||
},
|
||||
on_place = armor.on_armor_use,
|
||||
on_secondary_use = armor.on_armor_use,
|
||||
})
|
||||
|
||||
minetest.register_tool("mcl_armor:boots_diamond",{
|
||||
description = S("Diamond Boots"),
|
||||
_doc_items_longdesc = longdesc,
|
||||
_doc_items_usagehelp = usage,
|
||||
inventory_image = "mcl_armor_inv_boots_diamond.png",
|
||||
groups = {armor_feet=1, mcl_armor_points=3, mcl_armor_uses=430, mcl_armor_toughness=2, enchantability=10 },
|
||||
_repair_material = "mcl_core:diamond",
|
||||
sounds = {
|
||||
_mcl_armor_equip = "mcl_armor_equip_diamond",
|
||||
_mcl_armor_unequip = "mcl_armor_unequip_diamond",
|
||||
},
|
||||
on_place = armor.on_armor_use,
|
||||
on_secondary_use = armor.on_armor_use,
|
||||
})
|
||||
|
||||
minetest.register_tool("mcl_armor:boots_chain", {
|
||||
description = S("Chain Boots"),
|
||||
_doc_items_longdesc = longdesc,
|
||||
_doc_items_usagehelp = usage,
|
||||
inventory_image = "mcl_armor_inv_boots_chain.png",
|
||||
groups = {armor_feet=1, mcl_armor_points=1, mcl_armor_uses=196, enchantability=12 },
|
||||
_repair_material = "mcl_core:iron_ingot",
|
||||
sounds = {
|
||||
_mcl_armor_equip = "mcl_armor_equip_chainmail",
|
||||
_mcl_armor_unequip = "mcl_armor_unequip_chainmail",
|
||||
},
|
||||
on_place = armor.on_armor_use,
|
||||
on_secondary_use = armor.on_armor_use,
|
||||
})
|
||||
|
||||
-- Register Craft Recipies
|
||||
|
||||
local craft_ingreds = {
|
||||
leather = { "mcl_mobitems:leather" },
|
||||
iron = { "mcl_core:iron_ingot", "mcl_core:iron_nugget" },
|
||||
gold = { "mcl_core:gold_ingot", "mcl_core:gold_nugget" },
|
||||
diamond = { "mcl_core:diamond" },
|
||||
chain = { nil, "mcl_core:iron_nugget"} ,
|
||||
}
|
||||
|
||||
for k, v in pairs(craft_ingreds) do
|
||||
-- material
|
||||
local m = v[1]
|
||||
-- cooking result
|
||||
local c = v[2]
|
||||
if m ~= nil then
|
||||
minetest.register_craft({
|
||||
output = "mcl_armor:helmet_"..k,
|
||||
recipe = {
|
||||
mcl_armor = {
|
||||
longdesc = S("This is a piece of equippable armor which reduces the amount of damage you receive."),
|
||||
usage = S("To equip it, put it on the corresponding armor slot in your inventory menu."),
|
||||
elements = {
|
||||
head = {
|
||||
name = "helmet",
|
||||
description = "Helmet",
|
||||
durability = 0.6857,
|
||||
index = 2,
|
||||
craft = function(m)
|
||||
return {
|
||||
{ m, m, m},
|
||||
{ m, "", m},
|
||||
{"", "", ""},
|
||||
}
|
||||
end,
|
||||
},
|
||||
})
|
||||
minetest.register_craft({
|
||||
output = "mcl_armor:chestplate_"..k,
|
||||
recipe = {
|
||||
torso = {
|
||||
name = "chestplate",
|
||||
description = "Chestplate",
|
||||
durability = 1.0,
|
||||
index = 3,
|
||||
craft = function(m)
|
||||
return {
|
||||
{ m, "", m},
|
||||
{ m, m, m},
|
||||
{ m, m, m},
|
||||
}
|
||||
end,
|
||||
},
|
||||
})
|
||||
minetest.register_craft({
|
||||
output = "mcl_armor:leggings_"..k,
|
||||
recipe = {
|
||||
legs = {
|
||||
name = "leggings",
|
||||
description = "Leggings",
|
||||
durability = 0.9375,
|
||||
index = 4,
|
||||
craft = function(m)
|
||||
return {
|
||||
{ m, m, m},
|
||||
{ m, "", m},
|
||||
{ m, "", m},
|
||||
}
|
||||
end,
|
||||
},
|
||||
})
|
||||
minetest.register_craft({
|
||||
output = "mcl_armor:boots_"..k,
|
||||
recipe = {
|
||||
feet = {
|
||||
name = "boots",
|
||||
description = "Boots",
|
||||
durability = 0.8125,
|
||||
index = 5,
|
||||
craft = function(m)
|
||||
return {
|
||||
{ m, "", m},
|
||||
{ m, "", m},
|
||||
}
|
||||
end,
|
||||
}
|
||||
},
|
||||
})
|
||||
end
|
||||
if c ~= nil then
|
||||
minetest.register_craft({
|
||||
type = "cooking",
|
||||
output = c,
|
||||
recipe = "mcl_armor:helmet_"..k,
|
||||
cooktime = 10,
|
||||
})
|
||||
minetest.register_craft({
|
||||
type = "cooking",
|
||||
output = c,
|
||||
recipe = "mcl_armor:chestplate_"..k,
|
||||
cooktime = 10,
|
||||
})
|
||||
minetest.register_craft({
|
||||
type = "cooking",
|
||||
output = c,
|
||||
recipe = "mcl_armor:leggings_"..k,
|
||||
cooktime = 10,
|
||||
})
|
||||
minetest.register_craft({
|
||||
type = "cooking",
|
||||
output = c,
|
||||
recipe = "mcl_armor:boots_"..k,
|
||||
cooktime = 10,
|
||||
})
|
||||
end
|
||||
end
|
||||
player_view_range_factors = {},
|
||||
}
|
||||
|
||||
local modpath = minetest.get_modpath("mcl_armor")
|
||||
|
||||
dofile(modpath .. "/api.lua")
|
||||
dofile(modpath .. "/player.lua")
|
||||
dofile(modpath .. "/damage.lua")
|
||||
dofile(modpath .. "/register.lua")
|
||||
dofile(modpath .. "/alias.lua")
|
||||
|
169
mods/ITEMS/mcl_armor/player.lua
Normal file
169
mods/ITEMS/mcl_armor/player.lua
Normal file
@ -0,0 +1,169 @@
|
||||
mcl_player.player_register_model("mcl_armor_character.b3d", {
|
||||
animation_speed = 30,
|
||||
textures = {
|
||||
"character.png",
|
||||
"blank.png",
|
||||
"blank.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},
|
||||
sneak_stand = {x=222, y=302},
|
||||
sneak_mine = {x=346, y=365},
|
||||
sneak_walk = {x=304, y=323},
|
||||
sneak_walk_mine = {x=325, y=344},
|
||||
swim_walk = {x=368, y=387},
|
||||
swim_walk_mine = {x=389, y=408},
|
||||
swim_stand = {x=434, y=434},
|
||||
swim_mine = {x=411, y=430},
|
||||
run_walk = {x=440, y=459},
|
||||
run_walk_mine = {x=461, y=480},
|
||||
sit_mount = {x=484, y=484},
|
||||
die = {x=498, y=498},
|
||||
fly = {x=502, y=581},
|
||||
},
|
||||
})
|
||||
|
||||
mcl_player.player_register_model("mcl_armor_character_female.b3d", {
|
||||
animation_speed = 30,
|
||||
textures = {
|
||||
"character.png",
|
||||
"blank.png",
|
||||
"blank.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},
|
||||
sneak_stand = {x=222, y=302},
|
||||
sneak_mine = {x=346, y=365},
|
||||
sneak_walk = {x=304, y=323},
|
||||
sneak_walk_mine = {x=325, y=344},
|
||||
swim_walk = {x=368, y=387},
|
||||
swim_walk_mine = {x=389, y=408},
|
||||
swim_stand = {x=434, y=434},
|
||||
swim_mine = {x=411, y=430},
|
||||
run_walk = {x=440, y=459},
|
||||
run_walk_mine = {x=461, y=480},
|
||||
sit_mount = {x=484, y=484},
|
||||
die = {x=498, y=498},
|
||||
fly = {x=502, y=581},
|
||||
},
|
||||
})
|
||||
|
||||
function mcl_armor.update_player(player, info)
|
||||
mcl_player.player_set_armor(player, info.texture, info.preview)
|
||||
|
||||
local meta = player:get_meta()
|
||||
meta:set_int("mcl_armor:armor_points", info.points)
|
||||
|
||||
mcl_armor.player_view_range_factors[player] = info.view_range_factors
|
||||
end
|
||||
|
||||
local function is_armor_action(inventory_info)
|
||||
return inventory_info.from_list == "armor" or inventory_info.to_list == "armor" or inventory_info.listname == "armor"
|
||||
end
|
||||
|
||||
local function limit_put(player, inventory, index, stack, count)
|
||||
local def = stack:get_definition()
|
||||
|
||||
if not def then
|
||||
return 0
|
||||
end
|
||||
|
||||
local element = def._mcl_armor_element
|
||||
|
||||
if not element then
|
||||
return 0
|
||||
end
|
||||
|
||||
local element_index = mcl_armor.elements[element].index
|
||||
|
||||
if index ~= 1 and index ~= element_index then
|
||||
return 0
|
||||
end
|
||||
|
||||
local old_stack = inventory:get_stack("armor", element_index)
|
||||
|
||||
if old_stack:is_empty() or index ~= 1 and old_stack:get_name() ~= stack:get_name() and count <= 1 then
|
||||
return count
|
||||
else
|
||||
return 0
|
||||
end
|
||||
end
|
||||
|
||||
local function limit_take(player, inventory, index, stack, count)
|
||||
if mcl_enchanting.has_enchantment(stack, "curse_of_binding") and not minetest.is_creative_enabled(player:get_player_name()) then
|
||||
return 0
|
||||
end
|
||||
|
||||
return count
|
||||
end
|
||||
|
||||
minetest.register_allow_player_inventory_action(function(player, action, inventory, inventory_info)
|
||||
if not is_armor_action(inventory_info) then
|
||||
return
|
||||
end
|
||||
|
||||
if action == "put" then
|
||||
return limit_put(player, inventory, inventory_info.index, inventory_info.stack, inventory_info.stack:get_count())
|
||||
elseif action == "take" then
|
||||
return limit_take(player, inventory, inventory_info.index, inventory_info.stack, inventory_info.stack:get_count())
|
||||
else
|
||||
if inventory_info.from_list ~= "armor" then
|
||||
return limit_put(player, inventory, inventory_info.to_index, inventory:get_stack(inventory_info.from_list, inventory_info.from_index), inventory_info.count)
|
||||
elseif inventory_info.to_list ~= "armor" then
|
||||
return limit_take(player, inventory, inventory_info.from_index, inventory:get_stack(inventory_info.from_list, inventory_info.from_index), inventory_info.count)
|
||||
else
|
||||
return 0
|
||||
end
|
||||
end
|
||||
end)
|
||||
|
||||
local function on_put(player, inventory, index, stack)
|
||||
if index == 1 then
|
||||
mcl_armor.equip(stack, player)
|
||||
inventory:set_stack("armor", 1, nil)
|
||||
else
|
||||
mcl_armor.on_equip(stack, player)
|
||||
end
|
||||
end
|
||||
|
||||
minetest.register_on_player_inventory_action(function(player, action, inventory, inventory_info)
|
||||
if is_armor_action(inventory_info) then
|
||||
if action == "put" then
|
||||
on_put(player, inventory, inventory_info.index, inventory_info.stack)
|
||||
elseif action == "take" then
|
||||
mcl_armor.on_unequip(inventory_info.stack, player)
|
||||
else
|
||||
local stack = inventory:get_stack(inventory_info.to_list, inventory_info.to_index)
|
||||
if inventory_info.to_list == "armor" then
|
||||
on_put(player, inventory, inventory_info.to_index, stack)
|
||||
elseif inventory_info.from_list == "armor" then
|
||||
mcl_armor.on_unequip(stack, player)
|
||||
end
|
||||
end
|
||||
end
|
||||
end)
|
||||
|
||||
minetest.register_on_joinplayer(function(player)
|
||||
mcl_player.player_set_model(player, "mcl_armor_character.b3d")
|
||||
player:get_inventory():set_size("armor", 5)
|
||||
|
||||
minetest.after(1, function()
|
||||
if player:is_player() then
|
||||
mcl_armor.update(player)
|
||||
end
|
||||
end)
|
||||
end)
|
||||
|
||||
minetest.register_on_leaveplayer(function(player)
|
||||
mcl_armor.player_view_range_factors[player] = nil
|
||||
end)
|
205
mods/ITEMS/mcl_armor/register.lua
Normal file
205
mods/ITEMS/mcl_armor/register.lua
Normal file
@ -0,0 +1,205 @@
|
||||
local S = minetest.get_translator("mcl_armor")
|
||||
|
||||
mcl_armor.register_set({
|
||||
name = "leather",
|
||||
description = "Leather",
|
||||
descriptions = {
|
||||
head = "Cap",
|
||||
torso = "Tunic",
|
||||
legs = "Pants",
|
||||
},
|
||||
durability = 80,
|
||||
enchantability = 15,
|
||||
points = {
|
||||
head = 1,
|
||||
torso = 3,
|
||||
legs = 2,
|
||||
feet = 1,
|
||||
},
|
||||
craft_material = "mcl_mobitems:leather",
|
||||
})
|
||||
|
||||
mcl_armor.register_set({
|
||||
name = "gold",
|
||||
description = "Golden",
|
||||
durability = 112,
|
||||
enchantability = 25,
|
||||
points = {
|
||||
head = 2,
|
||||
torso = 5,
|
||||
legs = 3,
|
||||
feet = 1,
|
||||
},
|
||||
craft_material = "mcl_core:gold_ingot",
|
||||
cook_material = "mcl_core:gold_nugget",
|
||||
sound_equip = "mcl_armor_equip_iron",
|
||||
sound_unequip = "mcl_armor_unequip_iron",
|
||||
})
|
||||
|
||||
mcl_armor.register_set({
|
||||
name = "chain",
|
||||
description = "Chain",
|
||||
durability = 240,
|
||||
enchantability = 12,
|
||||
points = {
|
||||
head = 2,
|
||||
torso = 5,
|
||||
legs = 4,
|
||||
feet = 1,
|
||||
},
|
||||
repair_material = "mcl_core:iron_ingot",
|
||||
cook_material = "mcl_core:iron_nugget",
|
||||
})
|
||||
|
||||
mcl_armor.register_set({
|
||||
name = "iron",
|
||||
description = "Iron",
|
||||
durability = 240,
|
||||
enchantability = 9,
|
||||
points = {
|
||||
head = 2,
|
||||
torso = 6,
|
||||
legs = 5,
|
||||
feet = 2,
|
||||
},
|
||||
craft_material = "mcl_core:iron_ingot",
|
||||
cook_material = "mcl_core:iron_nugget",
|
||||
})
|
||||
|
||||
mcl_armor.register_set({
|
||||
name = "diamond",
|
||||
description = "Diamond",
|
||||
durability = 528,
|
||||
enchantability = 10,
|
||||
points = {
|
||||
head = 3,
|
||||
torso = 8,
|
||||
legs = 6,
|
||||
feet = 3,
|
||||
},
|
||||
toughness = 2,
|
||||
craft_material = "mcl_core:diamond",
|
||||
})
|
||||
|
||||
mcl_armor.register_protection_enchantment({
|
||||
id = "projectile_protection",
|
||||
name = S("Projectile Protection"),
|
||||
description = S("Reduces projectile damage."),
|
||||
power_range_table = {{1, 16}, {11, 26}, {21, 36}, {31, 46}, {41, 56}},
|
||||
incompatible = {blast_protection = true, fire_protection = true, protection = true},
|
||||
factor = 2,
|
||||
damage_flag = "is_projectile",
|
||||
})
|
||||
|
||||
mcl_armor.register_protection_enchantment({
|
||||
id = "blast_protection",
|
||||
name = S("Blast Protection"),
|
||||
description = S("Reduces explosion damage and knockback."),
|
||||
power_range_table = {{5, 13}, {13, 21}, {21, 29}, {29, 37}},
|
||||
weight = 2,
|
||||
incompatible = {fire_protection = true, protection = true, projectile_protection = true},
|
||||
factor = 2,
|
||||
damage_flag = "is_explosion",
|
||||
})
|
||||
|
||||
mcl_armor.register_protection_enchantment({
|
||||
id = "fire_protection",
|
||||
name = S("Fire Protection"),
|
||||
description = S("Reduces fire damage."),
|
||||
power_range_table = {{5, 13}, {13, 21}, {21, 29}, {29, 37}},
|
||||
incompatible = {blast_protection = true, protection = true, projectile_protection = true},
|
||||
factor = 2,
|
||||
damage_flag = "is_fire",
|
||||
})
|
||||
|
||||
mcl_armor.register_protection_enchantment({
|
||||
id = "protection",
|
||||
name = S("Protection"),
|
||||
description = S("Reduces most types of damage by 4% for each level."),
|
||||
power_range_table = {{1, 12}, {12, 23}, {23, 34}, {34, 45}},
|
||||
incompatible = {blast_protection = true, fire_protection = true, projectile_protection = true},
|
||||
factor = 1,
|
||||
})
|
||||
|
||||
mcl_armor.register_protection_enchantment({
|
||||
id = "feather_falling",
|
||||
name = S("Feather Falling"),
|
||||
description = S("Reduces fall damage."),
|
||||
power_range_table = {{5, 11}, {11, 17}, {17, 23}, {23, 29}},
|
||||
factor = 3,
|
||||
primary = {combat_armor_feet = true},
|
||||
damage_type = "fall",
|
||||
})
|
||||
|
||||
-- requires engine change
|
||||
--[[mcl_enchanting.enchantments.aqua_affinity = {
|
||||
name = S("Aqua Affinity"),
|
||||
max_level = 1,
|
||||
primary = {armor_head = true},
|
||||
secondary = {},
|
||||
disallow = {non_combat_armor = true},
|
||||
incompatible = {},
|
||||
weight = 2,
|
||||
description = S("Increases underwater mining speed."),
|
||||
curse = false,
|
||||
on_enchant = function() end,
|
||||
requires_tool = false,
|
||||
treasure = false,
|
||||
power_range_table = {{1, 41}},
|
||||
inv_combat_tab = true,
|
||||
inv_tool_tab = false,
|
||||
}]]--
|
||||
|
||||
mcl_enchanting.enchantments.curse_of_binding = {
|
||||
name = S("Curse of Binding"),
|
||||
max_level = 1,
|
||||
primary = {},
|
||||
secondary = {armor_head = true, armor_torso = true, armor_legs = true, armor_feet = true},
|
||||
disallow = {},
|
||||
incompatible = {},
|
||||
weight = 1,
|
||||
description = S("Item cannot be removed from armor slots except due to death, breaking or in Creative Mode."),
|
||||
curse = true,
|
||||
on_enchant = function() end,
|
||||
requires_tool = false,
|
||||
treasure = true,
|
||||
power_range_table = {{25, 50}},
|
||||
inv_combat_tab = true,
|
||||
inv_tool_tab = false,
|
||||
}
|
||||
|
||||
mcl_enchanting.enchantments.thorns = {
|
||||
name = S("Thorns"),
|
||||
max_level = 3,
|
||||
primary = {combat_armor_chestplate = true},
|
||||
secondary = {combat_armor = true},
|
||||
disallow = {},
|
||||
incompatible = {},
|
||||
weight = 1,
|
||||
description = S("Reflects some of the damage taken when hit, at the cost of reducing durability with each proc."),
|
||||
curse = false,
|
||||
on_enchant = function() end,
|
||||
requires_tool = false,
|
||||
treasure = false,
|
||||
power_range_table = {{10, 61}, {30, 71}, {50, 81}},
|
||||
inv_combat_tab = true,
|
||||
inv_tool_tab = false,
|
||||
}
|
||||
|
||||
-- Elytra
|
||||
|
||||
minetest.register_tool("mcl_armor:elytra", {
|
||||
description = S("Elytra"),
|
||||
_doc_items_longdesc = mcl_armor.longdesc,
|
||||
_doc_items_usagehelp = mcl_armor.usage,
|
||||
inventory_image = "mcl_armor_inv_elytra.png",
|
||||
groups = {armor = 1, non_combat_armor = 1, armor_torso = 1, non_combat_torso = 1, mcl_armor_uses = 10},
|
||||
sounds = {
|
||||
_mcl_armor_equip = "mcl_armor_equip_leather",
|
||||
_mcl_armor_unequip = "mcl_armor_unequip_leather",
|
||||
},
|
||||
on_place = mcl_armor.equip_on_use,
|
||||
on_secondary_use = mcl_armor.equip_on_use,
|
||||
_mcl_armor_element = "torso",
|
||||
_mcl_armor_texture = "mcl_armor_elytra.png"
|
||||
})
|
@ -1,84 +1,41 @@
|
||||
local S = minetest.get_translator("mcl_armor_stand")
|
||||
|
||||
local elements = {"head", "torso", "legs", "feet"}
|
||||
|
||||
local function get_stand_object(pos)
|
||||
local object = nil
|
||||
local objects = minetest.get_objects_inside_radius(pos, 0.5) or {}
|
||||
for _, obj in pairs(objects) do
|
||||
local ent = obj:get_luaentity()
|
||||
if ent then
|
||||
if ent.name == "mcl_armor_stand:armor_entity" then
|
||||
-- Remove duplicates
|
||||
if object then
|
||||
obj:remove()
|
||||
else
|
||||
object = obj
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
return object
|
||||
-- Spawn a stand entity
|
||||
local function spawn_stand_entity(pos, node)
|
||||
local luaentity = minetest.add_entity(pos, "mcl_armor_stand:armor_entity"):get_luaentity()
|
||||
luaentity:update_rotation(node or minetest.get_node(pos))
|
||||
return luaentity
|
||||
end
|
||||
|
||||
local function update_entity(pos)
|
||||
local node = minetest.get_node(pos)
|
||||
local object = get_stand_object(pos)
|
||||
if object then
|
||||
if not string.find(node.name, "mcl_armor_stand:") then
|
||||
object:remove()
|
||||
return
|
||||
end
|
||||
else
|
||||
object = minetest.add_entity(pos, "mcl_armor_stand:armor_entity")
|
||||
end
|
||||
if object then
|
||||
local texture = "blank.png"
|
||||
local textures = {}
|
||||
local meta = minetest.get_meta(pos)
|
||||
local inv = meta:get_inventory()
|
||||
local yaw = 0
|
||||
if inv then
|
||||
for _, element in pairs(elements) do
|
||||
local stack = inv:get_stack("armor_"..element, 1)
|
||||
if stack:get_count() == 1 then
|
||||
local item = stack:get_name() or ""
|
||||
if minetest.registered_aliases[item] then
|
||||
item = minetest.registered_aliases[item]
|
||||
end
|
||||
local def = stack:get_definition() or {}
|
||||
local groups = def.groups or {}
|
||||
if groups["armor_"..element] then
|
||||
local texture = def.texture or item:gsub("%:", "_")
|
||||
table.insert(textures, texture..".png")
|
||||
-- Find a stand entity or spawn one
|
||||
local function get_stand_entity(pos, node)
|
||||
for _, obj in ipairs(minetest.get_objects_inside_radius(pos, 0)) do
|
||||
local luaentity = obj:get_luaentity()
|
||||
if luaentity and luaentity.name == "mcl_armor_stand:armor_entity" then
|
||||
return luaentity
|
||||
end
|
||||
end
|
||||
return spawn_stand_entity(pos, node)
|
||||
end
|
||||
|
||||
-- Migrate the old inventory format
|
||||
local function migrate_inventory(inv)
|
||||
inv:set_size("armor", 5)
|
||||
local lists = inv:get_lists()
|
||||
for name, element in pairs(mcl_armor.elements) do
|
||||
local listname = "armor_" .. name
|
||||
local list = lists[listname]
|
||||
if list then
|
||||
inv:set_stack("armor", element.index, list[1])
|
||||
inv:set_size(listname, 0)
|
||||
end
|
||||
if #textures > 0 then
|
||||
texture = table.concat(textures, "^")
|
||||
end
|
||||
if node.param2 then
|
||||
local rot = node.param2 % 4
|
||||
if rot == 1 then
|
||||
yaw = 3 * math.pi / 2
|
||||
elseif rot == 2 then
|
||||
yaw = math.pi
|
||||
elseif rot == 3 then
|
||||
yaw = math.pi / 2
|
||||
end
|
||||
end
|
||||
object:set_yaw(yaw)
|
||||
object:set_properties({textures={texture}})
|
||||
end
|
||||
end
|
||||
|
||||
-- Drop all armor of the armor stand on the ground
|
||||
local drop_armor = function(pos)
|
||||
local meta = minetest.get_meta(pos)
|
||||
local inv = meta:get_inventory()
|
||||
for _, element in pairs(elements) do
|
||||
local stack = inv:get_stack("armor_"..element, 1)
|
||||
-- Drop all armor on the ground when it got destroyed
|
||||
local function drop_inventory(pos)
|
||||
local inv = minetest.get_meta(pos):get_inventory()
|
||||
for _, stack in pairs(inv:get_list("armor")) do
|
||||
if not stack:is_empty() then
|
||||
local p = {x=pos.x+math.random(0, 10)/10-0.5, y=pos.y, z=pos.z+math.random(0, 10)/10-0.5}
|
||||
minetest.add_item(p, stack)
|
||||
@ -111,136 +68,26 @@ minetest.register_node("mcl_armor_stand:armor_stand", {
|
||||
_mcl_hardness = 2,
|
||||
sounds = mcl_sounds.node_sound_wood_defaults(),
|
||||
on_construct = function(pos)
|
||||
local meta = minetest.get_meta(pos)
|
||||
local inv = meta:get_inventory()
|
||||
for _, element in pairs(elements) do
|
||||
inv:set_size("armor_"..element, 1)
|
||||
end
|
||||
spawn_stand_entity(pos)
|
||||
end,
|
||||
on_destruct = function(pos)
|
||||
drop_inventory(pos)
|
||||
end,
|
||||
-- Drop all armor on the ground when it got destroyed
|
||||
on_destruct = drop_armor,
|
||||
-- Put piece of armor on armor stand, or take one away
|
||||
on_rightclick = function(pos, node, clicker, itemstack, pointed_thing)
|
||||
local protname = clicker:get_player_name()
|
||||
|
||||
if minetest.is_protected(pos, protname) then
|
||||
minetest.record_protection_violation(pos, protname)
|
||||
return itemstack
|
||||
end
|
||||
|
||||
local inv = minetest.get_inventory({type = "node", pos = pos})
|
||||
if not inv then
|
||||
return itemstack
|
||||
end
|
||||
|
||||
-- Check if player wields armor
|
||||
local name = itemstack:get_name()
|
||||
local list
|
||||
for e=1, #elements do
|
||||
local g = minetest.get_item_group(name, "armor_" .. elements[e])
|
||||
if g ~= nil and g ~= 0 then
|
||||
list = "armor_" .. elements[e]
|
||||
break
|
||||
end
|
||||
end
|
||||
-- If player wields armor, put it on armor stand
|
||||
local wielditem = clicker:get_wielded_item()
|
||||
if list then
|
||||
-- ... but only if the slot is free
|
||||
local single_item = ItemStack(itemstack)
|
||||
single_item:set_count(1)
|
||||
if inv:is_empty(list) then
|
||||
inv:add_item(list, single_item)
|
||||
armor:play_equip_sound(single_item, nil, pos)
|
||||
update_entity(pos)
|
||||
itemstack:take_item()
|
||||
return itemstack
|
||||
end
|
||||
end
|
||||
|
||||
-- Take armor from stand if player has a free hand or wields the same armor type (if stackable)
|
||||
for e=1, #elements do
|
||||
local stand_armor = inv:get_stack("armor_" .. elements[e], 1)
|
||||
if not stand_armor:is_empty() then
|
||||
local pinv = clicker:get_inventory()
|
||||
local taken = false
|
||||
-- Empty hand
|
||||
if wielditem:get_name() == "" then
|
||||
pinv:set_stack("main", clicker:get_wield_index(), stand_armor)
|
||||
taken = true
|
||||
-- Stackable armor type (if not already full). This is the case for e.g. mob heads.
|
||||
-- This is done purely for convenience.
|
||||
elseif (wielditem:get_name() == stand_armor:get_name() and wielditem:get_count() < wielditem:get_stack_max()) then
|
||||
wielditem:set_count(wielditem:get_count()+1)
|
||||
pinv:set_stack("main", clicker:get_wield_index(), wielditem)
|
||||
taken = true
|
||||
end
|
||||
if taken then
|
||||
armor:play_equip_sound(stand_armor, nil, pos, true)
|
||||
stand_armor:take_item()
|
||||
inv:set_stack("armor_" .. elements[e], 1, stand_armor)
|
||||
end
|
||||
update_entity(pos)
|
||||
return clicker:get_wielded_item()
|
||||
end
|
||||
end
|
||||
update_entity(pos)
|
||||
return itemstack
|
||||
end,
|
||||
after_place_node = function(pos)
|
||||
minetest.add_entity(pos, "mcl_armor_stand:armor_entity")
|
||||
end,
|
||||
allow_metadata_inventory_take = function(pos, listname, index, stack, player)
|
||||
local name = player:get_player_name()
|
||||
if minetest.is_protected(pos, name) then
|
||||
minetest.record_protection_violation(pos, name)
|
||||
return 0
|
||||
else
|
||||
return stack:get_count()
|
||||
end
|
||||
end,
|
||||
allow_metadata_inventory_put = function(pos, listname, index, stack, player)
|
||||
local name = player:get_player_name()
|
||||
if minetest.is_protected(pos, name) then
|
||||
minetest.record_protection_violation(pos, name)
|
||||
return 0
|
||||
end
|
||||
local def = stack:get_definition() or {}
|
||||
local groups = def.groups or {}
|
||||
if groups[listname] then
|
||||
return 1
|
||||
end
|
||||
return 0
|
||||
end,
|
||||
allow_metadata_inventory_move = function()
|
||||
return 0
|
||||
end,
|
||||
on_metadata_inventory_put = function(pos)
|
||||
update_entity(pos)
|
||||
end,
|
||||
on_metadata_inventory_take = function(pos)
|
||||
update_entity(pos)
|
||||
end,
|
||||
after_destruct = function(pos)
|
||||
update_entity(pos)
|
||||
end,
|
||||
on_blast = function(pos, _, do_drop)
|
||||
local object = get_stand_object(pos)
|
||||
if object then
|
||||
object:remove()
|
||||
end
|
||||
minetest.after(1, function(pos)
|
||||
update_entity(pos)
|
||||
end, pos)
|
||||
minetest.remove_node(pos)
|
||||
if do_drop then
|
||||
minetest.add_item(pos, "mcl_armor_stand:armor_stand")
|
||||
end
|
||||
return mcl_armor.equip(itemstack, get_stand_entity(pos, node).object, true)
|
||||
end,
|
||||
on_rotate = function(pos, node, user, mode)
|
||||
if mode == screwdriver.ROTATE_FACE then
|
||||
node.param2 = (node.param2 + 1) % 4
|
||||
minetest.swap_node(pos, node)
|
||||
update_entity(pos)
|
||||
get_stand_entity(pos, node):update_rotation(node)
|
||||
return true
|
||||
end
|
||||
return false
|
||||
@ -248,6 +95,7 @@ minetest.register_node("mcl_armor_stand:armor_stand", {
|
||||
})
|
||||
|
||||
minetest.register_entity("mcl_armor_stand:armor_entity", {
|
||||
initial_properties = {
|
||||
physical = true,
|
||||
visual = "mesh",
|
||||
mesh = "3d_armor_entity.obj",
|
||||
@ -255,43 +103,36 @@ minetest.register_entity("mcl_armor_stand:armor_entity", {
|
||||
collisionbox = {-0.1,-0.4,-0.1, 0.1,1.3,0.1},
|
||||
pointable = false,
|
||||
textures = {"blank.png"},
|
||||
pos = nil,
|
||||
timer = 0,
|
||||
static_save = false,
|
||||
},
|
||||
on_activate = function(self)
|
||||
local pos = self.object:get_pos()
|
||||
self.object:set_armor_groups({immortal = 1})
|
||||
if pos then
|
||||
self.pos = vector.round(pos)
|
||||
update_entity(pos)
|
||||
end
|
||||
self.node_pos = vector.round(self.object:get_pos())
|
||||
self.inventory = minetest.get_meta(self.node_pos):get_inventory()
|
||||
migrate_inventory(self.inventory)
|
||||
mcl_armor.update(self.object)
|
||||
end,
|
||||
on_step = function(self, dtime)
|
||||
if not self.pos then
|
||||
return
|
||||
end
|
||||
self.timer = self.timer + dtime
|
||||
if self.timer > 1 then
|
||||
self.timer = 0
|
||||
local pos = self.object:get_pos()
|
||||
if pos then
|
||||
if vector.equals(vector.round(pos), self.pos) then
|
||||
return
|
||||
end
|
||||
end
|
||||
update_entity(self.pos)
|
||||
if minetest.get_node(self.node_pos).name ~= "mcl_armor_stand:armor_stand" then
|
||||
self.object:remove()
|
||||
end
|
||||
end,
|
||||
update_armor = function(self, info)
|
||||
self.object:set_properties({textures = {info.texture}})
|
||||
end,
|
||||
update_rotation = function(self, node)
|
||||
self.object:set_yaw(minetest.dir_to_yaw(minetest.facedir_to_dir(node.param2)))
|
||||
end,
|
||||
})
|
||||
|
||||
-- FIXME: Armor helper entity can get destroyed by /clearobjects
|
||||
minetest.register_lbm({
|
||||
label = "Respawn armor stand entities",
|
||||
name = "mcl_armor_stand:respawn_entities",
|
||||
nodenames = {"mcl_armor_stand:armor_stand"},
|
||||
run_at_every_load = true,
|
||||
action = function(pos, node)
|
||||
update_entity(pos, node)
|
||||
spawn_stand_entity(pos, node)
|
||||
end,
|
||||
})
|
||||
|
||||
@ -304,7 +145,6 @@ minetest.register_craft({
|
||||
}
|
||||
})
|
||||
|
||||
|
||||
-- Legacy handling
|
||||
minetest.register_alias("3d_armor_stand:armor_stand", "mcl_armor_stand:armor_stand")
|
||||
minetest.register_entity(":3d_armor_stand:armor_entity", {
|
||||
|
@ -69,6 +69,7 @@ local ARROW_ENTITY={
|
||||
_stuckrechecktimer=nil,-- An additional timer for periodically re-checking the stuck status of an arrow
|
||||
_stuckin=nil, --Position of node in which arow is stuck.
|
||||
_shooter=nil, -- ObjectRef of player or mob who shot it
|
||||
_is_arrow = true,
|
||||
|
||||
_viscosity=0, -- Viscosity of node the arrow is currently in
|
||||
_deflection_cooloff=0, -- Cooloff timer after an arrow deflection, to prevent many deflections in quick succession
|
||||
@ -254,9 +255,6 @@ ARROW_ENTITY.on_step = function(self, dtime)
|
||||
|
||||
-- Punch target object but avoid hurting enderman.
|
||||
if not lua or lua.name ~= "mobs_mc:enderman" then
|
||||
if obj:is_player() and rawget(_G, "armor") and armor.last_damage_types then
|
||||
armor.last_damage_types[obj:get_player_name()] = "projectile"
|
||||
end
|
||||
if self._in_player == false then
|
||||
damage_particles(self.object:get_pos(), self._is_critical)
|
||||
end
|
||||
|
@ -59,6 +59,7 @@ mcl_bows.shoot_arrow = function(arrow_item, pos, dir, yaw, shooter, power, damag
|
||||
obj:set_yaw(yaw-math.pi/2)
|
||||
local le = obj:get_luaentity()
|
||||
le._shooter = shooter
|
||||
le._source_object = shooter
|
||||
le._damage = damage
|
||||
le._is_critical = is_critical
|
||||
le._startpos = pos
|
||||
|
@ -203,7 +203,7 @@ S("• When lava is directly above water, the water turns into stone."),
|
||||
_mcl_node_death_message = lava_death_messages,
|
||||
post_effect_color = {a=245, r=208, g=73, b=10},
|
||||
stack_max = 64,
|
||||
groups = { lava=3, lava_source=1, liquid=2, destroys_items=1, not_in_creative_inventory=1, dig_by_piston=1, set_on_fire=15},
|
||||
groups = { lava=3, lava_source=1, liquid=2, destroys_items=1, not_in_creative_inventory=1, dig_by_piston=1, set_on_fire=15, fire_damage=1},
|
||||
_mcl_blast_resistance = 100,
|
||||
-- Hardness intentionally set to infinite instead of 100 (Minecraft value) to avoid problems in creative mode
|
||||
_mcl_hardness = -1,
|
||||
|
@ -10,25 +10,6 @@ local function increase_damage(damage_group, factor)
|
||||
end
|
||||
end
|
||||
|
||||
-- requires engine change
|
||||
--[[mcl_enchanting.enchantments.aqua_affinity = {
|
||||
name = S("Aqua Affinity"),
|
||||
max_level = 1,
|
||||
primary = {armor_head = true},
|
||||
secondary = {},
|
||||
disallow = {non_combat_armor = true},
|
||||
incompatible = {},
|
||||
weight = 2,
|
||||
description = S("Increases underwater mining speed."),
|
||||
curse = false,
|
||||
on_enchant = function() end,
|
||||
requires_tool = false,
|
||||
treasure = false,
|
||||
power_range_table = {{1, 41}},
|
||||
inv_combat_tab = true,
|
||||
inv_tool_tab = false,
|
||||
}]]--
|
||||
|
||||
-- implemented via on_enchant and additions in mobs_mc; Slowness IV part unimplemented
|
||||
mcl_enchanting.enchantments.bane_of_arthropods = {
|
||||
name = S("Bane of Arthropods"),
|
||||
@ -48,25 +29,6 @@ mcl_enchanting.enchantments.bane_of_arthropods = {
|
||||
inv_tool_tab = false,
|
||||
}
|
||||
|
||||
-- implemented in mcl_armor
|
||||
mcl_enchanting.enchantments.blast_protection = {
|
||||
name = S("Blast Protection"),
|
||||
max_level = 4,
|
||||
primary = {armor_head = true, armor_torso = true, armor_legs = true, armor_feet = true},
|
||||
secondary = {},
|
||||
disallow = {non_combat_armor = true},
|
||||
incompatible = {fire_protection = true, protection = true, projectile_protection = true},
|
||||
weight = 2,
|
||||
description = S("Reduces explosion damage and knockback."),
|
||||
curse = false,
|
||||
on_enchant = function() end,
|
||||
requires_tool = false,
|
||||
treasure = false,
|
||||
power_range_table = {{5, 13}, {13, 21}, {21, 29}, {29, 37}},
|
||||
inv_combat_tab = true,
|
||||
inv_tool_tab = false,
|
||||
}
|
||||
|
||||
-- requires missing MineClone2 feature
|
||||
--[[mcl_enchanting.enchantments.channeling = {
|
||||
name = S("Channeling"),
|
||||
@ -86,25 +48,6 @@ mcl_enchanting.enchantments.blast_protection = {
|
||||
inv_tool_tab = false,
|
||||
}]]--
|
||||
|
||||
-- implemented in mcl_armor
|
||||
mcl_enchanting.enchantments.curse_of_binding = {
|
||||
name = S("Curse of Binding"),
|
||||
max_level = 1,
|
||||
primary = {},
|
||||
secondary = {armor_head = true, armor_torso = true, armor_legs = true, armor_feet = true},
|
||||
disallow = {},
|
||||
incompatible = {},
|
||||
weight = 1,
|
||||
description = S("Item cannot be removed from armor slots except due to death, breaking or in Creative Mode."),
|
||||
curse = true,
|
||||
on_enchant = function() end,
|
||||
requires_tool = false,
|
||||
treasure = true,
|
||||
power_range_table = {{25, 50}},
|
||||
inv_combat_tab = true,
|
||||
inv_tool_tab = false,
|
||||
}
|
||||
|
||||
-- implemented in mcl_death_drop
|
||||
mcl_enchanting.enchantments.curse_of_vanishing = {
|
||||
name = S("Curse of Vanishing"),
|
||||
@ -164,24 +107,6 @@ mcl_enchanting.enchantments.efficiency = {
|
||||
inv_tool_tab = true,
|
||||
}
|
||||
|
||||
-- implemented in mcl_armor
|
||||
mcl_enchanting.enchantments.feather_falling = {
|
||||
name = S("Feather Falling"),
|
||||
max_level = 4,
|
||||
primary = {armor_feet = true},
|
||||
secondary = {},
|
||||
disallow = {non_combat_armor = true},
|
||||
incompatible = {},
|
||||
weight = 5,
|
||||
description = S("Reduces fall damage."),curse = false,
|
||||
on_enchant = function() end,
|
||||
requires_tool = false,
|
||||
treasure = false,
|
||||
power_range_table = {{5, 11}, {11, 17}, {17, 23}, {23, 29}},
|
||||
inv_combat_tab = true,
|
||||
inv_tool_tab = false,
|
||||
}
|
||||
|
||||
-- implemented in mcl_mobs and via register_on_punchplayer callback
|
||||
mcl_enchanting.enchantments.fire_aspect = {
|
||||
name = S("Fire Aspect"),
|
||||
@ -207,31 +132,12 @@ minetest.register_on_punchplayer(function(player, hitter, time_from_last_punch,
|
||||
if wielditem then
|
||||
local fire_aspect_level = mcl_enchanting.get_enchantment(wielditem, "fire_aspect")
|
||||
if fire_aspect_level > 0 then
|
||||
mcl_burning.set_on_fire(player, fire_aspect_level * 4, hitter:get_player_name())
|
||||
mcl_burning.set_on_fire(player, fire_aspect_level * 4)
|
||||
end
|
||||
end
|
||||
end
|
||||
end)
|
||||
|
||||
-- implemented in mcl_armor
|
||||
mcl_enchanting.enchantments.fire_protection = {
|
||||
name = S("Fire Protection"),
|
||||
max_level = 4,
|
||||
primary = {armor_head = true, armor_torso = true, armor_legs = true, armor_feet = true},
|
||||
secondary = {},
|
||||
disallow = {non_combat_armor = true},
|
||||
incompatible = {blast_protection = true, protection = true, projectile_protection = true},
|
||||
weight = 5,
|
||||
description = S("Reduces fire damage."),
|
||||
curse = false,
|
||||
on_enchant = function() end,
|
||||
requires_tool = false,
|
||||
treasure = false,
|
||||
power_range_table = {{10, 18}, {18, 26}, {26, 34}, {34, 42}},
|
||||
inv_combat_tab = true,
|
||||
inv_tool_tab = false,
|
||||
}
|
||||
|
||||
mcl_enchanting.enchantments.flame = {
|
||||
name = S("Flame"),
|
||||
max_level = 1,
|
||||
@ -530,44 +436,6 @@ mcl_enchanting.enchantments.power = {
|
||||
inv_tool_tab = false,
|
||||
}
|
||||
|
||||
-- implemented in mcl_armor
|
||||
mcl_enchanting.enchantments.projectile_protection = {
|
||||
name = S("Projectile Protection"),
|
||||
max_level = 4,
|
||||
primary = {armor_head = true, armor_torso = true, armor_legs = true, armor_feet = true},
|
||||
secondary = {},
|
||||
disallow = {non_combat_armor = true},
|
||||
incompatible = {blast_protection = true, fire_protection = true, protection = true},
|
||||
weight = 5,
|
||||
description = S("Reduces projectile damage."),
|
||||
curse = false,
|
||||
on_enchant = function() end,
|
||||
requires_tool = false,
|
||||
treasure = false,
|
||||
power_range_table = {{1, 16}, {11, 26}, {21, 36}, {31, 46}, {41, 56}},
|
||||
inv_combat_tab = true,
|
||||
inv_tool_tab = false,
|
||||
}
|
||||
|
||||
-- implemented in mcl_armor
|
||||
mcl_enchanting.enchantments.protection = {
|
||||
name = S("Protection"),
|
||||
max_level = 4,
|
||||
primary = {armor_head = true, armor_torso = true, armor_legs = true, armor_feet = true},
|
||||
secondary = {},
|
||||
disallow = {non_combat_armor = true},
|
||||
incompatible = {blast_protection = true, fire_protection = true, projectile_protection = true},
|
||||
weight = 10,
|
||||
description = S("Reduces most types of damage by 4% for each level."),
|
||||
curse = false,
|
||||
on_enchant = function() end,
|
||||
requires_tool = false,
|
||||
treasure = false,
|
||||
power_range_table = {{1, 12}, {12, 23}, {23, 34}, {34, 45}},
|
||||
inv_combat_tab = true,
|
||||
inv_tool_tab = false,
|
||||
}
|
||||
|
||||
-- implemented via minetest.calculate_knockback (together with the Knockback enchantment) and mcl_bows
|
||||
mcl_enchanting.enchantments.punch = {
|
||||
name = S("Punch"),
|
||||
@ -739,25 +607,6 @@ mcl_enchanting.enchantments.soul_speed = {
|
||||
inv_tool_tab = false,
|
||||
}]]--
|
||||
|
||||
-- implemented in mcl_armor
|
||||
mcl_enchanting.enchantments.thorns = {
|
||||
name = S("Thorns"),
|
||||
max_level = 3,
|
||||
primary = {armor_head = true},
|
||||
secondary = {armor_torso = true, armor_legs = true, armor_feet = true},
|
||||
disallow = {non_combat_armor = true},
|
||||
incompatible = {},
|
||||
weight = 1,
|
||||
description = S("Reflects some of the damage taken when hit, at the cost of reducing durability with each proc."),
|
||||
curse = false,
|
||||
on_enchant = function() end,
|
||||
requires_tool = false,
|
||||
treasure = false,
|
||||
power_range_table = {{10, 61}, {30, 71}, {50, 81}},
|
||||
inv_combat_tab = true,
|
||||
inv_tool_tab = false,
|
||||
}
|
||||
|
||||
-- for tools & weapons implemented via on_enchant; for bows implemented in mcl_bows; for armor implemented in mcl_armor and mcl_tt; for fishing rods implemented in mcl_fishing
|
||||
mcl_enchanting.enchantments.unbreaking = {
|
||||
name = S("Unbreaking"),
|
||||
|
@ -267,7 +267,8 @@ function mcl_enchanting.initialize()
|
||||
new_def.groups.not_in_creative_inventory = 1
|
||||
new_def.groups.not_in_craft_guide = 1
|
||||
new_def.groups.enchanted = 1
|
||||
new_def.texture = itemdef.texture or itemname:gsub("%:", "_")
|
||||
new_def._mcl_armor_texture = new_def._mcl_armor_texture and new_def._mcl_armor_texture .. mcl_enchanting.overlay
|
||||
new_def._mcl_armor_preview = new_def._mcl_armor_preview and new_def._mcl_armor_preview .. mcl_enchanting.overlay
|
||||
new_def._mcl_enchanting_enchanted_tool = new_name
|
||||
new_def.after_use = get_after_use_callback(itemdef)
|
||||
local register_list = register_item_list
|
||||
|
@ -111,12 +111,16 @@ pumpkin_face_base_def.description = S("Pumpkin")
|
||||
pumpkin_face_base_def._doc_items_longdesc = S("A pumpkin can be worn as a helmet. Pumpkins grow from pumpkin stems, which in turn grow from pumpkin seeds.")
|
||||
pumpkin_face_base_def._doc_items_usagehelp = nil
|
||||
pumpkin_face_base_def.tiles = {"farming_pumpkin_top.png", "farming_pumpkin_top.png", "farming_pumpkin_side.png", "farming_pumpkin_side.png", "farming_pumpkin_side.png", "farming_pumpkin_face.png"}
|
||||
pumpkin_face_base_def.groups.armor=1
|
||||
pumpkin_face_base_def.groups.non_combat_armor=1
|
||||
pumpkin_face_base_def.groups.armor_head=1
|
||||
pumpkin_face_base_def.groups.non_combat_armor_head=1
|
||||
pumpkin_face_base_def._mcl_armor_mob_range_factor = 0
|
||||
pumpkin_face_base_def._mcl_armor_mob_range_mob = "mobs_mc:enderman"
|
||||
pumpkin_face_base_def._mcl_armor_entry = "head"
|
||||
pumpkin_face_base_def.groups.non_combat_armor=1
|
||||
if minetest.get_modpath("mcl_armor") then
|
||||
pumpkin_face_base_def.on_secondary_use = armor.on_armor_use
|
||||
pumpkin_face_base_def.on_secondary_use = mcl_armor.equip_on_use
|
||||
end
|
||||
|
||||
-- Register stem growth
|
||||
|
@ -5,7 +5,7 @@ local mod_screwdriver = minetest.get_modpath("screwdriver")
|
||||
|
||||
local equip_armor
|
||||
if minetest.get_modpath("mcl_armor") then
|
||||
equip_armor = armor.on_armor_use
|
||||
equip_armor = mcl_armor.equip_on_use
|
||||
end
|
||||
|
||||
-- Heads system
|
||||
@ -42,7 +42,7 @@ local function addhead(name, texture, desc, longdesc, rangemob, rangefactor)
|
||||
{ -0.25, -0.5, -0.25, 0.25, 0.0, 0.25, },
|
||||
},
|
||||
},
|
||||
groups = {handy=1, armor_head=1,non_combat_armor=1, head=1, deco_block=1, dig_by_piston=1 },
|
||||
groups = {handy = 1, armor = 1, armor_head = 1, non_combat_armor = 1, non_combat_armor_head = 1, head = 1, deco_block = 1, dig_by_piston = 1},
|
||||
-- The head textures are based off the textures of an actual mob.
|
||||
tiles = {
|
||||
-- Note: bottom texture is overlaid over top texture to get rid of possible transparency.
|
||||
@ -111,6 +111,7 @@ local function addhead(name, texture, desc, longdesc, rangemob, rangefactor)
|
||||
|
||||
_mcl_armor_mob_range_mob = rangemob,
|
||||
_mcl_armor_mob_range_factor = rangefactor,
|
||||
_mcl_armor_element = "head",
|
||||
_mcl_blast_resistance = 1,
|
||||
_mcl_hardness = 1,
|
||||
})
|
||||
|
@ -1,6 +1,5 @@
|
||||
local S = minetest.get_translator("mcl_nether")
|
||||
|
||||
local mod_death_messages = minetest.get_modpath("mcl_death_messages")
|
||||
local mod_screwdriver = minetest.get_modpath("screwdriver") ~= nil
|
||||
local on_rotate
|
||||
if mod_screwdriver then
|
||||
@ -111,10 +110,7 @@ minetest.register_node("mcl_nether:magma", {
|
||||
end
|
||||
-- Hurt players standing on top of this block
|
||||
if player:get_hp() > 0 then
|
||||
if mod_death_messages then
|
||||
mcl_death_messages.player_damage(player, S("@1 stood too long on a magma block.", player:get_player_name()))
|
||||
end
|
||||
player:set_hp(player:get_hp() - 1, { type = "punch", from = "mod" })
|
||||
mcl_util.deal_damage(player, 1, {type = "hot_floor"})
|
||||
end
|
||||
end,
|
||||
_mcl_blast_resistance = 0.5,
|
||||
|
@ -1,3 +1,3 @@
|
||||
name = mcl_nether
|
||||
depends = mcl_core, mcl_sounds, mcl_util, walkover, doc_items, mcl_colors
|
||||
optional_depends = mcl_death_messages, doc, screwdriver
|
||||
optional_depends = doc, screwdriver
|
||||
|
@ -132,17 +132,10 @@ minetest.register_globalstep(function(dtime)
|
||||
if player:get_pos() then mcl_potions._add_spawner(player, "#225533") end
|
||||
|
||||
if EF.poisoned[player].hit_timer >= EF.poisoned[player].step then
|
||||
|
||||
if entity and entity._cmi_is_mob then
|
||||
entity.health = math.max(entity.health - 1, 1)
|
||||
EF.poisoned[player].hit_timer = 0
|
||||
elseif is_player then
|
||||
player:set_hp( math.max(player:get_hp() - 1, 1), { type = "punch", other = "poison"})
|
||||
EF.poisoned[player].hit_timer = 0
|
||||
else -- if not player or mob then remove
|
||||
EF.poisoned[player] = nil
|
||||
if mcl_util.get_hp(player) - 1 > 0 then
|
||||
mcl_util.deal_damage(player, 1, {type = "magic"})
|
||||
end
|
||||
|
||||
EF.poisoned[player].hit_timer = 0
|
||||
end
|
||||
|
||||
if EF.poisoned[player] and EF.poisoned[player].timer >= EF.poisoned[player].dur then
|
||||
@ -351,37 +344,12 @@ minetest.register_globalstep(function(dtime)
|
||||
|
||||
end)
|
||||
|
||||
|
||||
local is_fire_node = { ["mcl_core:lava_flowing"]=true,
|
||||
["mcl_core:lava_source"]=true,
|
||||
["mcl_fire:eternal_fire"]=true,
|
||||
["mcl_fire:fire"]=true,
|
||||
["mcl_nether:magma"]=true,
|
||||
["mcl_nether:nether_lava_source"]=true,
|
||||
["mcl_nether:nether_lava_flowing"]=true,
|
||||
["mcl_nether:nether_lava_source"]=true
|
||||
}
|
||||
|
||||
-- Prevent damage to player with Fire Resistance enabled
|
||||
minetest.register_on_player_hpchange(function(player, hp_change, reason)
|
||||
|
||||
if EF.fire_proof[player] and hp_change < 0 then
|
||||
-- This is a bit forced, but it assumes damage is taken by fire and avoids it
|
||||
-- also assumes any change in hp happens between calls to this function
|
||||
-- it's worth noting that you don't take damage from players in this case...
|
||||
local player_info = mcl_playerinfo[player:get_player_name()]
|
||||
|
||||
if is_fire_node[player_info.node_head] or is_fire_node[player_info.node_feet] or is_fire_node[player_info.node_stand] then
|
||||
mcl_damage.register_modifier(function(obj, damage, reason)
|
||||
if EF.fire_proof[obj] and not reason.flags.bypasses_magic and reason.flags.is_fire then
|
||||
return 0
|
||||
else
|
||||
return hp_change
|
||||
end
|
||||
|
||||
else
|
||||
return hp_change
|
||||
end
|
||||
|
||||
end, true)
|
||||
end, -50)
|
||||
|
||||
|
||||
|
||||
@ -603,21 +571,18 @@ function mcl_potions.make_invisible(player, toggle)
|
||||
return
|
||||
end
|
||||
|
||||
if minetest.get_modpath("mcl_armor") and player:is_player() then
|
||||
armor.textures[playername].skin = skin_file
|
||||
armor:update_player_visuals(player)
|
||||
elseif not player:is_player() and minetest.get_modpath("mcl_armor") or not player:is_player() and not minetest.get_modpath("mcl_armor") then
|
||||
if player:is_player() then
|
||||
mcl_player.player_set_skin(player, "mobs_mc_empty.png")
|
||||
elseif not player:is_player() then
|
||||
player:set_properties({visual_size = {x = 0, y = 0}})
|
||||
end
|
||||
player:set_nametag_attributes({color = {a = 0}})
|
||||
|
||||
elseif EF.invisible[player] then -- show player
|
||||
|
||||
if minetest.get_modpath("mcl_armor") and player:is_player() then
|
||||
skin_file = mcl_skins.skins[playername] .. ".png"
|
||||
armor.textures[playername].skin = skin_file
|
||||
armor:update_player_visuals(player)
|
||||
elseif not player:is_player() and minetest.get_modpath("mcl_armor") or not player:is_player() and not minetest.get_modpath("mcl_armor") then
|
||||
if player:is_player() then
|
||||
mcl_skins.update_player_skin(player)
|
||||
elseif not player:is_player() then
|
||||
player:set_properties({visual_size = EF.invisible[player].old_size})
|
||||
end
|
||||
player:set_nametag_attributes({color = {r = 255, g = 255, b = 255, a = 255}})
|
||||
@ -724,12 +689,7 @@ function mcl_potions.healing_func(player, hp)
|
||||
hp = -1
|
||||
end
|
||||
|
||||
if obj and obj._cmi_is_mob then
|
||||
obj.health = obj.health + hp
|
||||
elseif player:is_player() then
|
||||
player:set_hp(player:get_hp() + hp, { type = "punch", other = "harming" })
|
||||
end
|
||||
|
||||
mcl_util.deal_damage(obj, -hp, {type = "magic"})
|
||||
end
|
||||
|
||||
end
|
||||
|
@ -1,3 +1,3 @@
|
||||
name = mcl_tnt
|
||||
depends = mcl_explosions, mcl_particles
|
||||
optional_depends = mcl_sounds, mcl_mobitems, mcl_death_messages, doc_identifier, mesecons
|
||||
optional_depends = mcl_sounds, mcl_mobitems, doc_identifier, mesecons
|
||||
|
@ -1,5 +1,58 @@
|
||||
-- Node is currently defined in mobs_mc.
|
||||
-- TODO: Add full item definition here when status effects become a thing.
|
||||
local hud_totem = {}
|
||||
|
||||
-- Add group for Creative Mode.
|
||||
minetest.override_item("mobs_mc:totem", {groups = { combat_item=1}})
|
||||
minetest.register_on_leaveplayer(function(player)
|
||||
hud_totem[player] = nil
|
||||
end)
|
||||
|
||||
-- Save the player from death when holding totem of undying in hand
|
||||
mcl_damage.register_modifier(function(obj, damage, reason)
|
||||
if obj:is_player() then
|
||||
local hp = obj:get_hp()
|
||||
if hp - damage <= 0 then
|
||||
local wield = obj:get_wielded_item()
|
||||
if wield:get_name() == "mobs_mc:totem" then
|
||||
local ppos = obj:get_pos()
|
||||
local pnname = minetest.get_node(ppos).name
|
||||
-- Some exceptions when _not_ to save the player
|
||||
for n=1, #mobs_mc.misc.totem_fail_nodes do
|
||||
if pnname == mobs_mc.misc.totem_fail_nodes[n] then
|
||||
return
|
||||
end
|
||||
end
|
||||
-- Reset breath as well
|
||||
if obj:get_breath() < 11 then
|
||||
obj:set_breath(10)
|
||||
end
|
||||
|
||||
if not minetest.is_creative_enabled(obj:get_player_name()) then
|
||||
wield:take_item()
|
||||
obj:set_wielded_item(wield)
|
||||
end
|
||||
|
||||
-- Effects
|
||||
minetest.sound_play({name = "mcl_totems_totem", gain=1}, {pos=ppos, max_hear_distance=16}, true)
|
||||
|
||||
-- Big totem overlay
|
||||
if not hud_totem[obj] then
|
||||
hud_totem[obj] = obj:hud_add({
|
||||
hud_elem_type = "image",
|
||||
text = "mcl_totems_totem.png",
|
||||
position = { x=0.5, y=1 },
|
||||
scale = { x=17, y=17 },
|
||||
offset = { x=0, y=-178 },
|
||||
z_index = 100,
|
||||
})
|
||||
minetest.after(3, function()
|
||||
if obj:is_player() then
|
||||
obj:hud_remove(hud_totem[obj])
|
||||
hud_totem[obj] = nil
|
||||
end
|
||||
end)
|
||||
end
|
||||
|
||||
-- Set HP to exactly 1
|
||||
return hp - 1
|
||||
end
|
||||
end
|
||||
end
|
||||
end, 1000)
|
||||
|
@ -1,2 +1,2 @@
|
||||
name = mcl_totems
|
||||
depends = mobs_mc
|
||||
depends = mobs_mc, mcl_damage
|
||||
|
@ -1,5 +1,4 @@
|
||||
local S = minetest.get_translator("mcl_commands")
|
||||
local mod_death_messages = minetest.get_modpath("mcl_death_messages")
|
||||
|
||||
local function handle_kill_command(suspect, victim)
|
||||
if minetest.settings:get_bool("enable_damage") == false then
|
||||
@ -21,17 +20,8 @@ local function handle_kill_command(suspect, victim)
|
||||
if wield:get_name() == "mobs_mc:totem" then
|
||||
victimref:set_wielded_item("")
|
||||
end
|
||||
if mod_death_messages then
|
||||
local msg
|
||||
if suspect == victim then
|
||||
msg = S("@1 committed suicide.", victim)
|
||||
else
|
||||
msg = S("@1 was killed by @2.", victim, suspect)
|
||||
end
|
||||
mcl_death_messages.player_damage(victimref, msg)
|
||||
end
|
||||
-- DIE!
|
||||
victimref:set_hp(0)
|
||||
victimref:set_hp(0, {_mcl_type = "out_of_world"})
|
||||
-- Log
|
||||
if not suspect == victim then
|
||||
minetest.log("action", string.format("%s killed %s using /kill", suspect, victim))
|
||||
|
@ -1,4 +1,3 @@
|
||||
name = mcl_commands
|
||||
author = Wuzzy
|
||||
description = MCL2 commands
|
||||
optional_depends = mcl_death_messages
|
||||
|
30
mods/PLAYER/mcl_criticals/init.lua
Normal file
30
mods/PLAYER/mcl_criticals/init.lua
Normal file
@ -0,0 +1,30 @@
|
||||
mcl_damage.register_modifier(function(obj, damage, reason)
|
||||
if reason.type == "player" then
|
||||
local hitter = reason.direct
|
||||
if mcl_sprint.is_sprinting(hitter) then
|
||||
obj:add_velocity(hitter:get_velocity())
|
||||
elseif (hitter:get_velocity() or hitter:get_player_velocity()).y < 0 then
|
||||
local pos = mcl_util.get_object_center(obj)
|
||||
minetest.add_particlespawner({
|
||||
amount = 15,
|
||||
time = 0.1,
|
||||
minpos = {x=pos.x-0.5, y=pos.y-0.5, z=pos.z-0.5},
|
||||
maxpos = {x=pos.x+0.5, y=pos.y+0.5, z=pos.z+0.5},
|
||||
minvel = {x=-0.1, y=-0.1, z=-0.1},
|
||||
maxvel = {x=0.1, y=0.1, z=0.1},
|
||||
minacc = {x=0, y=0, z=0},
|
||||
maxacc = {x=0, y=0, z=0},
|
||||
minexptime = 1,
|
||||
maxexptime = 2,
|
||||
minsize = 1.5,
|
||||
maxsize = 1.5,
|
||||
collisiondetection = false,
|
||||
vertical = false,
|
||||
texture = "mcl_particles_crit.png^[colorize:#bc7a57:127",
|
||||
})
|
||||
minetest.sound_play("mcl_criticals_hit", {object = obj})
|
||||
-- the minecraft wiki is actually wrong about a crit dealing 150% damage, see minecraft source code
|
||||
return damage + math.random(0, math.floor(damage * 1.5 + 2))
|
||||
end
|
||||
end
|
||||
end, -100)
|
2
mods/PLAYER/mcl_criticals/mod.conf
Normal file
2
mods/PLAYER/mcl_criticals/mod.conf
Normal file
@ -0,0 +1,2 @@
|
||||
name = mcl_criticals
|
||||
depends = mcl_damage
|
BIN
mods/PLAYER/mcl_criticals/sounds/mcl_criticals_hit.0.ogg
Normal file
BIN
mods/PLAYER/mcl_criticals/sounds/mcl_criticals_hit.0.ogg
Normal file
Binary file not shown.
BIN
mods/PLAYER/mcl_criticals/sounds/mcl_criticals_hit.1.ogg
Normal file
BIN
mods/PLAYER/mcl_criticals/sounds/mcl_criticals_hit.1.ogg
Normal file
Binary file not shown.
BIN
mods/PLAYER/mcl_criticals/sounds/mcl_criticals_hit.2.ogg
Normal file
BIN
mods/PLAYER/mcl_criticals/sounds/mcl_criticals_hit.2.ogg
Normal file
Binary file not shown.
@ -11,7 +11,6 @@ end
|
||||
mcl_death_drop.register_dropped_list("PLAYER", "main", true)
|
||||
mcl_death_drop.register_dropped_list("PLAYER", "craft", true)
|
||||
mcl_death_drop.register_dropped_list("PLAYER", "armor", true)
|
||||
mcl_death_drop.register_dropped_list(function(player) return select(3, armor:get_valid_player(player)) end , "armor", false)
|
||||
|
||||
minetest.register_on_dieplayer(function(player)
|
||||
local keep = minetest.settings:get_bool("mcl_keepInventory", false)
|
||||
@ -50,7 +49,6 @@ minetest.register_on_dieplayer(function(player)
|
||||
inv:set_list(listname, {})
|
||||
end
|
||||
end
|
||||
armor:set_player_armor(player)
|
||||
armor:update_inventory(player)
|
||||
mcl_armor.update(player)
|
||||
end
|
||||
end)
|
||||
|
@ -1,5 +1,4 @@
|
||||
local S = minetest.get_translator("mcl_hunger")
|
||||
local mod_death_messages = minetest.get_modpath("mcl_death_messages")
|
||||
|
||||
-- wrapper for minetest.item_eat (this way we make sure other mods can't break this one)
|
||||
minetest.do_item_eat = function(hp_change, replace_with_item, itemstack, user, pointed_thing)
|
||||
@ -110,10 +109,7 @@ local function poisonp(tick, time, time_left, damage, exhaustion, name)
|
||||
-- Deal damage and exhaust player
|
||||
-- TODO: Introduce fatal poison at higher difficulties
|
||||
if player:get_hp()-damage > 0 then
|
||||
if mod_death_messages then
|
||||
mcl_death_messages.player_damage(player, S("@1 succumbed to the poison.", name))
|
||||
end
|
||||
player:set_hp(player:get_hp()-damage)
|
||||
mcl_util.deal_damage(player, damage, {type = "hunger"})
|
||||
end
|
||||
|
||||
mcl_hunger.exhaust(name, exhaustion)
|
||||
|
@ -1,5 +1,4 @@
|
||||
local S = minetest.get_translator("mcl_hunger")
|
||||
local mod_death_messages = minetest.get_modpath("mcl_death_messages")
|
||||
|
||||
mcl_hunger = {}
|
||||
|
||||
@ -159,10 +158,7 @@ minetest.register_globalstep(function(dtime)
|
||||
-- Damage hungry player down to 1 HP
|
||||
-- TODO: Allow starvation at higher difficulty levels
|
||||
if hp-1 > 0 then
|
||||
if mod_death_messages then
|
||||
mcl_death_messages.player_damage(player, S("@1 starved to death.", name))
|
||||
end
|
||||
player:set_hp(hp-1)
|
||||
mcl_util.deal_damage(player, 1, {type = "starve"})
|
||||
end
|
||||
end
|
||||
end
|
||||
|
@ -2,4 +2,3 @@ name = mcl_hunger
|
||||
author = BlockMen
|
||||
description = Adds a simple hunger meachanic with satiation, food poisoning and different healing.
|
||||
depends = hudbars
|
||||
optional_depends = mcl_death_messages
|
||||
|
@ -88,22 +88,41 @@ function mcl_player.player_set_model(player, model_name)
|
||||
player_model[name] = model_name
|
||||
end
|
||||
|
||||
function mcl_player.player_set_textures(player, textures, preview)
|
||||
local name = player:get_player_name()
|
||||
player_textures[name] = textures
|
||||
player:set_properties({textures = textures,})
|
||||
if preview then
|
||||
player:get_meta():set_string("mcl_player:preview", preview)
|
||||
local function set_texture(player, index, texture)
|
||||
local textures = player_textures[player:get_player_name()]
|
||||
textures[index] = texture
|
||||
player:set_properties({textures = textures})
|
||||
end
|
||||
|
||||
local function set_preview(player, field, preview)
|
||||
player:get_meta():set_string("mcl_player:" .. field .. "_preview", preview)
|
||||
end
|
||||
|
||||
function mcl_player.player_set_skin(player, texture, preview)
|
||||
set_texture(player, 1, texture)
|
||||
set_preview(player, "skin", preview)
|
||||
end
|
||||
|
||||
function mcl_player.player_set_armor(player, texture, preview)
|
||||
set_texture(player, 2, texture)
|
||||
set_preview(player, "armor", preview)
|
||||
end
|
||||
|
||||
function mcl_player.player_set_wielditem(player, texture)
|
||||
set_texture(player, 3, texture)
|
||||
end
|
||||
|
||||
function mcl_player.player_get_preview(player)
|
||||
local preview = player:get_meta():get_string("mcl_player:preview")
|
||||
if preview == nil or preview == "" then
|
||||
return "player.png"
|
||||
else
|
||||
return preview
|
||||
local preview = player:get_meta():get_string("mcl_player:skin_preview")
|
||||
if preview == "" then
|
||||
preview = "player.png"
|
||||
end
|
||||
local armor_preview = player:get_meta():set_string("mcl_player:armor_preview")
|
||||
if armor_preview ~= "" then
|
||||
preview = preview .. "^" .. armor_preview
|
||||
end
|
||||
return preview
|
||||
|
||||
end
|
||||
|
||||
function mcl_player.get_player_formspec_model(player, x, y, w, h, fsname)
|
||||
@ -129,8 +148,10 @@ end
|
||||
|
||||
-- Update appearance when the player joins
|
||||
minetest.register_on_joinplayer(function(player)
|
||||
mcl_player.player_attached[player:get_player_name()] = false
|
||||
local name = player:get_player_name()
|
||||
mcl_player.player_attached[name] = false
|
||||
mcl_player.player_set_model(player, "character.b3d")
|
||||
player_textures[name] = {"blank.png", "blank.png", "blank.png"}
|
||||
--player:set_local_animation({x=0, y=79}, {x=168, y=187}, {x=189, y=198}, {x=200, y=219}, 30)
|
||||
player:set_fov(86.1) -- see <https://minecraft.gamepedia.com/Options#Video_settings>>>>
|
||||
end)
|
||||
@ -222,62 +243,3 @@ minetest.register_globalstep(function(dtime)
|
||||
end
|
||||
end
|
||||
end)
|
||||
|
||||
-- Don't change HP if the player falls in the water or through End Portal:
|
||||
minetest.register_on_player_hpchange(function(player, hp_change, reason)
|
||||
if reason and reason.type == "fall" and player then
|
||||
local pos = player:get_pos()
|
||||
local node = minetest.get_node(pos)
|
||||
local velocity = player:get_velocity() or player:get_player_velocity() or {x=0,y=-10,z=0}
|
||||
local v_axis_max = math.max(math.abs(velocity.x), math.abs(velocity.y), math.abs(velocity.z))
|
||||
local step = {x = velocity.x / v_axis_max, y = velocity.y / v_axis_max, z = velocity.z / v_axis_max}
|
||||
for i = 1, math.ceil(v_axis_max/5)+1 do -- trace at least 1/5 of the way per second
|
||||
if not node or node.name == "ignore" then
|
||||
minetest.get_voxel_manip():read_from_map(pos, pos)
|
||||
node = minetest.get_node(pos)
|
||||
end
|
||||
if node then
|
||||
if minetest.registered_nodes[node.name].walkable then
|
||||
return hp_change
|
||||
end
|
||||
if minetest.get_item_group(node.name, "water") ~= 0 then
|
||||
return 0
|
||||
end
|
||||
if node.name == "mcl_portals:portal_end" then
|
||||
if mcl_portals and mcl_portals.end_teleport then
|
||||
mcl_portals.end_teleport(player)
|
||||
end
|
||||
return 0
|
||||
end
|
||||
end
|
||||
pos = vector.add(pos, step)
|
||||
node = minetest.get_node(pos)
|
||||
end
|
||||
end
|
||||
return hp_change
|
||||
end, true)
|
||||
|
||||
minetest.register_on_respawnplayer(function(player)
|
||||
local pos = player:get_pos()
|
||||
minetest.add_particlespawner({
|
||||
amount = 50,
|
||||
time = 0.001,
|
||||
minpos = vector.add(pos, 0),
|
||||
maxpos = vector.add(pos, 0),
|
||||
minvel = vector.new(-5,-5,-5),
|
||||
maxvel = vector.new(5,5,5),
|
||||
minexptime = 1.1,
|
||||
maxexptime = 1.5,
|
||||
minsize = 1,
|
||||
maxsize = 2,
|
||||
collisiondetection = false,
|
||||
vertical = false,
|
||||
texture = "mcl_particles_mob_death.png^[colorize:#000000:255",
|
||||
})
|
||||
|
||||
minetest.sound_play("mcl_mobs_mob_poof", {
|
||||
pos = pos,
|
||||
gain = 1.0,
|
||||
max_hear_distance = 8,
|
||||
}, true)
|
||||
end)
|
||||
|
@ -1,4 +1,4 @@
|
||||
name = mcl_playerinfo
|
||||
author = TenPlus1
|
||||
description = This is a helper mod for other mod to query the nodes around the player.
|
||||
depends = mcl_init, mcl_core, mcl_particles, mcl_death_messages
|
||||
depends = mcl_init, mcl_core, mcl_particles
|
||||
|
@ -114,37 +114,6 @@ end
|
||||
|
||||
local node_stand, node_stand_below, node_head, node_feet
|
||||
|
||||
|
||||
minetest.register_on_punchplayer(function(player, hitter, damage)
|
||||
if hitter:is_player() then
|
||||
if hitter:get_player_control().aux1 then
|
||||
player:add_velocity(hitter:get_velocity())
|
||||
end
|
||||
if hitter:get_velocity().y < -6 then
|
||||
player:set_hp(player:get_hp() - (damage * math.random(0.50 , 0.75)))
|
||||
local pos = player:get_pos()
|
||||
minetest.add_particlespawner({
|
||||
amount = 15,
|
||||
time = 0.1,
|
||||
minpos = {x=pos.x-0.5, y=pos.y-0.5, z=pos.z-0.5},
|
||||
maxpos = {x=pos.x+0.5, y=pos.y+0.5, z=pos.z+0.5},
|
||||
minvel = {x=-0.1, y=-0.1, z=-0.1},
|
||||
maxvel = {x=0.1, y=0.1, z=0.1},
|
||||
minacc = {x=0, y=0, z=0},
|
||||
maxacc = {x=0, y=0, z=0},
|
||||
minexptime = 1,
|
||||
maxexptime = 2,
|
||||
minsize = 1.5,
|
||||
maxsize = 1.5,
|
||||
collisiondetection = false,
|
||||
vertical = false,
|
||||
texture = "mcl_particles_crit.png^[colorize:#bc7a57:127",
|
||||
})
|
||||
end
|
||||
end
|
||||
end)
|
||||
|
||||
|
||||
minetest.register_globalstep(function(dtime)
|
||||
|
||||
time = time + dtime
|
||||
@ -166,6 +135,7 @@ minetest.register_globalstep(function(dtime)
|
||||
local parent = player:get_attach()
|
||||
local wielded = player:get_wielded_item()
|
||||
local player_velocity = player:get_velocity() or player:get_player_velocity()
|
||||
local wielded_def = wielded:get_definition()
|
||||
|
||||
local c_x, c_y = unpack(player_collision(player))
|
||||
|
||||
@ -247,7 +217,16 @@ minetest.register_globalstep(function(dtime)
|
||||
playerphysics.remove_physics_factor(player, "gravity", "mcl_playerplus:elytra")
|
||||
end
|
||||
|
||||
if wielded_def and wielded_def._mcl_toollike_wield then
|
||||
player:set_bone_position("Wield_Item", vector.new(0,3.9,1.3), vector.new(90,0,0))
|
||||
elseif string.find(wielded:get_name(), "mcl_bows:bow") then
|
||||
player:set_bone_position("Wield_Item", vector.new(.5,4.5,-1.6), vector.new(90,0,20))
|
||||
else
|
||||
player:set_bone_position("Wield_Item", vector.new(-1.5,4.9,1.8), vector.new(135,0,90))
|
||||
end
|
||||
|
||||
player_velocity_old = player:get_velocity() or player:get_player_velocity()
|
||||
|
||||
-- controls right and left arms pitch when shooting a bow
|
||||
if string.find(wielded:get_name(), "mcl_bows:bow") and control.RMB and not control.LMB and not control.up and not control.down and not control.left and not control.right then
|
||||
player:set_bone_position("Arm_Right_Pitch_Control", vector.new(-3,5.785,0), vector.new(pitch+90,-30,pitch * -1 * .35))
|
||||
@ -421,8 +400,7 @@ minetest.register_globalstep(function(dtime)
|
||||
-- Check privilege, too
|
||||
and (not check_player_privs(name, {noclip = true})) then
|
||||
if player:get_hp() > 0 then
|
||||
mcl_death_messages.player_damage(player, S("@1 suffocated to death.", name))
|
||||
player:set_hp(player:get_hp() - 1)
|
||||
mcl_util.deal_damage(player, 1, {type = "in_wall"})
|
||||
end
|
||||
end
|
||||
|
||||
@ -437,8 +415,7 @@ minetest.register_globalstep(function(dtime)
|
||||
local dist_feet = vector.distance({x=pos.x, y=pos.y-1, z=pos.z}, near)
|
||||
if dist < 1.1 or dist_feet < 1.1 then
|
||||
if player:get_hp() > 0 then
|
||||
mcl_death_messages.player_damage(player, S("@1 was prickled to death by a cactus.", name))
|
||||
player:set_hp(player:get_hp() - 1, { type = "punch", from = "mod" })
|
||||
mcl_util.deal_damage(player, 1, {type = "cactus"})
|
||||
end
|
||||
end
|
||||
end
|
||||
@ -545,3 +522,61 @@ minetest.register_on_leaveplayer(function(player)
|
||||
mcl_playerplus_internal[name] = nil
|
||||
mcl_playerplus.elytra[player] = nil
|
||||
end)
|
||||
|
||||
-- Don't change HP if the player falls in the water or through End Portal:
|
||||
mcl_damage.register_modifier(function(obj, damage, reason)
|
||||
if reason.type == "fall" then
|
||||
local pos = obj:get_pos()
|
||||
local node = minetest.get_node(pos)
|
||||
local velocity = obj:get_velocity() or obj:get_player_velocity() or {x=0,y=-10,z=0}
|
||||
local v_axis_max = math.max(math.abs(velocity.x), math.abs(velocity.y), math.abs(velocity.z))
|
||||
local step = {x = velocity.x / v_axis_max, y = velocity.y / v_axis_max, z = velocity.z / v_axis_max}
|
||||
for i = 1, math.ceil(v_axis_max/5)+1 do -- trace at least 1/5 of the way per second
|
||||
if not node or node.name == "ignore" then
|
||||
minetest.get_voxel_manip():read_from_map(pos, pos)
|
||||
node = minetest.get_node(pos)
|
||||
end
|
||||
if node then
|
||||
if minetest.registered_nodes[node.name].walkable then
|
||||
return
|
||||
end
|
||||
if minetest.get_item_group(node.name, "water") ~= 0 then
|
||||
return 0
|
||||
end
|
||||
if node.name == "mcl_portals:portal_end" then
|
||||
if mcl_portals and mcl_portals.end_teleport then
|
||||
mcl_portals.end_teleport(obj)
|
||||
end
|
||||
return 0
|
||||
end
|
||||
end
|
||||
pos = vector.add(pos, step)
|
||||
node = minetest.get_node(pos)
|
||||
end
|
||||
end
|
||||
end, -200)
|
||||
|
||||
minetest.register_on_respawnplayer(function(player)
|
||||
local pos = player:get_pos()
|
||||
minetest.add_particlespawner({
|
||||
amount = 50,
|
||||
time = 0.001,
|
||||
minpos = vector.add(pos, 0),
|
||||
maxpos = vector.add(pos, 0),
|
||||
minvel = vector.new(-5,-5,-5),
|
||||
maxvel = vector.new(5,5,5),
|
||||
minexptime = 1.1,
|
||||
maxexptime = 1.5,
|
||||
minsize = 1,
|
||||
maxsize = 2,
|
||||
collisiondetection = false,
|
||||
vertical = false,
|
||||
texture = "mcl_particles_mob_death.png^[colorize:#000000:255",
|
||||
})
|
||||
|
||||
minetest.sound_play("mcl_mobs_mob_poof", {
|
||||
pos = pos,
|
||||
gain = 1.0,
|
||||
max_hear_distance = 8,
|
||||
}, true)
|
||||
end)
|
||||
|
@ -1,5 +1,5 @@
|
||||
name = mcl_playerplus
|
||||
author = TenPlus1
|
||||
description = Adds some simple player-related gameplay effects: Hurt by touching a cactus, suffocation and more.
|
||||
depends = mcl_init, mcl_core, mcl_particles, mcl_hunger, mcl_death_messages, playerphysics, mcl_playerinfo, mcl_weather, mcl_spawn, mcl_enchanting
|
||||
depends = mcl_init, mcl_core, mcl_particles, mcl_hunger, playerphysics, mcl_playerinfo, mcl_weather, mcl_spawn, mcl_enchanting, mcl_damage
|
||||
|
||||
|
@ -7,7 +7,6 @@ mcl_skins = {
|
||||
}
|
||||
|
||||
local S = minetest.get_translator("mcl_skins")
|
||||
local has_mcl_armor = minetest.get_modpath("mcl_armor")
|
||||
local has_mcl_inventory = minetest.get_modpath("mcl_inventory")
|
||||
|
||||
-- load skin list and metadata
|
||||
@ -115,10 +114,6 @@ mcl_skins.set_player_skin = function(player, skin_id)
|
||||
mcl_skins.previews[playername] = preview
|
||||
player:get_meta():set_string("mcl_skins:skin_id", tostring(skin_id))
|
||||
mcl_skins.update_player_skin(player)
|
||||
if has_mcl_armor then
|
||||
armor.textures[playername].skin = skin_file
|
||||
armor:update_player_visuals(player)
|
||||
end
|
||||
if has_mcl_inventory then
|
||||
mcl_inventory.update_inventory_formspec(player)
|
||||
end
|
||||
@ -134,7 +129,7 @@ mcl_skins.update_player_skin = function(player)
|
||||
return
|
||||
end
|
||||
local playername = player:get_player_name()
|
||||
mcl_player.player_set_textures(player, { mcl_skins.skins[playername] .. ".png" }, mcl_skins.previews[playername] .. ".png" )
|
||||
mcl_player.player_set_skin(player, mcl_skins.skins[playername] .. ".png", mcl_skins.previews[playername] .. ".png")
|
||||
end
|
||||
|
||||
-- load player skin on join
|
||||
|
@ -2,4 +2,4 @@ name = mcl_skins
|
||||
author = TenPlus1
|
||||
description = Mod that allows players to set their individual skins.
|
||||
depends = mcl_player
|
||||
optional_depends = mcl_inventory, intllib, mcl_armor
|
||||
optional_depends = mcl_inventory, intllib
|
||||
|
118
mods/PLAYER/mcl_wieldview/init.lua
Normal file
118
mods/PLAYER/mcl_wieldview/init.lua
Normal file
@ -0,0 +1,118 @@
|
||||
mcl_wieldview = {
|
||||
players = {}
|
||||
}
|
||||
|
||||
function mcl_wieldview.get_item_texture(itemname)
|
||||
if itemname == "" then
|
||||
return
|
||||
end
|
||||
|
||||
local def = minetest.registered_items[itemname]
|
||||
if not def then
|
||||
return
|
||||
end
|
||||
|
||||
local inv_image = def.inventory_image
|
||||
if inv_image == "" then
|
||||
return
|
||||
end
|
||||
|
||||
local texture = inv_image
|
||||
|
||||
local transform = minetest.get_item_group(itemname, "wieldview_transform")
|
||||
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" .. transform
|
||||
end
|
||||
|
||||
return texture
|
||||
end
|
||||
|
||||
function mcl_wieldview.update_wielded_item(player)
|
||||
if not player then
|
||||
return
|
||||
end
|
||||
local itemstack = player:get_wielded_item()
|
||||
local itemname = itemstack:get_name()
|
||||
|
||||
local def = mcl_wieldview.players[player]
|
||||
|
||||
if def.item == itemname then
|
||||
return
|
||||
end
|
||||
|
||||
def.item = itemname
|
||||
def.texture = mcl_wieldview.get_item_texture(itemname) or "blank.png"
|
||||
|
||||
mcl_player.player_set_wielditem(player, def.texture)
|
||||
end
|
||||
|
||||
minetest.register_on_joinplayer(function(player)
|
||||
mcl_wieldview.players[player] = {item = "", texture = "blank.png"}
|
||||
|
||||
minetest.after(0, function()
|
||||
if not player:is_player() then
|
||||
return
|
||||
end
|
||||
|
||||
mcl_wieldview.update_wielded_item(player)
|
||||
|
||||
local itementity = minetest.add_entity(player:get_pos(), "mcl_wieldview:wieldnode")
|
||||
itementity:set_attach(player, "Hand_Right", vector.new(0, 1, 0), vector.new(90, 0, 45))
|
||||
itementity:get_luaentity().wielder = player
|
||||
end)
|
||||
end)
|
||||
|
||||
minetest.register_on_leaveplayer(function(player)
|
||||
mcl_wieldview.players[player] = nil
|
||||
end)
|
||||
|
||||
minetest.register_globalstep(function()
|
||||
for _, player in pairs(minetest.get_connected_players()) do
|
||||
mcl_wieldview.update_wielded_item(player)
|
||||
end
|
||||
end)
|
||||
|
||||
minetest.register_entity("mcl_wieldview:wieldnode", {
|
||||
initial_properties = {
|
||||
hp_max = 1,
|
||||
visual = "wielditem",
|
||||
physical = false,
|
||||
textures = {""},
|
||||
automatic_rotate = 1.5,
|
||||
is_visible = true,
|
||||
pointable = false,
|
||||
collide_with_objects = false,
|
||||
static_save = false,
|
||||
collisionbox = {-0.21, -0.21, -0.21, 0.21, 0.21, 0.21},
|
||||
selectionbox = {-0.21, -0.21, -0.21, 0.21, 0.21, 0.21},
|
||||
visual_size = {x = 0.21, y = 0.21},
|
||||
},
|
||||
|
||||
itemstring = "",
|
||||
|
||||
on_step = function(self)
|
||||
if self.wielder:is_player() then
|
||||
local def = mcl_wieldview.players[self.wielder]
|
||||
local itemstring = def.item
|
||||
|
||||
if self.itemstring ~= itemstring then
|
||||
local itemdef = minetest.registered_items[itemstring]
|
||||
self.object:set_properties({glow = itemdef and itemdef.light_source or 0})
|
||||
|
||||
-- wield item as cubic
|
||||
if def.texture == "blank.png" then
|
||||
self.object:set_properties({textures = {itemstring}})
|
||||
-- wield item as flat
|
||||
else
|
||||
self.object:set_properties({textures = {""}})
|
||||
end
|
||||
|
||||
self.itemstring = itemstring
|
||||
end
|
||||
else
|
||||
self.object:remove()
|
||||
end
|
||||
end,
|
||||
})
|
@ -1,5 +1,4 @@
|
||||
name = wieldview
|
||||
name = mcl_wieldview
|
||||
author = stujones11
|
||||
description = Makes hand wielded items visible to other players.
|
||||
depends = mcl_armor
|
||||
|
||||
depends = mcl_player
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user