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:
Elias Fleckenstein 2021-04-27 16:32:41 +00:00
commit 79aac4c494
102 changed files with 2218 additions and 2866 deletions

View 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)

View File

@ -0,0 +1,3 @@
name = mcl_damage
author = Fleckenstein
description = Minecraft-like damage reason system

View File

@ -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)

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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,

View File

@ -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

View File

@ -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,

View File

@ -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},

View File

@ -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",

View File

@ -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)

View File

@ -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,

View File

@ -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,

View File

@ -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,

View File

@ -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,

View File

@ -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},

View File

@ -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,

View File

@ -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,

View File

@ -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)

View File

@ -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,

View File

@ -25,6 +25,7 @@ local carpets = {
}
mobs:register_mob("mobs_mc:llama", {
description = S("Llama"),
type = "animal",
spawn_class = "passive",
hp_min = 15,

View File

@ -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 = ""

View File

@ -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,

View File

@ -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,

View File

@ -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,

View File

@ -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"

View File

@ -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,

View File

@ -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",

View File

@ -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,

View File

@ -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 = {
{

View File

@ -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,

View File

@ -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,

View File

@ -21,6 +21,7 @@ local gotten_texture = {
}
mobs:register_mob("mobs_mc:snowman", {
description = S("Snow Golem"),
type = "npc",
spawn_class = "passive",
passive = true,

View File

@ -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

View File

@ -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,

View File

@ -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,

View File

@ -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,

View File

@ -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,

View File

@ -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",

View File

@ -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,

View File

@ -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,

View File

@ -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,

View File

@ -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,

View File

@ -19,6 +19,7 @@ end
-- Wolf
local wolf = {
description = S("Wolf"),
type = "animal",
spawn_class = "passive",
can_despawn = true,

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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], ...)
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", ...)
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
end
end
local last_damages = { }
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
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_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
if message then
local name = player:get_player_name()
if not name then
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
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
end)

View File

@ -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

View File

@ -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=

View File

@ -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

View File

@ -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

View File

@ -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)..

View File

@ -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;main]"..
"listring[detached:"..player_name.."_armor;armor]"
"listring[current_player;armor]"..
"listring[current_player;main]" ..
"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

View File

@ -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 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]
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 player then
if stack:is_empty() 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
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

View 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

View File

@ -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)

View 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)

View File

@ -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",
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,
},
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",
torso = {
name = "chestplate",
description = "Chestplate",
durability = 1.0,
index = 3,
craft = function(m)
return {
{ m, "", m},
{ m, m, m},
{ m, m, m},
}
end,
},
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",
legs = {
name = "leggings",
description = "Leggings",
durability = 0.9375,
index = 4,
craft = function(m)
return {
{ m, m, m},
{ m, "", m},
{ m, "", m},
}
end,
},
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",
feet = {
name = "boots",
description = "Boots",
durability = 0.8125,
index = 5,
craft = function(m)
return {
{ m, "", m},
{ m, "", m},
}
end,
}
},
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"} ,
player_view_range_factors = {},
}
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 = {
{m, m, m},
{m, "", m},
{"", "", ""},
},
})
minetest.register_craft({
output = "mcl_armor:chestplate_"..k,
recipe = {
{m, "", m},
{m, m, m},
{m, m, m},
},
})
minetest.register_craft({
output = "mcl_armor:leggings_"..k,
recipe = {
{m, m, m},
{m, "", m},
{m, "", m},
},
})
minetest.register_craft({
output = "mcl_armor:boots_"..k,
recipe = {
{m, "", m},
{m, "", m},
},
})
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
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")

View 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)

View 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"
})

View File

@ -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
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.object:set_armor_groups({immortal = 1})
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", {

View File

@ -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

View File

@ -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

View File

@ -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,

View File

@ -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"),

View File

@ -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

View File

@ -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

View File

@ -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,
})

View File

@ -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,

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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)

View File

@ -1,2 +1,2 @@
name = mcl_totems
depends = mobs_mc
depends = mobs_mc, mcl_damage

View File

@ -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))

View File

@ -1,4 +1,3 @@
name = mcl_commands
author = Wuzzy
description = MCL2 commands
optional_depends = mcl_death_messages

View 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)

View File

@ -0,0 +1,2 @@
name = mcl_criticals
depends = mcl_damage

View File

@ -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)

View File

@ -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)

View File

@ -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

View File

@ -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

View File

@ -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)
end
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)

View File

@ -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

View File

@ -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)

View File

@ -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

View File

@ -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

View File

@ -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

View 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,
})

View File

@ -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