1
0
Fork 0

Merge pull request 'Rewrite armor + new damage system' (#1555) from damage into master

Reviewed-on: MineClone2/MineClone2#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 = {} mcl_explosions = {}
local mod_death_messages = minetest.get_modpath("mcl_death_messages") ~= nil
local mod_fire = minetest.get_modpath("mcl_fire") ~= nil local mod_fire = minetest.get_modpath("mcl_fire") ~= nil
local CONTENT_FIRE = minetest.get_content_id("mcl_fire:fire") local CONTENT_FIRE = minetest.get_content_id("mcl_fire:fire")
@ -150,7 +149,8 @@ end
-- raydirs - The directions for each ray -- raydirs - The directions for each ray
-- radius - The maximum distance each ray will go -- radius - The maximum distance each ray will go
-- info - Table containing information about explosion -- 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: -- Values in info:
-- drop_chance - The chance that destroyed nodes will drop their items -- 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 -- Note that this function has been optimized, it contains code which has been
-- inlined to avoid function calls and unnecessary table creation. This was -- inlined to avoid function calls and unnecessary table creation. This was
-- measured to give a significant performance increase. -- 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 vm = get_voxel_manip()
local emin, emax = vm:read_from_map(vector.subtract(pos, radius), 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() local ent = obj:get_luaentity()
-- Ignore items to lower lag -- 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 opos = obj:get_pos()
local collisionbox = nil local collisionbox = nil
@ -321,7 +321,6 @@ local function trace_explode(pos, strength, raydirs, radius, info, puncher)
impact = 0 impact = 0
end end
local damage = math.floor((impact * impact + impact) * 7 * strength + 1) local damage = math.floor((impact * impact + impact) * 7 * strength + 1)
local source = puncher or obj
local sleep_formspec_doesnt_close_mt53 = false local sleep_formspec_doesnt_close_mt53 = false
if obj:is_player() then 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 sleep_formspec_doesnt_close_mt53 = true
end end
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 end
if sleep_formspec_doesnt_close_mt53 then 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 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 then return end if not obj:is_player() then
obj:punch(obj, 10, { damage_groups = { full_punch_interval = 1, fleshy = damage, knockback = impact * 20.0 } }, punch_dir) return
obj:add_velocity(vector.multiply(punch_dir, impact * 20)) end
end, obj, damage, impact, vector.new(punch_dir))
else mcl_util.deal_damage(obj, damage, {type = "explosion", direct = direct, source = source})
obj:punch(source, 10, { damage_groups = { full_punch_interval = 1, fleshy = damage, knockback = impact * 20.0 } }, punch_dir)
if obj:is_player() then
obj:add_velocity(vector.multiply(punch_dir, impact * 20)) 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)) obj:add_velocity(vector.multiply(punch_dir, impact * 20))
end end
end end
@ -422,7 +417,8 @@ end
-- pos - The position where the explosion originates from -- pos - The position where the explosion originates from
-- strength - The blast strength of the explosion (a TNT explosion uses 4) -- strength - The blast strength of the explosion (a TNT explosion uses 4)
-- info - Table containing information about explosion -- 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: -- Values in info:
-- drop_chance - If specified becomes the drop chance of all nodes in the -- 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) -- griefing - If true, the explosion will destroy nodes (default: true)
-- grief_protected - If true, the explosion will also destroy nodes which have -- grief_protected - If true, the explosion will also destroy nodes which have
-- been protected (default: false) -- 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 if info == nil then
info = {} info = {}
end end
@ -465,7 +461,7 @@ function mcl_explosions.explode(pos, strength, info, puncher)
info.drop_chance = 0 info.drop_chance = 0
end end
trace_explode(pos, strength, shape, radius, info, puncher) trace_explode(pos, strength, shape, radius, info, direct, source)
if info.particles then if info.particles then
add_particles(pos, radius) add_particles(pos, radius)

View File

@ -418,3 +418,120 @@ function mcl_util.get_color(colorstr)
return colorstr, hex return colorstr, hex
end end
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 return nodes
end 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 if obj:get_hp() < 0 then
return return
end end
@ -47,27 +47,27 @@ function mcl_burning.set_on_fire(obj, burn_time, reason)
return return
end end
local max_fire_prot_lvl = 0 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 armor_list then
if minetest.is_creative_enabled(obj:get_player_name()) then for _, stack in pairs(armor_list) do
burn_time = burn_time / 100 local fire_prot_lvl = mcl_enchanting.get_enchantment(stack, "fire_protection")
if fire_prot_lvl > max_fire_prot_lvl then
max_fire_prot_lvl = fire_prot_lvl
end
end
end end
local inv = obj:get_inventory() if max_fire_prot_lvl > 0 then
burn_time = burn_time - math.floor(burn_time * max_fire_prot_lvl * 0.15)
for i = 2, 5 do
local stack = inv:get_stack("armor", i)
local fire_prot_lvl = mcl_enchanting.get_enchantment(stack, "fire_protection")
max_fire_prot_lvl = math.max(max_fire_prot_lvl, fire_prot_lvl)
end 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
if not storage.burn_time or burn_time >= storage.burn_time then if not storage.burn_time or burn_time >= storage.burn_time then
if obj:is_player() and not storage.fire_hud_id then if obj:is_player() and not storage.fire_hud_id then
storage.fire_hud_id = obj:hud_add({ storage.fire_hud_id = obj:hud_add({
@ -79,7 +79,6 @@ function mcl_burning.set_on_fire(obj, burn_time, reason)
}) })
end end
storage.burn_time = burn_time storage.burn_time = burn_time
storage.burn_reason = reason
storage.fire_damage_timer = 0 storage.fire_damage_timer = 0
local fire_entity = minetest.add_entity(obj:get_pos(), "mcl_burning:fire") 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] = {} mcl_burning.storage[obj] = {}
else else
storage.burn_time = nil storage.burn_time = nil
storage.burn_reason = nil
storage.fire_damage_timer = nil storage.fire_damage_timer = nil
end end
end end
@ -140,36 +138,9 @@ function mcl_burning.tick(obj, dtime, storage)
storage.fire_damage_timer = 0 storage.fire_damage_timer = 0
local luaentity = obj:get_luaentity() 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 if not luaentity or not luaentity.fire_damage_resistant then
local do_damage = true mcl_util.deal_damage(obj, 1, {type = "on_fire"})
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
end end
end end
end end

View File

@ -1,9 +1,6 @@
local S = minetest.get_translator("mcl_falling_nodes") 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 has_mcl_armor = minetest.get_modpath("mcl_armor")
local is_creative_enabled = minetest.is_creative_enabled
local get_falling_depth = function(self) local get_falling_depth = function(self)
if not self._startpos then if not self._startpos then
-- Fallback -- Fallback
@ -23,80 +20,31 @@ local deal_falling_damage = function(self, dtime)
-- Fallback -- Fallback
self._startpos = pos self._startpos = pos
end end
local objs = minetest.get_objects_inside_radius(pos, 1) self._hit = self._hit or {}
for _,v in ipairs(objs) do for _, obj in ipairs(minetest.get_objects_inside_radius(pos, 1)) do
if v:is_player() then if mcl_util.get_hp(obj) > 0 and not self._hit[obj] then
local hp = v:get_hp() self._hit[obj] = true
local name = v:get_player_name() local way = self._startpos.y - pos.y
if hp ~= 0 then local damage = (way - 1) * 2
if not self._hit_players then damage = math.min(40, math.max(0, damage))
self._hit_players = {} if damage >= 1 then
end -- Reduce damage if wearing a helmet
local hit = false local inv = mcl_util.get_inventory(obj)
for _,v in ipairs(self._hit_players) do if inv then
if name == v then local helmet = inv:get_stack("armor", 2)
hit = true 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
end end
if not hit then local deathmsg, dmg_type
table.insert(self._hit_players, name) if minetest.get_item_group(self.node.name, "anvil") ~= 0 then
local way = self._startpos.y - pos.y dmg_type = "anvil"
local damage = (way - 1) * 2 else
damage = math.min(40, math.max(0, damage)) dmg_type = "falling_node"
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 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)
inv:set_stack("armor", 2, helmet)
end
end
local msg
if minetest.get_item_group(self.node.name, "anvil") ~= 0 then
msg = S("@1 was smashed by a falling anvil.", v:get_player_name())
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
end end
mcl_util.deal_damage(obj, damage, {type = dmg_type})
end end
end end
end end
@ -166,7 +114,7 @@ minetest.register_entity(":__builtin:falling_node", {
on_activate = function(self, staticdata) on_activate = function(self, staticdata)
self.object:set_armor_groups({immortal = 1}) self.object:set_armor_groups({immortal = 1})
local ds = minetest.deserialize(staticdata) local ds = minetest.deserialize(staticdata)
if ds then if ds then
self._startpos = ds._startpos self._startpos = ds._startpos
@ -200,7 +148,7 @@ minetest.register_entity(":__builtin:falling_node", {
local np = {x = pos.x, y = pos.y + 0.3, z = pos.z} local np = {x = pos.x, y = pos.y + 0.3, z = pos.z}
local n2 = minetest.get_node(np) local n2 = minetest.get_node(np)
if n2.name == "mcl_portals:portal_end" then if n2.name == "mcl_portals:portal_end" then
-- TODO: Teleport falling node. -- TODO: Teleport falling node.
self.object:remove() self.object:remove()
return return
end end
@ -239,7 +187,7 @@ minetest.register_entity(":__builtin:falling_node", {
end end
local nd = minetest.registered_nodes[n2.name] local nd = minetest.registered_nodes[n2.name]
if n2.name == "mcl_portals:portal_end" then if n2.name == "mcl_portals:portal_end" then
-- TODO: Teleport falling node. -- TODO: Teleport falling node.
elseif (nd and nd.buildable_to == true) or minetest.get_item_group(self.node.name, "crush_after_fall") ~= 0 then elseif (nd and nd.buildable_to == true) or minetest.get_item_group(self.node.name, "crush_after_fall") ~= 0 then
-- Replace destination node if it's buildable to -- Replace destination node if it's buildable to

View File

@ -177,7 +177,8 @@ local function object_in_range(self, object)
local factor local factor
-- Apply view range reduction for special player armor -- Apply view range reduction for special player armor
if object:is_player() and mod_armor then 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 end
-- Distance check -- Distance check
local dist local dist
@ -3770,6 +3771,7 @@ minetest.register_entity(name, {
use_texture_alpha = def.use_texture_alpha, use_texture_alpha = def.use_texture_alpha,
stepheight = def.stepheight or 0.6, stepheight = def.stepheight or 0.6,
name = name, name = name,
description = def.description,
type = def.type, type = def.type,
attack_type = def.attack_type, attack_type = def.attack_type,
fly = def.fly, fly = def.fly,

View File

@ -516,8 +516,6 @@ end
-- Evoker -- Evoker
if c("totem") then if c("totem") then
local hud_totem = {}
-- Totem of Undying -- Totem of Undying
minetest.register_craftitem("mobs_mc:totem", { minetest.register_craftitem("mobs_mc:totem", {
description = S("Totem of Undying"), description = S("Totem of Undying"),
@ -527,66 +525,8 @@ if c("totem") then
inventory_image = "mcl_totems_totem.png", inventory_image = "mcl_totems_totem.png",
wield_image = "mcl_totems_totem.png", wield_image = "mcl_totems_totem.png",
stack_max = 1, 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 end
-- Rotten flesh -- Rotten flesh

View File

@ -3,6 +3,7 @@
local S = minetest.get_translator("mobs_mc") local S = minetest.get_translator("mobs_mc")
mobs:register_mob("mobs_mc:bat", { mobs:register_mob("mobs_mc:bat", {
description = S("Bat"),
type = "animal", type = "animal",
spawn_class = "ambient", spawn_class = "ambient",
can_despawn = true, can_despawn = true,

View File

@ -11,6 +11,7 @@ local S = minetest.get_translator("mobs_mc")
mobs:register_mob("mobs_mc:blaze", { mobs:register_mob("mobs_mc:blaze", {
description = S("Blaze"),
type = "monster", type = "monster",
spawn_class = "hostile", spawn_class = "hostile",
hp_min = 20, hp_min = 20,
@ -147,13 +148,11 @@ mobs:register_arrow("mobs_mc:blaze_fireball", {
visual_size = {x = 0.3, y = 0.3}, visual_size = {x = 0.3, y = 0.3},
textures = {"mcl_fire_fire_charge.png"}, textures = {"mcl_fire_fire_charge.png"},
velocity = 15, velocity = 15,
_is_fireball = true,
-- Direct hit, no fire... just plenty of pain -- Direct hit, no fire... just plenty of pain
hit_player = function(self, player) hit_player = function(self, player)
if rawget(_G, "armor") and armor.last_damage_types then mcl_burning.set_on_fire(player, 5)
armor.last_damage_types[player:get_player_name()] = "fireball"
end
mcl_burning.set_on_fire(player, 5, "blaze")
player:punch(self.object, 1.0, { player:punch(self.object, 1.0, {
full_punch_interval = 1.0, full_punch_interval = 1.0,
damage_groups = {fleshy = 5}, damage_groups = {fleshy = 5},

View File

@ -9,6 +9,7 @@ local S = minetest.get_translator("mobs_mc")
mobs:register_mob("mobs_mc:chicken", { mobs:register_mob("mobs_mc:chicken", {
description = S("Chicken"),
type = "animal", type = "animal",
spawn_class = "passive", spawn_class = "passive",
@ -95,14 +96,14 @@ mobs:register_mob("mobs_mc:chicken", {
gain = 1.0, gain = 1.0,
max_hear_distance = 16, max_hear_distance = 16,
}, true) }, true)
end, end,
}) })
--spawn --spawn
mobs:spawn_specific( mobs:spawn_specific(
"mobs_mc:chicken", "mobs_mc:chicken",
"overworld", "overworld",
"ground", "ground",
{ {
"FlowerForest", "FlowerForest",
@ -122,10 +123,10 @@ mobs:spawn_specific(
"ExtremeHillsM", "ExtremeHillsM",
"BirchForestM", "BirchForestM",
}, },
9, 9,
minetest.LIGHT_MAX+1, minetest.LIGHT_MAX+1,
30, 17000, 30, 17000,
3, 3,
mobs_mc.spawn_height.water, mobs_mc.spawn_height.water,
mobs_mc.spawn_height.overworld_max) mobs_mc.spawn_height.overworld_max)

View File

@ -3,6 +3,7 @@
local S = minetest.get_translator("mobs_mc") local S = minetest.get_translator("mobs_mc")
local cow_def = { local cow_def = {
description = S("Cow"),
type = "animal", type = "animal",
spawn_class = "passive", spawn_class = "passive",
hp_min = 10, hp_min = 10,
@ -43,7 +44,7 @@ local cow_def = {
stand_speed = 25, walk_speed = 40, stand_speed = 25, walk_speed = 40,
run_speed = 60, stand_start = 0, run_speed = 60, stand_start = 0,
stand_end = 0, walk_start = 0, stand_end = 0, walk_start = 0,
walk_end = 40, run_start = 0, walk_end = 40, run_start = 0,
run_end = 40, run_end = 40,
}, },
follow = mobs_mc.follow.cow, follow = mobs_mc.follow.cow,
@ -81,7 +82,7 @@ mobs:register_mob("mobs_mc:cow", cow_def)
-- Mooshroom -- Mooshroom
local mooshroom_def = table.copy(cow_def) local mooshroom_def = table.copy(cow_def)
mooshroom_def.description = S("Mooshroom")
mooshroom_def.mesh = "mobs_mc_cow.b3d" 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.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) mooshroom_def.on_rightclick = function(self, clicker)
@ -147,7 +148,7 @@ mobs:register_mob("mobs_mc:mooshroom", mooshroom_def)
-- Spawning -- Spawning
mobs:spawn_specific( mobs:spawn_specific(
"mobs_mc:cow", "mobs_mc:cow",
"overworld", "overworld",
"ground", "ground",
{ {
"FlowerForest", "FlowerForest",
@ -167,30 +168,30 @@ mobs:spawn_specific(
"ExtremeHillsM", "ExtremeHillsM",
"BirchForestM", "BirchForestM",
}, },
9, 9,
minetest.LIGHT_MAX+1, minetest.LIGHT_MAX+1,
30, 30,
17000, 17000,
10, 10,
mobs_mc.spawn_height.water, mobs_mc.spawn_height.water,
mobs_mc.spawn_height.overworld_max) mobs_mc.spawn_height.overworld_max)
mobs:spawn_specific( mobs:spawn_specific(
"mobs_mc:mooshroom", "mobs_mc:mooshroom",
"overworld", "overworld",
"ground", "ground",
{ {
"MushroomIslandShore", "MushroomIslandShore",
"MushroomIsland" "MushroomIsland"
}, },
9, 9,
minetest.LIGHT_MAX+1, minetest.LIGHT_MAX+1,
30, 30,
17000, 17000,
5, 5,
mobs_mc.spawn_height.overworld_min, mobs_mc.spawn_height.overworld_min,
mobs_mc.spawn_height.overworld_max) mobs_mc.spawn_height.overworld_max)
-- spawn egg -- spawn egg

View File

@ -130,6 +130,7 @@ mobs:register_mob("mobs_mc:creeper", {
}) })
mobs:register_mob("mobs_mc:creeper_charged", { mobs:register_mob("mobs_mc:creeper_charged", {
description = S("Creeper"),
type = "monster", type = "monster",
spawn_class = "hostile", spawn_class = "hostile",
hp_min = 20, hp_min = 20,
@ -142,7 +143,7 @@ mobs:register_mob("mobs_mc:creeper_charged", {
mesh = "mobs_mc_creeper.b3d", mesh = "mobs_mc_creeper.b3d",
--BOOM --BOOM
textures = { textures = {
{"mobs_mc_creeper.png", {"mobs_mc_creeper.png",
"mobs_mc_creeper_charge.png"}, "mobs_mc_creeper_charge.png"},
@ -254,8 +255,8 @@ mobs:register_mob("mobs_mc:creeper_charged", {
}) })
mobs:spawn_specific( mobs:spawn_specific(
"mobs_mc:creeper", "mobs_mc:creeper",
"overworld", "overworld",
"ground", "ground",
{ {
"Mesa", "Mesa",
@ -398,12 +399,12 @@ mobs:spawn_specific(
"ExtremeHillsM_underground", "ExtremeHillsM_underground",
"JungleEdgeM_underground", "JungleEdgeM_underground",
}, },
0, 0,
7, 7,
20, 20,
16500, 16500,
2, 2,
mobs_mc.spawn_height.overworld_min, mobs_mc.spawn_height.overworld_min,
mobs_mc.spawn_height.overworld_max) mobs_mc.spawn_height.overworld_max)
-- spawn eggs -- spawn eggs

View File

@ -5,6 +5,7 @@
local S = minetest.get_translator("mobs_mc") local S = minetest.get_translator("mobs_mc")
mobs:register_mob("mobs_mc:enderdragon", { mobs:register_mob("mobs_mc:enderdragon", {
description = S("Ender Dragon"),
type = "monster", type = "monster",
spawn_class = "hostile", spawn_class = "hostile",
pathfinding = 1, pathfinding = 1,

View File

@ -190,6 +190,7 @@ end
local mobs_griefing = minetest.settings:get_bool("mobs_griefing") ~= false local mobs_griefing = minetest.settings:get_bool("mobs_griefing") ~= false
mobs:register_mob("mobs_mc:enderman", { mobs:register_mob("mobs_mc:enderman", {
description = S("Enderman"),
type = "monster", type = "monster",
spawn_class = "passive", spawn_class = "passive",
passive = true, passive = true,
@ -330,7 +331,7 @@ mobs:register_mob("mobs_mc:enderman", {
end end
-- Check to see if people are near by enough to look at us. -- Check to see if people are near by enough to look at us.
for _,obj in pairs(minetest.get_connected_players()) do for _,obj in pairs(minetest.get_connected_players()) do
--check if they are within radius --check if they are within radius
local player_pos = obj:get_pos() local player_pos = obj:get_pos()
if player_pos then -- prevent crashing in 1 in a million scenario if player_pos then -- prevent crashing in 1 in a million scenario
@ -355,7 +356,7 @@ mobs:register_mob("mobs_mc:enderman", {
local ender_eye_pos = vector.new(enderpos.x, enderpos.y + 2.75, enderpos.z) local ender_eye_pos = vector.new(enderpos.x, enderpos.y + 2.75, enderpos.z)
local eye_distance_from_player = vector.distance(ender_eye_pos, look_pos) local eye_distance_from_player = vector.distance(ender_eye_pos, look_pos)
look_pos = vector.add(look_pos, vector.multiply(look_dir, eye_distance_from_player)) look_pos = vector.add(look_pos, vector.multiply(look_dir, eye_distance_from_player))
--if looking in general head position, turn hostile --if looking in general head position, turn hostile
if minetest.line_of_sight(ender_eye_pos, look_pos_base) and vector.distance(look_pos, ender_eye_pos) <= 0.4 then if minetest.line_of_sight(ender_eye_pos, look_pos_base) and vector.distance(look_pos, ender_eye_pos) <= 0.4 then
self.provoked = "staring" self.provoked = "staring"
@ -364,7 +365,7 @@ mobs:register_mob("mobs_mc:enderman", {
else -- I'm not sure what this part does, but I don't want to break anything - jordan4ibanez else -- I'm not sure what this part does, but I don't want to break anything - jordan4ibanez
if self.provoked == "staring" then if self.provoked == "staring" then
self.provoked = "broke_contact" self.provoked = "broke_contact"
end end
end end
end end
@ -562,23 +563,23 @@ mobs:register_mob("mobs_mc:enderman", {
-- End spawn -- End spawn
mobs:spawn_specific( mobs:spawn_specific(
"mobs_mc:enderman", "mobs_mc:enderman",
"end", "end",
"ground", "ground",
{ {
"End" "End"
}, },
0, 0,
minetest.LIGHT_MAX+1, minetest.LIGHT_MAX+1,
30, 30,
3000, 3000,
12, 12,
mobs_mc.spawn_height.end_min, mobs_mc.spawn_height.end_min,
mobs_mc.spawn_height.end_max) mobs_mc.spawn_height.end_max)
-- Overworld spawn -- Overworld spawn
mobs:spawn_specific( mobs:spawn_specific(
"mobs_mc:enderman", "mobs_mc:enderman",
"overworld", "overworld",
"ground", "ground",
{ {
"Mesa", "Mesa",
@ -721,28 +722,28 @@ mobs:spawn_specific(
"ExtremeHillsM_underground", "ExtremeHillsM_underground",
"JungleEdgeM_underground", "JungleEdgeM_underground",
}, },
0, 0,
7, 7,
30, 30,
19000, 19000,
2, 2,
mobs_mc.spawn_height.overworld_min, mobs_mc.spawn_height.overworld_min,
mobs_mc.spawn_height.overworld_max) mobs_mc.spawn_height.overworld_max)
-- Nether spawn (rare) -- Nether spawn (rare)
mobs:spawn_specific( mobs:spawn_specific(
"mobs_mc:enderman", "mobs_mc:enderman",
"nether", "nether",
"ground", "ground",
{ {
"Nether" "Nether"
}, },
0, 0,
7, 7,
30, 30,
27500, 27500,
4, 4,
mobs_mc.spawn_height.nether_min, mobs_mc.spawn_height.nether_min,
mobs_mc.spawn_height.nether_max) mobs_mc.spawn_height.nether_max)
-- spawn eggs -- spawn eggs

View File

@ -5,6 +5,7 @@
local S = minetest.get_translator("mobs_mc") local S = minetest.get_translator("mobs_mc")
mobs:register_mob("mobs_mc:endermite", { mobs:register_mob("mobs_mc:endermite", {
description = S("Endermite"),
type = "monster", type = "monster",
spawn_class = "hostile", spawn_class = "hostile",
passive = false, passive = false,

View File

@ -11,6 +11,7 @@ local S = minetest.get_translator("mobs_mc")
mobs:register_mob("mobs_mc:ghast", { mobs:register_mob("mobs_mc:ghast", {
description = S("Ghast"),
type = "monster", type = "monster",
spawn_class = "hostile", spawn_class = "hostile",
pathfinding = 1, pathfinding = 1,
@ -76,18 +77,18 @@ mobs:register_mob("mobs_mc:ghast", {
mobs:spawn_specific( mobs:spawn_specific(
"mobs_mc:ghast", "mobs_mc:ghast",
"nether", "nether",
"ground", "ground",
{ {
"Nether" "Nether"
}, },
0, 0,
minetest.LIGHT_MAX+1, minetest.LIGHT_MAX+1,
30, 30,
18000, 18000,
2, 2,
mobs_mc.spawn_height.nether_min, mobs_mc.spawn_height.nether_min,
mobs_mc.spawn_height.nether_max) mobs_mc.spawn_height.nether_max)
-- fireball (projectile) -- fireball (projectile)
@ -97,11 +98,9 @@ mobs:register_arrow("mobs_mc:fireball", {
textures = {"mcl_fire_fire_charge.png"}, textures = {"mcl_fire_fire_charge.png"},
velocity = 15, velocity = 15,
collisionbox = {-.5, -.5, -.5, .5, .5, .5}, collisionbox = {-.5, -.5, -.5, .5, .5, .5},
_is_fireball = true,
hit_player = function(self, player) 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, { player:punch(self.object, 1.0, {
full_punch_interval = 1.0, full_punch_interval = 1.0,
damage_groups = {fleshy = 6}, damage_groups = {fleshy = 6},

View File

@ -5,6 +5,7 @@
local S = minetest.get_translator("mobs_mc") local S = minetest.get_translator("mobs_mc")
mobs:register_mob("mobs_mc:guardian", { mobs:register_mob("mobs_mc:guardian", {
description = S("Guardian"),
type = "monster", type = "monster",
spawn_class = "hostile", spawn_class = "hostile",
hp_min = 30, hp_min = 30,

View File

@ -7,6 +7,7 @@
local S = minetest.get_translator("mobs_mc") local S = minetest.get_translator("mobs_mc")
mobs:register_mob("mobs_mc:guardian_elder", { mobs:register_mob("mobs_mc:guardian_elder", {
description = S("Elder Guardian"),
type = "monster", type = "monster",
spawn_class = "hostile", spawn_class = "hostile",
hp_min = 80, hp_min = 80,

View File

@ -83,6 +83,7 @@ end
-- Horse -- Horse
local horse = { local horse = {
description = S("Horse"),
type = "animal", type = "animal",
spawn_class = "passive", spawn_class = "passive",
visual = "mesh", visual = "mesh",
@ -418,6 +419,7 @@ mobs:register_mob("mobs_mc:horse", horse)
-- Skeleton horse -- Skeleton horse
local skeleton_horse = table.copy(horse) local skeleton_horse = table.copy(horse)
skeleton_horse.description = S("Skeleton Horse")
skeleton_horse.breath_max = -1 skeleton_horse.breath_max = -1
skeleton_horse.armor = {undead = 100, fleshy = 100} skeleton_horse.armor = {undead = 100, fleshy = 100}
skeleton_horse.textures = {{"blank.png", "mobs_mc_horse_skeleton.png", "blank.png"}} 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 -- Zombie horse
local zombie_horse = table.copy(horse) local zombie_horse = table.copy(horse)
zombie_horse.description = S("Zombie Horse")
zombie_horse.breath_max = -1 zombie_horse.breath_max = -1
zombie_horse.armor = {undead = 100, fleshy = 100} zombie_horse.armor = {undead = 100, fleshy = 100}
zombie_horse.textures = {{"blank.png", "mobs_mc_horse_zombie.png", "blank.png"}} 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 -- Donkey
local d = 0.86 -- donkey scale local d = 0.86 -- donkey scale
local donkey = table.copy(horse) local donkey = table.copy(horse)
donkey.description = S("Donkey")
donkey.textures = {{"blank.png", "mobs_mc_donkey.png", "blank.png"}} donkey.textures = {{"blank.png", "mobs_mc_donkey.png", "blank.png"}}
donkey.animation = { donkey.animation = {
speed_normal = 25, speed_normal = 25,
@ -494,6 +498,7 @@ mobs:register_mob("mobs_mc:donkey", donkey)
-- Mule -- Mule
local m = 0.94 local m = 0.94
local mule = table.copy(donkey) local mule = table.copy(donkey)
mule.description = S("Mule")
mule.textures = {{"blank.png", "mobs_mc_mule.png", "blank.png"}} 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.visual_size = { x=horse.visual_size.x*m, y=horse.visual_size.y*m }
mule.sounds = table.copy(donkey.sounds) mule.sounds = table.copy(donkey.sounds)
@ -532,18 +537,18 @@ mobs:spawn_specific(
"ExtremeHillsM", "ExtremeHillsM",
"BirchForestM", "BirchForestM",
}, },
0, 0,
minetest.LIGHT_MAX+1, minetest.LIGHT_MAX+1,
30, 30,
15000, 15000,
4, 4,
mobs_mc.spawn_height.water+3, mobs_mc.spawn_height.water+3,
mobs_mc.spawn_height.overworld_max) mobs_mc.spawn_height.overworld_max)
mobs:spawn_specific( mobs:spawn_specific(
"mobs_mc:donkey", "mobs_mc:donkey",
"overworld", "overworld",
"ground", "ground",
{ {
"Mesa", "Mesa",
@ -553,12 +558,12 @@ mobs:spawn_specific(
"MesaPlateauF_grasstop", "MesaPlateauF_grasstop",
"MesaBryce", "MesaBryce",
}, },
0, 0,
minetest.LIGHT_MAX+1, minetest.LIGHT_MAX+1,
30, 30,
15000, 15000,
4, 4,
mobs_mc.spawn_height.water+3, mobs_mc.spawn_height.water+3,
mobs_mc.spawn_height.overworld_max) mobs_mc.spawn_height.overworld_max)
-- spawn eggs -- spawn eggs

View File

@ -12,6 +12,7 @@ local S = minetest.get_translator("mobs_mc")
mobs:register_mob("mobs_mc:iron_golem", { mobs:register_mob("mobs_mc:iron_golem", {
description = S("Iron Golem"),
type = "npc", type = "npc",
spawn_class = "passive", spawn_class = "passive",
passive = true, passive = true,

View File

@ -25,6 +25,7 @@ local carpets = {
} }
mobs:register_mob("mobs_mc:llama", { mobs:register_mob("mobs_mc:llama", {
description = S("Llama"),
type = "animal", type = "animal",
spawn_class = "passive", spawn_class = "passive",
hp_min = 15, hp_min = 15,
@ -229,12 +230,12 @@ mobs:spawn_specific(
"MesaPlateauF_grasstop", "MesaPlateauF_grasstop",
"MesaBryce", "MesaBryce",
}, },
0, 0,
minetest.LIGHT_MAX+1, minetest.LIGHT_MAX+1,
30, 30,
15000, 15000,
5, 5,
mobs_mc.spawn_height.water+15, mobs_mc.spawn_height.water+15,
mobs_mc.spawn_height.overworld_max) mobs_mc.spawn_height.overworld_max)
-- spawn eggs -- spawn eggs

View File

@ -27,6 +27,7 @@ end
-- Ocelot -- Ocelot
local ocelot = { local ocelot = {
description = S("Ocelot"),
type = "animal", type = "animal",
spawn_class = "passive", spawn_class = "passive",
can_despawn = true, can_despawn = true,
@ -102,6 +103,7 @@ mobs:register_mob("mobs_mc:ocelot", ocelot)
-- Cat -- Cat
local cat = table.copy(ocelot) 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.textures = {{"mobs_mc_cat_black.png"}, {"mobs_mc_cat_red.png"}, {"mobs_mc_cat_siamese.png"}}
cat.can_despawn = false cat.can_despawn = false
cat.owner = "" cat.owner = ""
@ -154,8 +156,8 @@ local base_spawn_chance = 5000
-- Spawn ocelot -- Spawn ocelot
--they get the same as the llama because I'm trying to rework so much of this code right now -j4i --they get the same as the llama because I'm trying to rework so much of this code right now -j4i
mobs:spawn_specific( mobs:spawn_specific(
"mobs_mc:ocelot", "mobs_mc:ocelot",
"overworld", "overworld",
"ground", "ground",
{ {
"Jungle", "Jungle",
@ -163,12 +165,12 @@ mobs:spawn_specific(
"JungleM", "JungleM",
"JungleEdge", "JungleEdge",
}, },
0, 0,
minetest.LIGHT_MAX+1, minetest.LIGHT_MAX+1,
30, 30,
15000, 15000,
5, 5,
mobs_mc.spawn_height.water+15, mobs_mc.spawn_height.water+15,
mobs_mc.spawn_height.overworld_max) mobs_mc.spawn_height.overworld_max)
--[[ --[[
mobs:spawn({ mobs:spawn({
@ -183,7 +185,7 @@ mobs:spawn({
max_height = mobs_mc.spawn_height.overworld_max, max_height = mobs_mc.spawn_height.overworld_max,
on_spawn = function(self, pos) on_spawn = function(self, pos)
Note: Minecraft has a 1/3 spawn failure rate. Note: Minecraft has a 1/3 spawn failure rate.
In this mod it is emulated by reducing the spawn rate accordingly (see above). In this mod it is emulated by reducing the spawn rate accordingly (see above).
-- 1/7 chance to spawn 2 ocelot kittens -- 1/7 chance to spawn 2 ocelot kittens
if pr:next(1,7) == 1 then if pr:next(1,7) == 1 then

View File

@ -12,6 +12,7 @@ local S = minetest.get_translator("mobs_mc")
mobs:register_mob("mobs_mc:parrot", { mobs:register_mob("mobs_mc:parrot", {
description = S("Parrot"),
type = "npc", type = "npc",
spawn_class = "passive", spawn_class = "passive",
pathfinding = 1, pathfinding = 1,
@ -93,7 +94,7 @@ mobs:register_mob("mobs_mc:parrot", {
-- Parrots spawn rarely in jungles. TODO: Also check for jungle *biome* <- I'll get to this eventually -j4i -- Parrots spawn rarely in jungles. TODO: Also check for jungle *biome* <- I'll get to this eventually -j4i
mobs:spawn_specific( mobs:spawn_specific(
"mobs_mc:parrot", "mobs_mc:parrot",
"overworld", "overworld",
"ground", "ground",
{ {
"Jungle", "Jungle",
@ -101,12 +102,12 @@ mobs:spawn_specific(
"JungleM", "JungleM",
"JungleEdge", "JungleEdge",
}, },
0, 0,
minetest.LIGHT_MAX+1, minetest.LIGHT_MAX+1,
7, 7,
30000, 30000,
1, 1,
mobs_mc.spawn_height.water+7, mobs_mc.spawn_height.water+7,
mobs_mc.spawn_height.overworld_max) mobs_mc.spawn_height.overworld_max)
-- spawn eggs -- spawn eggs

View File

@ -3,6 +3,7 @@
local S = minetest.get_translator("mobs_mc") local S = minetest.get_translator("mobs_mc")
mobs:register_mob("mobs_mc:pig", { mobs:register_mob("mobs_mc:pig", {
description = S("Pig"),
type = "animal", type = "animal",
spawn_class = "passive", spawn_class = "passive",
runaway = true, runaway = true,
@ -183,8 +184,8 @@ mobs:register_mob("mobs_mc:pig", {
}) })
mobs:spawn_specific( mobs:spawn_specific(
"mobs_mc:pig", "mobs_mc:pig",
"overworld", "overworld",
"ground", "ground",
{ {
"FlowerForest", "FlowerForest",
@ -204,12 +205,12 @@ mobs:spawn_specific(
"ExtremeHillsM", "ExtremeHillsM",
"BirchForestM", "BirchForestM",
}, },
9, 9,
minetest.LIGHT_MAX+1, minetest.LIGHT_MAX+1,
30, 30,
15000, 15000,
8, 8,
mobs_mc.spawn_height.overworld_min, mobs_mc.spawn_height.overworld_min,
mobs_mc.spawn_height.overworld_max) mobs_mc.spawn_height.overworld_max)
-- spawn eggs -- spawn eggs

View File

@ -8,6 +8,7 @@ local S = minetest.get_translator("mobs_mc")
mobs:register_mob("mobs_mc:polar_bear", { mobs:register_mob("mobs_mc:polar_bear", {
description = S("Polar Bear"),
type = "animal", type = "animal",
spawn_class = "passive", spawn_class = "passive",
runaway = false, runaway = false,
@ -37,7 +38,7 @@ mobs:register_mob("mobs_mc:polar_bear", {
chance = 2, chance = 2,
min = 0, min = 0,
max = 2, max = 2,
looting = "common",}, looting = "common",},
-- 1/4 to drop raw salmon -- 1/4 to drop raw salmon
{name = mobs_mc.items.salmon_raw, {name = mobs_mc.items.salmon_raw,
chance = 4, chance = 4,

View File

@ -3,6 +3,7 @@
local S = minetest.get_translator("mobs_mc") local S = minetest.get_translator("mobs_mc")
local rabbit = { local rabbit = {
description = S("Rabbit"),
type = "animal", type = "animal",
spawn_class = "passive", spawn_class = "passive",
passive = true, passive = true,
@ -83,6 +84,7 @@ mobs:register_mob("mobs_mc:rabbit", rabbit)
-- The killer bunny (Only with spawn egg) -- The killer bunny (Only with spawn egg)
local killer_bunny = table.copy(rabbit) local killer_bunny = table.copy(rabbit)
killer_bunny.description = S("Killer Bunny")
killer_bunny.type = "monster" killer_bunny.type = "monster"
killer_bunny.spawn_class = "hostile" killer_bunny.spawn_class = "hostile"
killer_bunny.attack_type = "dogfight" killer_bunny.attack_type = "dogfight"
@ -110,8 +112,8 @@ mobs:register_mob("mobs_mc:killer_bunny", killer_bunny)
-- Different skins depending on spawn location <- we'll get to this when the spawning algorithm is fleshed out -- Different skins depending on spawn location <- we'll get to this when the spawning algorithm is fleshed out
mobs:spawn_specific( mobs:spawn_specific(
"mobs_mc:rabbit", "mobs_mc:rabbit",
"overworld", "overworld",
"ground", "ground",
{ {
"FlowerForest", "FlowerForest",
@ -131,12 +133,12 @@ mobs:spawn_specific(
"ExtremeHillsM", "ExtremeHillsM",
"BirchForestM", "BirchForestM",
}, },
9, 9,
minetest.LIGHT_MAX+1, minetest.LIGHT_MAX+1,
30, 30,
15000, 15000,
8, 8,
mobs_mc.spawn_height.overworld_min, mobs_mc.spawn_height.overworld_min,
mobs_mc.spawn_height.overworld_max) mobs_mc.spawn_height.overworld_max)
--[[ --[[

View File

@ -56,6 +56,7 @@ local gotten_texture = { "blank.png", "mobs_mc_sheep.png" }
--mcsheep --mcsheep
mobs:register_mob("mobs_mc:sheep", { mobs:register_mob("mobs_mc:sheep", {
description = S("Sheep"),
type = "animal", type = "animal",
spawn_class = "passive", spawn_class = "passive",
hp_min = 8, hp_min = 8,
@ -325,12 +326,12 @@ mobs:spawn_specific(
"ExtremeHillsM", "ExtremeHillsM",
"BirchForestM", "BirchForestM",
}, },
0, 0,
minetest.LIGHT_MAX+1, minetest.LIGHT_MAX+1,
30, 30,
15000, 15000,
3, 3,
mobs_mc.spawn_height.overworld_min, mobs_mc.spawn_height.overworld_min,
mobs_mc.spawn_height.overworld_max) mobs_mc.spawn_height.overworld_max)
-- spawn eggs -- spawn eggs

View File

@ -10,8 +10,9 @@ local S = minetest.get_translator("mobs_mc")
--################### --###################
-- animation 45-80 is transition between passive and attack stance -- animation 45-80 is transition between passive and attack stance
mobs:register_mob("mobs_mc:shulker", { mobs:register_mob("mobs_mc:shulker", {
description = S("Shulker"),
type = "monster", type = "monster",
spawn_class = "hostile", spawn_class = "hostile",
attack_type = "shoot", attack_type = "shoot",
@ -82,16 +83,16 @@ mobs:register_arrow("mobs_mc:shulkerbullet", {
mobs:register_egg("mobs_mc:shulker", S("Shulker"), "mobs_mc_spawn_icon_shulker.png", 0) mobs:register_egg("mobs_mc:shulker", S("Shulker"), "mobs_mc_spawn_icon_shulker.png", 0)
mobs:spawn_specific( mobs:spawn_specific(
"mobs_mc:shulker", "mobs_mc:shulker",
"end", "end",
"ground", "ground",
{ {
"End" "End"
}, },
0, 0,
minetest.LIGHT_MAX+1, minetest.LIGHT_MAX+1,
30, 30,
5000, 5000,
2, 2,
mobs_mc.spawn_height.end_min, mobs_mc.spawn_height.end_min,
mobs_mc.spawn_height.end_max) mobs_mc.spawn_height.end_max)

View File

@ -5,6 +5,7 @@
local S = minetest.get_translator("mobs_mc") local S = minetest.get_translator("mobs_mc")
mobs:register_mob("mobs_mc:silverfish", { mobs:register_mob("mobs_mc:silverfish", {
description = S("Silverfish"),
type = "monster", type = "monster",
spawn_class = "hostile", spawn_class = "hostile",
passive = false, passive = false,

View File

@ -13,6 +13,7 @@ local mod_bows = minetest.get_modpath("mcl_bows") ~= nil
local skeleton = { local skeleton = {
description = S("Skeleton"),
type = "monster", type = "monster",
spawn_class = "hostile", spawn_class = "hostile",
hp_min = 20, hp_min = 20,
@ -109,6 +110,7 @@ mobs:register_mob("mobs_mc:skeleton", skeleton)
--################### --###################
local stray = table.copy(skeleton) local stray = table.copy(skeleton)
stray.description = S("Stray")
stray.mesh = "mobs_mc_skeleton.b3d" stray.mesh = "mobs_mc_skeleton.b3d"
stray.textures = { stray.textures = {
{ {

View File

@ -10,6 +10,7 @@ local S = minetest.get_translator("mobs_mc")
--################### --###################
mobs:register_mob("mobs_mc:witherskeleton", { mobs:register_mob("mobs_mc:witherskeleton", {
description = S("Wither Skeleton"),
type = "monster", type = "monster",
spawn_class = "hostile", spawn_class = "hostile",
hp_min = 20, hp_min = 20,

View File

@ -56,6 +56,7 @@ end
-- Slime -- Slime
local slime_big = { local slime_big = {
description = S("Slime"),
type = "monster", type = "monster",
spawn_class = "hostile", spawn_class = "hostile",
pathfinding = 1, pathfinding = 1,
@ -158,8 +159,8 @@ local smin = mobs_mc.spawn_height.overworld_min
local smax = mobs_mc.spawn_height.water - 23 local smax = mobs_mc.spawn_height.water - 23
mobs:spawn_specific( mobs:spawn_specific(
"mobs_mc:slime_tiny", "mobs_mc:slime_tiny",
"overworld", "overworld",
"ground", "ground",
{ {
"FlowerForest_underground", "FlowerForest_underground",
@ -193,17 +194,17 @@ mobs:spawn_specific(
"ExtremeHillsM_underground", "ExtremeHillsM_underground",
"JungleEdgeM_underground", "JungleEdgeM_underground",
}, },
0, 0,
minetest.LIGHT_MAX+1, minetest.LIGHT_MAX+1,
30, 30,
12000, 12000,
4, 4,
smin, smin,
smax) smax)
mobs:spawn_specific( mobs:spawn_specific(
"mobs_mc:slime_small", "mobs_mc:slime_small",
"overworld", "overworld",
"ground", "ground",
{ {
"FlowerForest_underground", "FlowerForest_underground",
@ -236,19 +237,19 @@ mobs:spawn_specific(
"JungleM_underground", "JungleM_underground",
"ExtremeHillsM_underground", "ExtremeHillsM_underground",
"JungleEdgeM_underground", "JungleEdgeM_underground",
}, },
0, 0,
minetest.LIGHT_MAX+1, minetest.LIGHT_MAX+1,
30, 30,
8500, 8500,
4, 4,
smin, smin,
smax) smax)
mobs:spawn_specific( mobs:spawn_specific(
"mobs_mc:slime_big", "mobs_mc:slime_big",
"overworld", "overworld",
"ground", "ground",
{ {
"FlowerForest_underground", "FlowerForest_underground",
"JungleEdge_underground", "JungleEdge_underground",
@ -281,16 +282,17 @@ mobs:spawn_specific(
"ExtremeHillsM_underground", "ExtremeHillsM_underground",
"JungleEdgeM_underground", "JungleEdgeM_underground",
}, },
0, 0,
minetest.LIGHT_MAX+1, minetest.LIGHT_MAX+1,
30, 30,
10000, 10000,
4, 4,
smin, smin,
smax) smax)
-- Magma cube -- Magma cube
local magma_cube_big = { local magma_cube_big = {
description = S("Magma Cube"),
type = "monster", type = "monster",
spawn_class = "hostile", spawn_class = "hostile",
hp_min = 16, hp_min = 16,
@ -401,49 +403,49 @@ local mmin = mobs_mc.spawn_height.nether_min
local mmax = mobs_mc.spawn_height.nether_max local mmax = mobs_mc.spawn_height.nether_max
mobs:spawn_specific( mobs:spawn_specific(
"mobs_mc:magma_cube_tiny", "mobs_mc:magma_cube_tiny",
"nether", "nether",
"ground", "ground",
{ {
"Nether" "Nether"
}, },
0, 0,
minetest.LIGHT_MAX+1, minetest.LIGHT_MAX+1,
30, 30,
15000, 15000,
4, 4,
mmin, mmin,
mmax) mmax)
mobs:spawn_specific( mobs:spawn_specific(
"mobs_mc:magma_cube_small", "mobs_mc:magma_cube_small",
"nether", "nether",
"ground", "ground",
{ {
"Nether" "Nether"
}, },
0, 0,
minetest.LIGHT_MAX+1, minetest.LIGHT_MAX+1,
30, 30,
15500, 15500,
4, 4,
mmin, mmin,
mmax) mmax)
mobs:spawn_specific( mobs:spawn_specific(
"mobs_mc:magma_cube_big", "mobs_mc:magma_cube_big",
"nether", "nether",
"ground", "ground",
{ {
"Nether" "Nether"
}, },
0, 0,
minetest.LIGHT_MAX+1, minetest.LIGHT_MAX+1,
30, 30,
16000, 16000,
4, 4,
mmin, mmin,
mmax) mmax)
--mobs:spawn_specific("mobs_mc:magma_cube_tiny", mobs_mc.spawn.nether_fortress, {"air"}, 0, minetest.LIGHT_MAX+1, 30, 11000, 4, mmin, mmax) --mobs:spawn_specific("mobs_mc:magma_cube_tiny", mobs_mc.spawn.nether_fortress, {"air"}, 0, minetest.LIGHT_MAX+1, 30, 11000, 4, mmin, mmax)

View File

@ -21,6 +21,7 @@ local gotten_texture = {
} }
mobs:register_mob("mobs_mc:snowman", { mobs:register_mob("mobs_mc:snowman", {
description = S("Snow Golem"),
type = "npc", type = "npc",
spawn_class = "passive", spawn_class = "passive",
passive = true, 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) -- Spider by AspireMint (fishyWET (CC-BY-SA 3.0 license for texture)
local spider = { local spider = {
description = S("Spider"),
type = "monster", type = "monster",
spawn_class = "hostile", spawn_class = "hostile",
passive = false, passive = false,
@ -72,6 +73,7 @@ mobs:register_mob("mobs_mc:spider", spider)
-- Cave spider -- Cave spider
local cave_spider = table.copy(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)"} } cave_spider.textures = { {"mobs_mc_cave_spider.png^(mobs_mc_spider_eyes.png^[makealpha:0,0,0)"} }
-- TODO: Poison damage -- TODO: Poison damage
-- TODO: Revert damage to 2 -- TODO: Revert damage to 2
@ -88,8 +90,8 @@ mobs:register_mob("mobs_mc:cave_spider", cave_spider)
mobs:spawn_specific( mobs:spawn_specific(
"mobs_mc:spider", "mobs_mc:spider",
"overworld", "overworld",
"ground", "ground",
{ {
"Mesa", "Mesa",
@ -232,12 +234,12 @@ mobs:spawn_specific(
"ExtremeHillsM_underground", "ExtremeHillsM_underground",
"JungleEdgeM_underground", "JungleEdgeM_underground",
}, },
0, 0,
7, 7,
30, 30,
17000, 17000,
2, 2,
mobs_mc.spawn_height.overworld_min, mobs_mc.spawn_height.overworld_min,
mobs_mc.spawn_height.overworld_max) mobs_mc.spawn_height.overworld_max)
-- spawn eggs -- spawn eggs

View File

@ -7,6 +7,7 @@
local S = minetest.get_translator("mobs_mc") local S = minetest.get_translator("mobs_mc")
mobs:register_mob("mobs_mc:squid", { mobs:register_mob("mobs_mc:squid", {
description = S("Squid"),
type = "animal", type = "animal",
spawn_class = "water", spawn_class = "water",
can_despawn = true, can_despawn = true,

View File

@ -10,6 +10,7 @@ local S = minetest.get_translator("mobs_mc")
--################### --###################
mobs:register_mob("mobs_mc:vex", { mobs:register_mob("mobs_mc:vex", {
description = S("Vex"),
type = "monster", type = "monster",
spawn_class = "hostile", spawn_class = "hostile",
pathfinding = 1, pathfinding = 1,

View File

@ -927,6 +927,7 @@ end)
--[=======[ MOB REGISTRATION AND SPAWNING ]=======] --[=======[ MOB REGISTRATION AND SPAWNING ]=======]
mobs:register_mob("mobs_mc:villager", { mobs:register_mob("mobs_mc:villager", {
description = S("Villager"),
type = "npc", type = "npc",
spawn_class = "passive", spawn_class = "passive",
hp_min = 20, hp_min = 20,

View File

@ -12,6 +12,7 @@ local S = minetest.get_translator("mobs_mc")
local pr = PseudoRandom(os.time()*666) local pr = PseudoRandom(os.time()*666)
mobs:register_mob("mobs_mc:evoker", { mobs:register_mob("mobs_mc:evoker", {
description = S("Evoker"),
type = "monster", type = "monster",
spawn_class = "hostile", spawn_class = "hostile",
physical = true, physical = true,

View File

@ -7,6 +7,7 @@ local S = minetest.get_translator("mobs_mc")
local mod_bows = minetest.get_modpath("mcl_bows") ~= nil local mod_bows = minetest.get_modpath("mcl_bows") ~= nil
mobs:register_mob("mobs_mc:illusioner", { mobs:register_mob("mobs_mc:illusioner", {
description = S("Illusioner"),
type = "monster", type = "monster",
spawn_class = "hostile", spawn_class = "hostile",
attack_type = "shoot", attack_type = "shoot",

View File

@ -11,6 +11,7 @@ local S = minetest.get_translator("mobs_mc")
mobs:register_mob("mobs_mc:vindicator", { mobs:register_mob("mobs_mc:vindicator", {
description = S("Vindicator"),
type = "monster", type = "monster",
spawn_class = "hostile", spawn_class = "hostile",
physical = false, physical = false,

View File

@ -26,6 +26,7 @@ local professions = {
} }
mobs:register_mob("mobs_mc:villager_zombie", { mobs:register_mob("mobs_mc:villager_zombie", {
description = S("Zombie Villager"),
type = "monster", type = "monster",
spawn_class = "hostile", spawn_class = "hostile",
hp_min = 20, hp_min = 20,

View File

@ -13,6 +13,7 @@ local S = minetest.get_translator("mobs_mc")
mobs:register_mob("mobs_mc:witch", { mobs:register_mob("mobs_mc:witch", {
description = S("Witch"),
type = "monster", type = "monster",
spawn_class = "hostile", spawn_class = "hostile",
hp_min = 26, hp_min = 26,

View File

@ -10,6 +10,7 @@ local S = minetest.get_translator("mobs_mc")
--################### --###################
mobs:register_mob("mobs_mc:wither", { mobs:register_mob("mobs_mc:wither", {
description = S("Wither"),
type = "monster", type = "monster",
spawn_class = "hostile", spawn_class = "hostile",
hp_max = 300, hp_max = 300,

View File

@ -19,6 +19,7 @@ end
-- Wolf -- Wolf
local wolf = { local wolf = {
description = S("Wolf"),
type = "animal", type = "animal",
spawn_class = "passive", spawn_class = "passive",
can_despawn = true, can_despawn = true,
@ -138,7 +139,7 @@ dog.owner = ""
-- TODO: Start sitting by default -- TODO: Start sitting by default
dog.order = "roam" dog.order = "roam"
dog.owner_loyal = true dog.owner_loyal = true
dog.follow_velocity = 3.2 dog.follow_velocity = 3.2
-- Automatically teleport dog to owner -- Automatically teleport dog to owner
dog.do_custom = mobs_mc.make_owner_teleport_function(12) dog.do_custom = mobs_mc.make_owner_teleport_function(12)
dog.follow = mobs_mc.follow.dog dog.follow = mobs_mc.follow.dog
@ -254,12 +255,12 @@ mobs:spawn_specific(
"ExtremeHillsM", "ExtremeHillsM",
"BirchForestM", "BirchForestM",
}, },
0, 0,
minetest.LIGHT_MAX+1, minetest.LIGHT_MAX+1,
30, 30,
9000, 9000,
7, 7,
mobs_mc.spawn_height.water+3, mobs_mc.spawn_height.water+3,
mobs_mc.spawn_height.overworld_max) mobs_mc.spawn_height.overworld_max)
mobs:register_egg("mobs_mc:wolf", S("Wolf"), "mobs_mc_spawn_icon_wolf.png", 0) mobs:register_egg("mobs_mc:wolf", S("Wolf"), "mobs_mc_spawn_icon_wolf.png", 0)

View File

@ -46,6 +46,7 @@ table.insert(drops_zombie, {
}) })
local zombie = { local zombie = {
description = S("Zombie"),
type = "monster", type = "monster",
spawn_class = "hostile", spawn_class = "hostile",
hp_min = 20, hp_min = 20,
@ -102,6 +103,7 @@ mobs:register_mob("mobs_mc:zombie", zombie)
-- A smaller and more dangerous variant of the zombie -- A smaller and more dangerous variant of the zombie
local baby_zombie = table.copy(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.collisionbox = {-0.25, -0.01, -0.25, 0.25, 0.94, 0.25}
baby_zombie.xp_min = 12 baby_zombie.xp_min = 12
baby_zombie.xp_max = 12 baby_zombie.xp_max = 12
@ -115,6 +117,7 @@ mobs:register_mob("mobs_mc:baby_zombie", baby_zombie)
-- Husk. -- Husk.
-- Desert variant of the zombie -- Desert variant of the zombie
local husk = table.copy(zombie) local husk = table.copy(zombie)
husk.description = S("Husk")
husk.textures = { husk.textures = {
{ {
"mobs_mc_empty.png", -- armor "mobs_mc_empty.png", -- armor
@ -132,6 +135,7 @@ mobs:register_mob("mobs_mc:husk", husk)
-- Baby husk. -- Baby husk.
-- A smaller and more dangerous variant of the husk -- A smaller and more dangerous variant of the husk
local baby_husk = table.copy(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.collisionbox = {-0.25, -0.01, -0.25, 0.25, 0.94, 0.25}
baby_husk.xp_min = 12 baby_husk.xp_min = 12
baby_husk.xp_max = 12 baby_husk.xp_max = 12

View File

@ -11,6 +11,7 @@ local S = minetest.get_translator("mobs_mc")
local pigman = { 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: This combination is needed for a neutral mob which becomes hostile, if attacked
type = "animal", type = "animal",
passive = false, passive = false,
@ -94,6 +95,7 @@ mobs:register_mob("mobs_mc:pigman", pigman)
-- A smaller and more dangerous variant of the pigman -- A smaller and more dangerous variant of the pigman
local baby_pigman = table.copy(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.collisionbox = {-0.25, -0.01, -0.25, 0.25, 0.94, 0.25}
baby_pigman.xp_min = 13 baby_pigman.xp_min = 13
baby_pigman.xp_max = 13 baby_pigman.xp_max = 13
@ -112,33 +114,33 @@ mobs:register_mob("mobs_mc:baby_pigman", baby_pigman)
-- Regular spawning in the Nether -- Regular spawning in the Nether
mobs:spawn_specific( mobs:spawn_specific(
"mobs_mc:pigman", "mobs_mc:pigman",
"nether", "nether",
"ground", "ground",
{ {
"Nether" "Nether"
}, },
0, 0,
minetest.LIGHT_MAX+1, minetest.LIGHT_MAX+1,
30, 30,
6000, 6000,
3, 3,
mobs_mc.spawn_height.nether_min, mobs_mc.spawn_height.nether_min,
mobs_mc.spawn_height.nether_max) mobs_mc.spawn_height.nether_max)
-- Baby zombie is 20 times less likely than regular zombies -- Baby zombie is 20 times less likely than regular zombies
mobs:spawn_specific( mobs:spawn_specific(
"mobs_mc:baby_pigman", "mobs_mc:baby_pigman",
"nether", "nether",
"ground", "ground",
{ {
"Nether" "Nether"
}, },
0, 0,
minetest.LIGHT_MAX+1, minetest.LIGHT_MAX+1,
30, 30,
100000, 100000,
4, 4,
mobs_mc.spawn_height.nether_min, mobs_mc.spawn_height.nether_min,
mobs_mc.spawn_height.nether_max) mobs_mc.spawn_height.nether_max)
-- Spawning in Nether portals in the Overworld -- Spawning in Nether portals in the Overworld

View File

@ -11,7 +11,6 @@ of the license, or (at your option) any later version.
local S = minetest.get_translator("lightning") 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 get_connected_players = minetest.get_connected_players
local line_of_sight = minetest.line_of_sight local line_of_sight = minetest.line_of_sight
local get_node = minetest.get_node local get_node = minetest.get_node
@ -139,48 +138,39 @@ lightning.strike = function(pos)
for o=1, #objs do for o=1, #objs do
local obj = objs[o] local obj = objs[o]
local lua = obj:get_luaentity() local lua = obj:get_luaentity()
if obj:is_player() then -- pig → zombie pigman (no damage)
-- Player damage if lua and lua.name == "mobs_mc:pig" then
if has_mcl_death_msg then local rot = obj:get_yaw()
mcl_death_messages.player_damage(obj, S("@1 was struck by lightning.", obj:get_player_name())) obj:remove()
end obj = add_entity(pos2, "mobs_mc:pigman")
obj:set_hp(obj:get_hp()-5, { type = "punch", from = "mod" }) obj:set_yaw(rot)
-- Mobs
elseif lua and lua._cmi_is_mob then
-- pig → zombie pigman (no damage)
if 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) -- 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 if lua.base_texture[1] == "mobs_mc_mooshroom.png" then
lua.base_texture = { "mobs_mc_mooshroom_brown.png", "mobs_mc_mushroom_brown.png" } lua.base_texture = { "mobs_mc_mooshroom_brown.png", "mobs_mc_mushroom_brown.png" }
else
lua.base_texture = { "mobs_mc_mooshroom.png", "mobs_mc_mushroom_red.png" }
end
obj:set_properties({textures = lua.base_texture})
-- villager → witch (no damage)
elseif lua.name == "mobs_mc:villager" then
-- Witches are incomplete, this code is unused
-- TODO: Enable this code when witches are working.
--[[
local rot = obj:get_yaw()
obj:remove()
obj = minetest.add_entity(pos2, "mobs_mc:witch")
obj:set_yaw(rot)
]]
-- charged creeper
elseif 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
else else
obj:set_hp(obj:get_hp()-5, { type = "punch", from = "mod" }) lua.base_texture = { "mobs_mc_mooshroom.png", "mobs_mc_mushroom_red.png" }
end end
obj:set_properties({textures = lua.base_texture})
-- villager → witch (no damage)
elseif lua and lua.name == "mobs_mc:villager" then
-- Witches are incomplete, this code is unused
-- TODO: Enable this code when witches are working.
--[[
local rot = obj:get_yaw()
obj:remove()
obj = minetest.add_entity(pos2, "mobs_mc:witch")
obj:set_yaw(rot)
]]
-- charged creeper
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 objects: Just damage
else
mcl_util.deal_damage(obj, 5, {type = "lightning_bolt"})
end end
end end

View File

@ -2,5 +2,4 @@ name = lightning
author = sofar author = sofar
description = A mod that adds thunder and lightning effects. description = A mod that adds thunder and lightning effects.
depends = mcl_fire 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 dim_change = mcl_worlds.dimension_change
local is_in_void = mcl_worlds.is_in_void local is_in_void = mcl_worlds.is_in_void
local get_spawn_pos = mcl_spawn.get_player_spawn_pos 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 send_chat = minetest.chat_send_player
local get_connected = minetest.get_connected_players local get_connected = minetest.get_connected_players
@ -40,7 +39,6 @@ minetest.register_on_mods_loaded(function()
end end
self._void_timer = 0 self._void_timer = 0
local pos = obj:get_pos()
local void, void_deadly = is_in_void(pos) local void, void_deadly = is_in_void(pos)
if void_deadly then if void_deadly then
local ent = obj:get_luaentity() local ent = obj:get_luaentity()
@ -80,8 +78,7 @@ minetest.register_globalstep(function(dtime)
elseif enable_damage and not is_immortal then elseif enable_damage and not is_immortal then
-- Damage enabled, not immortal: Deal void damage (4 HP / 0.5 seconds) -- Damage enabled, not immortal: Deal void damage (4 HP / 0.5 seconds)
if player:get_hp() > 0 then if player:get_hp() > 0 then
death_msg(player, S("@1 fell into the endless void.", player:get_player_name())) mcl_util.deal_damage(player, VOID_DAMAGE, {type = "out_of_world"})
player:set_hp(player:get_hp() - VOID_DAMAGE)
end end
end end
end end

View File

@ -1,4 +1,4 @@
name = mcl_void_damage name = mcl_void_damage
author = Wuzzy author = Wuzzy
description = Deal damage to entities stuck in the deep void 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 S = minetest.get_translator("mcl_death_messages")
local N = function(s) return s end
local C = minetest.colorize
local color_skyblue = mcl_colors.AQUA mcl_death_messages = {
assist = {},
local function get_tool_name(item) messages = {
local name = item:get_meta():get_string("name") in_fire = {
if name ~= "" then _translator = S,
return name plain = "@1 went up in flames",
end assist = "@1 walked into fire whilst fighting @2",
local def = item:get_definition() },
return def._tt_original_description or def.description lightning_bolt = {
end _translator = S,
plain = "@1 was struck by lightning",
mcl_death_messages = {} assist = "@1 was struck by lightning whilst fighting @2",
},
-- Death messages on_fire = {
local msgs = { _translator = S,
["arrow"] = { plain = "@1 burned to death",
N("@1 was fatally hit by an arrow."), assist = "@1 was burnt to a crisp whilst fighting @2",
N("@1 has been killed by an arrow."), },
lava = {
_translator = S,
plain = "@1 tried to swim in lava",
assist = "@1 tried to swim in lava to escape @2"
},
hot_floor = {
_translator = S,
plain = "@1 discovered the floor was lava",
assist = "@1 walked into danger zone due to @2",
},
in_wall = {
_translator = S,
plain = "@1 suffocated in a wall",
assist = "@1 suffocated in a wall whilst fighting @2",
},
drown = {
_translator = S,
plain = "@1 drowned",
assist = "@1 drowned whilst trying to escape @2",
},
starve = {
_translator = S,
plain = "@1 starved to death",
assist = "@1 starved to death whilst fighting @2",
},
cactus = {
_translator = S,
plain = "@1 was pricked to death",
assist = "@1 walked into a cactus whilst trying to escape @2",
},
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"
},
fly_into_wall = {
_translator = S,
plain = "@1 experienced kinetic energy",
assist = "@1 experienced kinetic energy whilst trying to escape @2",
},
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",
},
generic = {
_translator = S,
plain = "@1 died",
assist = "@1 died because of @2",
},
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",
},
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.
}, },
["arrow_name"] = {
N("@1 was shot by @2 using [@3]"),
},
["arrow_skeleton"] = {
N("@1 was shot by Skeleton."),
},
["arrow_stray"] = {
N("@1 was shot by Stray."),
},
["arrow_illusioner"] = {
N("@1 was shot by Illusioner."),
},
["arrow_mob"] = {
N("@1 was shot."),
},
["drown"] = {
N("@1 forgot to breathe."),
N("@1 drowned."),
N("@1 ran out of oxygen."),
},
["murder"] = {
N("@1 was slain by @2 using [@3]"),
},
["murder_hand"] = {
N("@1 was slain by @2"),
},
["murder_any"] = {
N("@1 was killed."),
},
["mob_kill"] = {
N("@1 was slain by a mob."),
},
["blaze_fireball"] = {
N("@1 was burned to death by a Blaze's fireball."),
N("@1 was fireballed by a Blaze"),
},
["fire_charge"] = {
N("@1 was burned by a fire charge."),
},
["ghast_fireball"] = {
N("A Ghast scared @1 to death."),
N("@1 has been fireballed by a Ghast."),
},
["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.")
},
["other"] = {
N("@1 died."),
}
} }
local mobkills = { local function get_item_killer_message(obj, messages, reason)
["mobs_mc:zombie"] = N("@1 was slain by Zombie."), if messages.item then
["mobs_mc:baby_zombie"] = N("@1 was slain by Baby Zombie."), local wielded = mcl_util.get_wielded_item(reason.source)
["mobs_mc:blaze"] = N("@1 was burnt to a crisp while fighting Blaze."), local itemname = wielded:get_meta():get_string("name")
["mobs_mc:slime"] = N("@1 was slain by Slime."), if itemname ~= "" then
["mobs_mc:witch"] = N("@1 was slain by Witch using magic."), itemname = "[" .. itemname .. "]"
["mobs_mc:magma_cube_tiny"] = N("@1 was slain by Magma Cube."), if mcl_enchanting.is_enchanted(wielded:get_name()) then
["mobs_mc:magma_cube_small"] = N("@1 was slain by Magma Cube."), itemname = minetest.colorize(mcl_colors.AQUA, itemname)
["mobs_mc:magma_cube_big"] = N("@1 was slain by Magma Cube."), end
["mobs_mc:wolf"] = N("@1 was slain by Wolf."), return messages._translator(messages.item, mcl_util.get_object_name(obj), mcl_util.get_object_name(reason.source), itemname)
["mobs_mc:cat"] = N("@1 was slain by Cat."), end
["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", ...)
end 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) local function get_killer_message(obj, messages, reason)
-- Death message return reason.source and (get_item_killer_message(obj, messages, reason) or get_plain_killer_message(obj, messages, reason))
local message = minetest.settings:get_bool("mcl_showDeathMessages") --Maybe cache the setting? end
if message == nil then
message = true local function get_assist_message(obj, messages, reason)
if messages.assist and mcl_death_messages.assist[obj] then
return messages._translator(messages.assist, mcl_util.get_object_name(obj), mcl_death_messages.assist[obj].name)
end end
if message then end
local name = player:get_player_name()
if not name 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 local function get_plain_message(obj, messages, reason)
if not hitter then return end if messages.plain then
return messages._translator(messages.plain, mcl_util.get_object_name(obj))
end
end
local hittername, hittertype, hittersubtype, shooter local function get_fallback_message(obj, messages, reason)
local hitter_toolname = get_tool_name(hitter:get_wielded_item()) return "mcl_death_messages.messages." .. reason.type .. " " .. mcl_util.get_object_name(obj)
end
-- Custom message local function fallback_translator(s)
if last_damages[name] then return s
msg = last_damages[name].message end
-- Unknown hitter
elseif hitter == nil then mcl_damage.register_on_death(function(obj, reason)
msg = dmsg("murder_any", name) if not minetest.settings:get_bool("mcl_showDeathMessages", true) then
-- Player return
elseif hitter:is_player() then end
hittername = hitter:get_player_name()
if hittername ~= nil then local send_to
if hitter_toolname == "" then
msg = dmsg("murder_hand", name, hittername) if obj:is_player() then
else send_to = true
msg = dmsg("murder", name, hittername, C(color_skyblue, hitter_toolname)) end -- ToDo: add mob death messages for owned mobs, only send to owner (sent_to = "player name")
end
else
msg = dmsg("murder_any", name) if send_to then
end local messages = mcl_death_messages.messages[reason.type] or {}
-- Mob (according to Common Mob Interface) messages._translator = messages._translator or fallback_translator
elseif hitter:get_luaentity()._cmi_is_mob then
if hitter:get_luaentity().nametag and hitter:get_luaentity().nametag ~= "" then local message =
hittername = hitter:get_luaentity().nametag get_killer_message(obj, messages, reason) or
end get_assist_message(obj, messages, reason) or
hittersubtype = hitter:get_luaentity().name get_plain_message(obj, messages, reason) or
if hittername then get_fallback_message(obj, messages, reason)
msg = dmsg("murder_hand", name, hittername)
elseif hittersubtype ~= nil and hittersubtype ~= "" then if send_to == true then
msg = mmsg(hittersubtype, name) minetest.chat_send_all(message)
else else
msg = dmsg("murder_any", name) minetest.chat_send_player(send_to, message)
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 end
if not msg then
msg = dmsg("other", name)
end
minetest.chat_send_all(msg)
last_damages[name] = nil
end end
end) end)
-- dmg_sequence_number is used to discard old damage events mcl_damage.register_on_damage(function(obj, damage, reason)
local dmg_sequence_number = 0 if obj:get_hp() - damage > 0 then
local start_damage_reset_countdown = function (player, sequence_number) if reason.source then
minetest.after(1, function(playername, sequence_number) mcl_death_messages.assist[obj] = {name = mcl_util.get_object_name(reason.source), timeout = 5}
if last_damages[playername] and last_damages[playername].sequence_number == sequence_number then else
last_damages[playername] = nil mcl_death_messages.assist[obj] = nil
end end
end, player:get_player_name(), sequence_number)
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
end end
end end)
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)

View File

@ -1,59 +1,58 @@
# textdomain: mcl_death_messages # textdomain: mcl_death_messages
@1 was fatally hit by an arrow.=@1 wurde tödlich von einem Pfeil getroffen. @1 went up in flames=@1 ging in Flammen auf
@1 has been killed by an arrow.=@1 wurde von einem Pfeil getötet. @1 walked into fire whilst fighting @2=@1 ist während eines Kampfes mit @2 in ein Feuer gelaufen
@1 was shot by an arrow from @2.=@1 wurde mit einem Pfeil von @2 abgeschossen. @1 was struck by lightning=@1 wurde von einem Blitz erschlagen
@1 was shot by an arrow from a skeleton.=@1 wurde von einem Skelett mit Pfeil und Bogen abgeschossen. @1 was struck by lightning whilst fighting @2=@1 wurde während eines Kampfes mit @2 von einem Blitz erschlagen
@1 was shot by an arrow from a stray.=@1 wurde von einem Eiswanderer mit Pfeil und Bogen abgeschossen. @1 burned to death=@1 ist verbrannt
@1 was shot by an arrow from an illusioner.=@1 wurde von einem Illusionisten mit Pfeil und Bogen abgeschossen. @1 was burnt to a crisp whilst fighting @2=@1 ist während eines Kampfes mit @2 verbrannt
@1 was shot by an arrow.=@1 wurde mit einem Pfeil abgeschossen. @1 tried to swim in lava=@1 hat versucht, in Lava zu schwimmen
@1 forgot to breathe.=@1 vergaß, zu atmen. @1 tried to swim in lava to escape @2=@1 hat versucht, in Lava zu schwimmen, um @2 zu entkommen
@1 drowned.=@1 ertrank. @1 discovered the floor was lava=@1 hat festgestellt, dass der Boden Lava ist
@1 ran out of oxygen.=@1 ging die Luft aus. @1 walked into danger zone due to @2=@1 ist wegen @2 in eine Gefahrenzone gelaufen
@1 was killed by @2.=@1 wurde von @2 getötet. @1 suffocated in a wall=@1 ist in einer Mauer erstickt
@1 was killed.=@1 wurde getötet. @1 suffocated in a wall whilst fighting @2=@1 ist während eines Kampfes mit @2 in einer Mauer erstickt
@1 was killed by a mob.=@1 wurde von einem Mob getötet. @1 drowned=@1 ist ertrunken
@1 was burned to death by a blaze's fireball.=@1 wurde von einem Feuerball einer Lohe zu Tode verbrannt. @1 drowned whilst trying to escape @2=@1 ist während dem Versuch, @2 zu entkommen, ertrunken
@1 was killed by a fireball from a blaze.=@1 wurde von einem Feuerball einer Lohe getötet. @1 starved to death=@1 ist verhungert
@1 was burned by a fire charge.=@1 wurde von einer Feuerkugel verbrannt. @1 starved to death whilst fighting @2=@1 ist während eines Kampfes mit @2 verhungert
A ghast scared @1 to death.=Ein Ghast hat @1 zu Tode erschrocken. @1 was pricked to death=@1 wurde zu Tode gestochen
@1 has been fireballed by a ghast.=@1 wurde von einem Ghast mit einer Feuerkugel abgeschossen. @1 walked into a cactus whilst trying to escape @2=@1 ist während dem Versuch, @2 zu entkommen, in einen Kaktus gelaufen
@1 fell from a high cliff.=@1 stürzte von einer hohen Klippe. @1 hit the ground too hard=@1 ist zu hart auf dem Boden aufgetroffen
@1 took fatal fall damage.=@1 nahm tödlichen Fallschaden. @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 fell victim to gravity.=@1 fiel der Schwerkraft zum Opfer. @1 experienced kinetic energy=@1 hat kinetische Energie erfahren
@1 died.=@1 starb. @1 experienced kinetic energy whilst trying to escape @2=@1 hat während dem Versuch, @2 zu entkommen, kinetische Energie erfahren
@1 was killed by a zombie.=@1 wurde von einem Zombie getötet. @1 fell out of the world=@1 ist aus der Welt gefallen
@1 was killed by a baby zombie.=@1 wurde von einem Zombiebaby getötet. @1 didn't want to live in the same world as @2=@1 wollte nicht in der gleichen Welt wie @2 leben
@1 was killed by a blaze.=@1 wurde von einer Lohe getötet. @1 died=@1 ist gestorben
@1 was killed by a slime.=@1 wurde von einem Schleim getötet. @1 died because of @2=@1 ist wegen @2 gestorben
@1 was killed by a witch.=@1 wurde von einer Hexe getötet. @1 was killed by magic=@1 wurde von Magie getötet
@1 was killed by a magma cube.=@1 wurde von einem Magmakubus 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 a wolf.=@1 wurde von einem Wolf getötet. @1 was killed by @2 using magic=@1 wurde von @2 mit Magie getötet
@1 was killed by a cat.=@1 wurde von einer Katze getötet. @1 was killed by @2 using @3=@1 wurde von @2 mit @3 getötet
@1 was killed by an ocelot.=@1 wurde von einem Ozelot getötet. @1 was roasted in dragon breath=@1 wurde in Drachenatem geröstet
@1 was killed by an ender dragon.=@1 wurde von einem Enderdrachen getötet. @1 was roasted in dragon breath by @2=@1 wurde in Drachenatem von @2 geröstet
@1 was killed by a wither.=@1 wurde von einem Wither getötet. @1 withered away=@1 ist davon gewithert
@1 was killed by an enderman.=@1 wurde von einem Enderman getötet. @1 withered away whilst fighting @2=@1 ist während einem Kampf mit @2 davon gewithert
@1 was killed by an endermite.=@1 wurde von einer Endermilbe getötet. @1 was killed by magic=@1 wurde von Magie getötet
@1 was killed by a ghast.=@1 wurde von einem Ghast getötet. @1 was shot by a skull from @2=@1 wurde von einem Schädel von @2 erschossen
@1 was killed by an elder guardian.=@1 wurde von einem Großen Wächter getötet. @1 was squashed by a falling anvil=@1 wurde von einem fallenden Amboss erquetscht
@1 was killed by a guardian.=@1 wurde von einem Wächter getötet. @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 killed by an iron golem.=@1 wurde von einem Eisengolem getötet. @1 was squashed by a falling block=@1 wurde von einem fallenden Block erquetscht
@1 was killed by a polar_bear.=@1 wurde von einem Eisbären getötet. @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 killed by a killer bunny.=@1 wurde von einem Killerkaninchen getötet. @1 was slain by @2=@1 wurde von @2 erschlagen
@1 was killed by a shulker.=@1 wurde von einem Schulker getötet. @1 was slain by @2 using @3=@1 wurde von @2 mit @3 erschlagen
@1 was killed by a silverfish.=@1 wurde von einem Silberfischchen getötet. @1 was slain by @2=@1 wurde von @2 erschlagen
@1 was killed by a skeleton.=@1 wurde von einem Skelett getötet. @1 was slain by @2 using @3=@1 wurde von @2 mit @3 erschlagen
@1 was killed by a stray.=@1 wurde von einem Eiswanderer getötet. @1 was shot by @2=@1 wurde von @2 erschossen
@1 was killed by a slime.=@1 wurde von einem Schleim getötet. @1 was shot by @2 using @3=@1 wurde von @2 mit @3 erschossen
@1 was killed by a spider.=@1 wurde von einer Spinne getötet. @1 was fireballed by @2=@1 wurde von @2 gefeuerballt
@1 was killed by a cave spider.=@1 wurde von einer Höhlenspinne getötet. @1 was fireballed by @2 using @3=@1 wurde von @2 mit @3 gefeuerballt
@1 was killed by a vex.=@1 wurde von einem Plagegeist getötet. @1 was killed trying to hurt @2=@1 ist bei dem Versuch, @2 zu verletzten gestorben
@1 was killed by an evoker.=@1 wurde von einem Magier getötet. @1 was killed by @3 trying to hurt @2=@1 ist bei dem Versuch, @2 zu verletzten, von @3 getötet worden
@1 was killed by an illusioner.=@1 wurde von einem Illusionisten getötet. @1 blew up=@1 ist gesprengt worden
@1 was killed by a vindicator.=@1 wurde von einem Diener getötet. @1 was blown up by @2=@1 wurde von @2 gesprengt
@1 was killed by a zombie villager.=@1 wurde von einem Dorfbewohnerzombie getötet. @1 was blown up by @2 using @3=@1 wurde von @2 mit @3 gesprengt
@1 was killed by a husk.=@1 wurde von einem Wüstenzombie getötet. @1 was squished too much=@1 war zu gequetscht
@1 was killed by a baby husk.=@1 wurde von einem Wüstenzombiebaby getötet. @1 was squashed by @2=@1 wurde von @2 erquetscht
@1 was killed by a zombie pigman.=@1 wurde von einem Schweinezombie getötet. @1 went off with a bang=@1 ging mit einem Knall ab
@1 was killed by a baby zombie pigman.=@1 wurde von einem Schweinezombiebaby getötet. @1 went off with a bang due to a firework fired from @3 by @2=@1 ging mit einem Knall wegen eines Feuerwerks, das mit @3 von @2 gefeuert wurde, ab
@1 was slain by @2.=

View File

@ -1,59 +1,58 @@
# textdomain: mcl_death_messages # textdomain: mcl_death_messages
@1 was fatally hit by an arrow.= @1 went up in flames=
@1 has been killed with an arrow.= @1 walked into fire whilst fighting @2=
@1 was shot by an arrow from @2.= @1 was struck by lightning=
@1 was shot by an arrow from a skeleton.= @1 was struck by lightning whilst fighting @2=
@1 was shot by an arrow from a stray.= @1 burned to death=
@1 was shot by an arrow from an illusioner.= @1 was burnt to a crisp whilst fighting @2=
@1 was shot by an arrow.= @1 tried to swim in lava=
@1 forgot to breathe.= @1 tried to swim in lava to escape @2=
@1 drowned.= @1 discovered the floor was lava=
@1 ran out of oxygen.= @1 walked into danger zone due to @2=
@1 was killed by @2.= @1 suffocated in a wall=
@1 was killed.= @1 suffocated in a wall whilst fighting @2=
@1 was killed by a mob.= @1 drowned=
@1 was burned to death by a blaze's fireball.= @1 drowned whilst trying to escape @2=
@1 was killed by a fireball from a blaze.= @1 starved to death=
@1 was burned by a fire charge.= @1 starved to death whilst fighting @2=
A ghast scared @1 to death.= @1 was pricked to death=
@1 has been fireballed by a ghast.= @1 walked into a cactus whilst trying to escape @2=
@1 fell from a high cliff.= @1 hit the ground too hard=
@1 took fatal fall damage.= @1 hit the ground too hard whilst trying to escape @2=
@1 fell victim to gravity.= @1 experienced kinetic energy=
@1 died.= @1 experienced kinetic energy whilst trying to escape @2=
@1 was killed by a zombie.= @1 fell out of the world=
@1 was killed by a baby zombie.= @1 didn't want to live in the same world as @2=
@1 was killed by a blaze.= @1 died=
@1 was killed by a slime.= @1 died because of @2=
@1 was killed by a witch.= @1 was killed by magic=
@1 was killed by a magma cube.= @1 was killed by magic whilst trying to escape @2=
@1 was killed by a wolf.= @1 was killed by @2 using magic=
@1 was killed by a cat.= @1 was killed by @2 using @3=
@1 was killed by an ocelot.= @1 was roasted in dragon breath=
@1 was killed by an ender dragon.= @1 was roasted in dragon breath by @2=
@1 was killed by a wither.= @1 withered away=
@1 was killed by an enderman.= @1 withered away whilst fighting @2=
@1 was killed by an endermite.= @1 was killed by magic=
@1 was killed by a ghast.= @1 was shot by a skull from @2=
@1 was killed by an elder guardian.= @1 was squashed by a falling anvil=
@1 was killed by a guardian.= @1 was squashed by a falling anvil whilst fighting @2=
@1 was killed by an iron golem.= @1 was squashed by a falling block=
@1 was killed by a polar_bear.= @1 was squashed by a falling block whilst fighting @2=
@1 was killed by a killer bunny.= @1 was slain by @2=
@1 was killed by a shulker.= @1 was slain by @2 using @3=
@1 was killed by a silverfish.= @1 was slain by @2=
@1 was killed by a skeleton.= @1 was slain by @2 using @3=
@1 was killed by a stray.= @1 was shot by @2=
@1 was killed by a slime.= @1 was shot by @2 using @3=
@1 was killed by a spider.= @1 was fireballed by @2=
@1 was killed by a cave spider.= @1 was fireballed by @2 using @3=
@1 was killed by a vex.= @1 was killed trying to hurt @2=
@1 was killed by an evoker.= @1 was killed by @3 trying to hurt @2=
@1 was killed by an illusioner.= @1 blew up=
@1 was killed by a vindicator.= @1 was blown up by @2=
@1 was killed by a zombie villager.= @1 was blown up by @2 using @3=
@1 was killed by a husk.= @1 was squished too much=
@1 was killed by a baby husk.= @1 was squashed by @2=
@1 was killed by a zombie pigman.= @1 went off with a bang=
@1 was killed by a baby zombie pigman.= @1 went off with a bang due to a firework fired from @3 by @2=
@1 was slain by @2.=

View File

@ -263,34 +263,7 @@ function mcl_experience.add_experience(player, experience)
local can = final_candidates[math.random(#final_candidates)] local can = final_candidates[math.random(#final_candidates)]
local stack, list, index, wear = can.stack, can.list, can.index, can.wear local stack, list, index, wear = can.stack, can.list, can.index, can.wear
local unbreaking_level = mcl_enchanting.get_enchantment(stack, "unbreaking") local unbreaking_level = mcl_enchanting.get_enchantment(stack, "unbreaking")
local uses local uses = mcl_util.calculate_durability(itemstack)
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 multiplier = 2 * 65535 / uses local multiplier = 2 * 65535 / uses
local repair = experience * multiplier local repair = experience * multiplier
local new_wear = wear - repair local new_wear = wear - repair

View File

@ -1,9 +1,5 @@
local S = minetest.get_translator("mcl_hbarmor") 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 = {} local mcl_hbarmor = {}
-- HUD statbar values -- 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) 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) function mcl_hbarmor.get_armor(player)
if not player or not armor.def then
return false
end
local name = player:get_player_name() 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 if not pts then
return false return false
else else

View File

@ -7,7 +7,6 @@ local players = {}
-- Containing all the items for each Creative Mode tab -- Containing all the items for each Creative Mode tab
local inventory_lists = {} local inventory_lists = {}
local show_armor = minetest.get_modpath("mcl_armor") ~= nil
local mod_player = minetest.get_modpath("mcl_player") ~= nil local mod_player = minetest.get_modpath("mcl_player") ~= nil
-- Create tables -- 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 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, "") player_preview = mcl_player.get_player_formspec_model(player, 3.9, 1.4, 1.2333, 2.4666, "")
else else
local img, img_player player_preview = "image[3.9,1.4;1.2333,2.4666;"..mcl_player.player_get_preview(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
end end
-- Background images for armor slots (hide if occupied) -- 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]".. main_list = "list[current_player;main;0,3.75;9,3;9]"..
mcl_formspec.get_itemslot_bg(0,3.75,9,3).. mcl_formspec.get_itemslot_bg(0,3.75,9,3)..
-- armor -- armor
"list[detached:"..playername.."_armor;armor;2.5,1.3;1,1;1]".. "list[current_player;armor;2.5,1.3;1,1;1]"..
"list[detached:"..playername.."_armor;armor;2.5,2.75;1,1;2]".. "list[current_player;armor;2.5,2.75;1,1;2]"..
"list[detached:"..playername.."_armor;armor;5.5,1.3;1,1;3]".. "list[current_player;armor;5.5,1.3;1,1;3]"..
"list[detached:"..playername.."_armor;armor;5.5,2.75;1,1;4]".. "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,1.3,1,1)..
mcl_formspec.get_itemslot_bg(2.5,2.75,1,1).. mcl_formspec.get_itemslot_bg(2.5,2.75,1,1)..
mcl_formspec.get_itemslot_bg(5.5,1.3,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 = {} mcl_inventory = {}
local show_armor = minetest.get_modpath("mcl_armor") ~= nil
local mod_player = minetest.get_modpath("mcl_player") ~= nil local mod_player = minetest.get_modpath("mcl_player") ~= nil
local mod_craftguide = minetest.get_modpath("mcl_craftguide") ~= 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 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, "") player_preview = mcl_player.get_player_formspec_model(player, 1.0, 0.0, 2.25, 4.5, "")
else else
local img, img_player player_preview = "image[1.1,0.2;2,4;"..mcl_player.player_get_preview(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
end end
local armor_slots = {"helmet", "chestplate", "leggings", "boots"} 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]".. "background[-0.19,-0.25;9.41,9.49;crafting_formspec_bg.png]"..
player_preview.. player_preview..
--armor --armor
"list[detached:"..player_name.."_armor;armor;0,0;1,1;1]".. "list[current_player;armor;0,0;1,1;1]"..
"list[detached:"..player_name.."_armor;armor;0,1;1,1;2]".. "list[current_player;armor;0,1;1,1;2]"..
"list[detached:"..player_name.."_armor;armor;0,2;1,1;3]".. "list[current_player;armor;0,2;1,1;3]"..
"list[detached:"..player_name.."_armor;armor;0,3;1,1;4]".. "list[current_player;armor;0,3;1,1;4]"..
mcl_formspec.get_itemslot_bg(0,0,1,1).. mcl_formspec.get_itemslot_bg(0,0,1,1)..
mcl_formspec.get_itemslot_bg(0,1,1,1).. mcl_formspec.get_itemslot_bg(0,1,1,1)..
mcl_formspec.get_itemslot_bg(0,2,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")).."]".. "tooltip[__mcl_achievements;"..F(S("Achievements")).."]"..
-- for shortcuts -- for shortcuts
"listring[current_player;main]".. "listring[current_player;main]"..
"listring[current_player;craft]".. "listring[current_player;armor]"..
"listring[current_player;main]".. "listring[current_player;main]" ..
"listring[detached:"..player_name.."_armor;armor]" "listring[current_player;craft]" ..
"listring[current_player;main]"
player:set_inventory_formspec(form) player:set_inventory_formspec(form)
end end
@ -176,18 +159,10 @@ minetest.register_on_joinplayer(function(player)
player:hud_set_hotbar_image("mcl_inventory_hotbar.png") player:hud_set_hotbar_image("mcl_inventory_hotbar.png")
player:hud_set_hotbar_selected_image("mcl_inventory_hotbar_selected.png") player:hud_set_hotbar_selected_image("mcl_inventory_hotbar_selected.png")
if show_armor then local old_update_player = mcl_armor.update_player
local set_player_armor_original = armor.set_player_armor mcl_armor.update_player = function(player, info)
local update_inventory_original = armor.update_inventory old_update_player(player, info)
armor.set_player_armor = function(self, player) set_inventory(player, true)
set_player_armor_original(self, player)
end
armor.update_inventory = function(self, player)
update_inventory_original(self, player)
set_inventory(player, true)
end
armor:set_player_armor(player)
armor:update_inventory(player)
end end
-- In Creative Mode, the initial inventory setup is handled in creative.lua -- In Creative Mode, the initial inventory setup is handled in creative.lua

View File

@ -136,94 +136,32 @@ local dispenserdef = {
-- Hardcoded dispensions -- -- Hardcoded dispensions --
-- Armor, mob heads and pumpkins -- Armor, mob heads and pumpkins
if igroups.armor_head or igroups.armor_torso or igroups.armor_legs or igroups.armor_feet then if igroups.armor then
local armor_type, armor_slot local droppos_below = {x = droppos.x, y = droppos.y - 1, z = droppos.z}
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
local droppos_below = {x=droppos.x, y=droppos.y-1, z=droppos.z} for _, objs in ipairs({minetest.get_objects_inside_radius(droppos, 1), minetest.get_objects_inside_radius(droppos_below, 1)}) do
local dropnode_below = minetest.get_node(droppos_below) for _, obj in ipairs(objs) do
-- Put armor on player or armor stand stack = mcl_armor.equip(stack, obj)
local standpos if stack:is_empty() then
if dropnode.name == "mcl_armor_stand:armor_stand" then
standpos = droppos
elseif dropnode_below.name == "mcl_armor_stand:armor_stand" then
standpos = droppos_below
end
if standpos then
local dropmeta = minetest.get_meta(standpos)
local dropinv = dropmeta:get_inventory()
if dropinv:room_for_item(armor_type, dropitem) then
dropinv:add_item(armor_type, dropitem)
minetest.registered_nodes["mcl_armor_stand:armor_stand"].on_metadata_inventory_put(standpos)
stack:take_item()
inv:set_stack("main", stack_id, stack)
armor:play_equip_sound(dropitem, nil, standpos)
armor_dispensed = true
end
else
-- Put armor on nearby player
-- First search for player in front of dispenser (check 2 nodes)
local objs1 = minetest.get_objects_inside_radius(droppos, 1)
local objs2 = minetest.get_objects_inside_radius(droppos_below, 1)
local objs_table = {objs1, objs2}
local player
for oi=1, #objs_table do
local objs_inner = objs_table[oi]
for o=1, #objs_inner do
--[[ First player in list is the lucky one. The other player get nothing :-(
If multiple players are close to the dispenser, it can be a bit
-- unpredictable on who gets the armor. ]]
if objs_inner[o]:is_player() then
player = objs_inner[o]
break
end
end
if player then
break break
end end
end end
-- If player found, add armor if stack:is_empty() then
if player then break
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 end
end
-- Place head or pumpkin as node, if equipping it as armor has failed -- 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 igroups.head or iname == "mcl_farming:pumpkin_face" then
if dropnodedef.buildable_to then if dropnodedef.buildable_to then
minetest.set_node(droppos, {name = iname, param2 = node.param2}) minetest.set_node(droppos, {name = iname, param2 = node.param2})
stack:take_item() stack:take_item()
inv:set_stack("main", stack_id, stack)
end
end end
end end
end end
inv:set_stack("main", stack_id, stack)
-- Spawn Egg -- Spawn Egg
elseif igroups.spawn_egg then elseif igroups.spawn_egg then
-- Spawn mob -- 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") local S = minetest.get_translator("mcl_armor")
dofile(minetest.get_modpath(minetest.get_current_modname()).."/armor.lua") mcl_armor = {
dofile(minetest.get_modpath(minetest.get_current_modname()).."/alias.lua") 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."),
-- Regisiter Head Armor elements = {
head = {
local longdesc = S("This is a piece of equippable armor which reduces the amount of damage you receive.") name = "helmet",
local usage = S("To equip it, put it on the corresponding armor slot in your inventory menu.") description = "Helmet",
durability = 0.6857,
minetest.register_tool("mcl_armor:elytra", { index = 2,
description = S("Elytra"), craft = function(m)
_doc_items_longdesc = longdesc, return {
_doc_items_usagehelp = usage, { m, m, m},
inventory_image = "mcl_armor_inv_elytra.png", { m, "", m},
groups = {armor_torso=1, mcl_armor_points=0, mcl_armor_uses=10, enchantability=0}, {"", "", ""},
_repair_material = "mcl_mobitems:leather", }
sounds = { end,
_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,
},
legs = {
name = "leggings",
description = "Leggings",
durability = 0.9375,
index = 4,
craft = function(m)
return {
{ m, m, m},
{ m, "", m},
{ m, "", m},
}
end,
},
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, player_view_range_factors = {},
on_secondary_use = armor.on_armor_use,
})
minetest.register_tool("mcl_armor:helmet_leather", {
description = S("Leather Cap"),
_doc_items_longdesc = longdesc,
_doc_items_usagehelp = usage,
inventory_image = "mcl_armor_inv_helmet_leather.png",
groups = {armor_head=1, mcl_armor_points=1, mcl_armor_uses=56, enchantability=15},
_repair_material = "mcl_mobitems:leather",
sounds = {
_mcl_armor_equip = "mcl_armor_equip_leather",
_mcl_armor_unequip = "mcl_armor_unequip_leather",
},
on_place = armor.on_armor_use,
on_secondary_use = armor.on_armor_use,
})
minetest.register_tool("mcl_armor:helmet_iron", {
description = S("Iron Helmet"),
_doc_items_longdesc = longdesc,
_doc_items_usagehelp = usage,
inventory_image = "mcl_armor_inv_helmet_iron.png",
groups = {armor_head=1, mcl_armor_points=2, mcl_armor_uses=166, enchantability=9 },
_repair_material = "mcl_core:iron_ingot",
sounds = {
_mcl_armor_equip = "mcl_armor_equip_iron",
_mcl_armor_unequip = "mcl_armor_unequip_iron",
},
on_place = armor.on_armor_use,
on_secondary_use = armor.on_armor_use,
})
minetest.register_tool("mcl_armor:helmet_gold", {
description = S("Golden Helmet"),
_doc_items_longdesc = longdesc,
_doc_items_usagehelp = usage,
inventory_image = "mcl_armor_inv_helmet_gold.png",
groups = {armor_head=1, mcl_armor_points=2, mcl_armor_uses=78, enchantability=25 },
_repair_material = "mcl_core:gold_ingot",
sounds = {
_mcl_armor_equip = "mcl_armor_equip_iron",
_mcl_armor_unequip = "mcl_armor_unequip_iron",
},
on_place = armor.on_armor_use,
on_secondary_use = armor.on_armor_use,
})
minetest.register_tool("mcl_armor:helmet_diamond",{
description = S("Diamond Helmet"),
_doc_items_longdesc = longdesc,
_doc_items_usagehelp = usage,
inventory_image = "mcl_armor_inv_helmet_diamond.png",
groups = {armor_head=1, mcl_armor_points=3, mcl_armor_uses=364, mcl_armor_toughness=2, enchantability=10 },
_repair_material = "mcl_core:diamond",
sounds = {
_mcl_armor_equip = "mcl_armor_equip_diamond",
_mcl_armor_unequip = "mcl_armor_unequip_diamond",
},
on_place = armor.on_armor_use,
on_secondary_use = armor.on_armor_use,
})
minetest.register_tool("mcl_armor:helmet_chain", {
description = S("Chain Helmet"),
_doc_items_longdesc = longdesc,
_doc_items_usagehelp = usage,
inventory_image = "mcl_armor_inv_helmet_chain.png",
groups = {armor_head=1, mcl_armor_points=2, mcl_armor_uses=166, enchantability=12 },
_repair_material = "mcl_core:iron_ingot",
sounds = {
_mcl_armor_equip = "mcl_armor_equip_chainmail",
_mcl_armor_unequip = "mcl_armor_unequip_chainmail",
},
on_place = armor.on_armor_use,
on_secondary_use = armor.on_armor_use,
})
-- Regisiter Torso Armor
minetest.register_tool("mcl_armor:chestplate_leather", {
description = S("Leather Tunic"),
_doc_items_longdesc = longdesc,
_doc_items_usagehelp = usage,
inventory_image = "mcl_armor_inv_chestplate_leather.png",
groups = {armor_torso=1, mcl_armor_points=3, mcl_armor_uses=81, enchantability=15 },
_repair_material = "mcl_mobitems:leather",
sounds = {
_mcl_armor_equip = "mcl_armor_equip_leather",
_mcl_armor_unequip = "mcl_armor_unequip_leather",
},
on_place = armor.on_armor_use,
on_secondary_use = armor.on_armor_use,
})
minetest.register_tool("mcl_armor:chestplate_iron", {
description = S("Iron Chestplate"),
_doc_items_longdesc = longdesc,
_doc_items_usagehelp = usage,
inventory_image = "mcl_armor_inv_chestplate_iron.png",
groups = {armor_torso=1, mcl_armor_points=6, mcl_armor_uses=241, enchantability=9 },
_repair_material = "mcl_core:iron_ingot",
sounds = {
_mcl_armor_equip = "mcl_armor_equip_iron",
_mcl_armor_unequip = "mcl_armor_unequip_iron",
},
on_place = armor.on_armor_use,
on_secondary_use = armor.on_armor_use,
})
minetest.register_tool("mcl_armor:chestplate_gold", {
description = S("Golden Chestplate"),
_doc_items_longdesc = longdesc,
_doc_items_usagehelp = usage,
inventory_image = "mcl_armor_inv_chestplate_gold.png",
groups = {armor_torso=1, mcl_armor_points=5, mcl_armor_uses=113, enchantability=25 },
_repair_material = "mcl_core:gold_ingot",
sounds = {
_mcl_armor_equip = "mcl_armor_equip_iron",
_mcl_armor_unequip = "mcl_armor_unequip_iron",
},
on_place = armor.on_armor_use,
on_secondary_use = armor.on_armor_use,
})
minetest.register_tool("mcl_armor:chestplate_diamond",{
description = S("Diamond Chestplate"),
_doc_items_longdesc = longdesc,
_doc_items_usagehelp = usage,
inventory_image = "mcl_armor_inv_chestplate_diamond.png",
groups = {armor_torso=1, mcl_armor_points=8, mcl_armor_uses=529, mcl_armor_toughness=2, enchantability=10 },
_repair_material = "mcl_core:diamond",
sounds = {
_mcl_armor_equip = "mcl_armor_equip_diamond",
_mcl_armor_unequip = "mcl_armor_unequip_diamond",
},
on_place = armor.on_armor_use,
on_secondary_use = armor.on_armor_use,
})
minetest.register_tool("mcl_armor:chestplate_chain", {
description = S("Chain Chestplate"),
_doc_items_longdesc = longdesc,
_doc_items_usagehelp = usage,
inventory_image = "mcl_armor_inv_chestplate_chain.png",
groups = {armor_torso=1, mcl_armor_points=5, mcl_armor_uses=241, enchantability=12 },
_repair_material = "mcl_core:iron_ingot",
sounds = {
_mcl_armor_equip = "mcl_armor_equip_chainmail",
_mcl_armor_unequip = "mcl_armor_unequip_chainmail",
},
on_place = armor.on_armor_use,
on_secondary_use = armor.on_armor_use,
})
-- Regisiter Leg Armor
minetest.register_tool("mcl_armor:leggings_leather", {
description = S("Leather Pants"),
_doc_items_longdesc = longdesc,
_doc_items_usagehelp = usage,
inventory_image = "mcl_armor_inv_leggings_leather.png",
groups = {armor_legs=1, mcl_armor_points=2, mcl_armor_uses=76, enchantability=15 },
_repair_material = "mcl_mobitems:leather",
sounds = {
_mcl_armor_equip = "mcl_armor_equip_leather",
_mcl_armor_unequip = "mcl_armor_unequip_leather",
},
on_place = armor.on_armor_use,
on_secondary_use = armor.on_armor_use,
})
minetest.register_tool("mcl_armor:leggings_iron", {
description = S("Iron Leggings"),
_doc_items_longdesc = longdesc,
_doc_items_usagehelp = usage,
inventory_image = "mcl_armor_inv_leggings_iron.png",
groups = {armor_legs=1, mcl_armor_points=5, mcl_armor_uses=226, enchantability=9 },
_repair_material = "mcl_core:iron_ingot",
sounds = {
_mcl_armor_equip = "mcl_armor_equip_iron",
_mcl_armor_unequip = "mcl_armor_unequip_iron",
},
on_place = armor.on_armor_use,
on_secondary_use = armor.on_armor_use,
})
minetest.register_tool("mcl_armor:leggings_gold", {
description = S("Golden Leggings"),
_doc_items_longdesc = longdesc,
_doc_items_usagehelp = usage,
inventory_image = "mcl_armor_inv_leggings_gold.png",
groups = {armor_legs=1, mcl_armor_points=3, mcl_armor_uses=106, enchantability=25 },
_repair_material = "mcl_core:gold_ingot",
sounds = {
_mcl_armor_equip = "mcl_armor_equip_iron",
_mcl_armor_unequip = "mcl_armor_unequip_iron",
},
on_place = armor.on_armor_use,
on_secondary_use = armor.on_armor_use,
})
minetest.register_tool("mcl_armor:leggings_diamond",{
description = S("Diamond Leggings"),
_doc_items_longdesc = longdesc,
_doc_items_usagehelp = usage,
inventory_image = "mcl_armor_inv_leggings_diamond.png",
groups = {armor_legs=1, mcl_armor_points=6, mcl_armor_uses=496, mcl_armor_toughness=2, enchantability=10 },
_repair_material = "mcl_core:diamond",
sounds = {
_mcl_armor_equip = "mcl_armor_equip_diamond",
_mcl_armor_unequip = "mcl_armor_unequip_diamond",
},
on_place = armor.on_armor_use,
on_secondary_use = armor.on_armor_use,
})
minetest.register_tool("mcl_armor:leggings_chain", {
description = S("Chain Leggings"),
_doc_items_longdesc = longdesc,
_doc_items_usagehelp = usage,
inventory_image = "mcl_armor_inv_leggings_chain.png",
groups = {armor_legs=1, mcl_armor_points=4, mcl_armor_uses=226, enchantability=12 },
_repair_material = "mcl_core:iron_ingot",
sounds = {
_mcl_armor_equip = "mcl_armor_equip_chainmail",
_mcl_armor_unequip = "mcl_armor_unequip_chainmail",
},
on_place = armor.on_armor_use,
on_secondary_use = armor.on_armor_use,
})
-- Regisiter Boots
minetest.register_tool("mcl_armor:boots_leather", {
description = S("Leather Boots"),
_doc_items_longdesc = longdesc,
_doc_items_usagehelp = usage,
inventory_image = "mcl_armor_inv_boots_leather.png",
groups = {armor_feet=1, mcl_armor_points=1, mcl_armor_uses=66, enchantability=15 },
_repair_material = "mcl_mobitems:leather",
sounds = {
_mcl_armor_equip = "mcl_armor_equip_leather",
_mcl_armor_unequip = "mcl_armor_unequip_leather",
},
on_place = armor.on_armor_use,
on_secondary_use = armor.on_armor_use,
})
minetest.register_tool("mcl_armor:boots_iron", {
description = S("Iron Boots"),
_doc_items_longdesc = longdesc,
_doc_items_usagehelp = usage,
inventory_image = "mcl_armor_inv_boots_iron.png",
groups = {armor_feet=1, mcl_armor_points=2, mcl_armor_uses=196, enchantability=9 },
_repair_material = "mcl_core:iron_ingot",
sounds = {
_mcl_armor_equip = "mcl_armor_equip_iron",
_mcl_armor_unequip = "mcl_armor_unequip_iron",
},
on_place = armor.on_armor_use,
on_secondary_use = armor.on_armor_use,
})
minetest.register_tool("mcl_armor:boots_gold", {
description = S("Golden Boots"),
_doc_items_longdesc = longdesc,
_doc_items_usagehelp = usage,
inventory_image = "mcl_armor_inv_boots_gold.png",
groups = {armor_feet=1, mcl_armor_points=1, mcl_armor_uses=92, enchantability=25 },
_repair_material = "mcl_core:gold_ingot",
sounds = {
_mcl_armor_equip = "mcl_armor_equip_iron",
_mcl_armor_unequip = "mcl_armor_unequip_iron",
},
on_place = armor.on_armor_use,
on_secondary_use = armor.on_armor_use,
})
minetest.register_tool("mcl_armor:boots_diamond",{
description = S("Diamond Boots"),
_doc_items_longdesc = longdesc,
_doc_items_usagehelp = usage,
inventory_image = "mcl_armor_inv_boots_diamond.png",
groups = {armor_feet=1, mcl_armor_points=3, mcl_armor_uses=430, mcl_armor_toughness=2, enchantability=10 },
_repair_material = "mcl_core:diamond",
sounds = {
_mcl_armor_equip = "mcl_armor_equip_diamond",
_mcl_armor_unequip = "mcl_armor_unequip_diamond",
},
on_place = armor.on_armor_use,
on_secondary_use = armor.on_armor_use,
})
minetest.register_tool("mcl_armor:boots_chain", {
description = S("Chain Boots"),
_doc_items_longdesc = longdesc,
_doc_items_usagehelp = usage,
inventory_image = "mcl_armor_inv_boots_chain.png",
groups = {armor_feet=1, mcl_armor_points=1, mcl_armor_uses=196, enchantability=12 },
_repair_material = "mcl_core:iron_ingot",
sounds = {
_mcl_armor_equip = "mcl_armor_equip_chainmail",
_mcl_armor_unequip = "mcl_armor_unequip_chainmail",
},
on_place = armor.on_armor_use,
on_secondary_use = armor.on_armor_use,
})
-- Register Craft Recipies
local craft_ingreds = {
leather = { "mcl_mobitems:leather" },
iron = { "mcl_core:iron_ingot", "mcl_core:iron_nugget" },
gold = { "mcl_core:gold_ingot", "mcl_core:gold_nugget" },
diamond = { "mcl_core:diamond" },
chain = { nil, "mcl_core:iron_nugget"} ,
} }
for k, v in pairs(craft_ingreds) do local modpath = minetest.get_modpath("mcl_armor")
-- material
local m = v[1] dofile(modpath .. "/api.lua")
-- cooking result dofile(modpath .. "/player.lua")
local c = v[2] dofile(modpath .. "/damage.lua")
if m ~= nil then dofile(modpath .. "/register.lua")
minetest.register_craft({ dofile(modpath .. "/alias.lua")
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

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 S = minetest.get_translator("mcl_armor_stand")
local elements = {"head", "torso", "legs", "feet"} -- Spawn a stand entity
local function spawn_stand_entity(pos, node)
local function get_stand_object(pos) local luaentity = minetest.add_entity(pos, "mcl_armor_stand:armor_entity"):get_luaentity()
local object = nil luaentity:update_rotation(node or minetest.get_node(pos))
local objects = minetest.get_objects_inside_radius(pos, 0.5) or {} return luaentity
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
end end
local function update_entity(pos) -- Find a stand entity or spawn one
local node = minetest.get_node(pos) local function get_stand_entity(pos, node)
local object = get_stand_object(pos) for _, obj in ipairs(minetest.get_objects_inside_radius(pos, 0)) do
if object then local luaentity = obj:get_luaentity()
if not string.find(node.name, "mcl_armor_stand:") then if luaentity and luaentity.name == "mcl_armor_stand:armor_entity" then
object:remove() return luaentity
return
end end
else
object = minetest.add_entity(pos, "mcl_armor_stand:armor_entity")
end end
if object then return spawn_stand_entity(pos, node)
local texture = "blank.png" end
local textures = {}
local meta = minetest.get_meta(pos) -- Migrate the old inventory format
local inv = meta:get_inventory() local function migrate_inventory(inv)
local yaw = 0 inv:set_size("armor", 5)
if inv then local lists = inv:get_lists()
for _, element in pairs(elements) do for name, element in pairs(mcl_armor.elements) do
local stack = inv:get_stack("armor_"..element, 1) local listname = "armor_" .. name
if stack:get_count() == 1 then local list = lists[listname]
local item = stack:get_name() or "" if list then
if minetest.registered_aliases[item] then inv:set_stack("armor", element.index, list[1])
item = minetest.registered_aliases[item] inv:set_size(listname, 0)
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")
end
end
end
end end
if #textures > 0 then
texture = table.concat(textures, "^")
end
if node.param2 then
local rot = node.param2 % 4
if rot == 1 then
yaw = 3 * math.pi / 2
elseif rot == 2 then
yaw = math.pi
elseif rot == 3 then
yaw = math.pi / 2
end
end
object:set_yaw(yaw)
object:set_properties({textures={texture}})
end end
end end
-- Drop all armor of the armor stand on the ground -- Drop all armor on the ground when it got destroyed
local drop_armor = function(pos) local function drop_inventory(pos)
local meta = minetest.get_meta(pos) local inv = minetest.get_meta(pos):get_inventory()
local inv = meta:get_inventory() for _, stack in pairs(inv:get_list("armor")) do
for _, element in pairs(elements) do
local stack = inv:get_stack("armor_"..element, 1)
if not stack:is_empty() then 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} 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) minetest.add_item(p, stack)
@ -111,136 +68,26 @@ minetest.register_node("mcl_armor_stand:armor_stand", {
_mcl_hardness = 2, _mcl_hardness = 2,
sounds = mcl_sounds.node_sound_wood_defaults(), sounds = mcl_sounds.node_sound_wood_defaults(),
on_construct = function(pos) on_construct = function(pos)
local meta = minetest.get_meta(pos) spawn_stand_entity(pos)
local inv = meta:get_inventory() end,
for _, element in pairs(elements) do on_destruct = function(pos)
inv:set_size("armor_"..element, 1) drop_inventory(pos)
end
end, 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) on_rightclick = function(pos, node, clicker, itemstack, pointed_thing)
local protname = clicker:get_player_name() local protname = clicker:get_player_name()
if minetest.is_protected(pos, protname) then if minetest.is_protected(pos, protname) then
minetest.record_protection_violation(pos, protname) minetest.record_protection_violation(pos, protname)
return itemstack return itemstack
end end
local inv = minetest.get_inventory({type = "node", pos = pos}) return mcl_armor.equip(itemstack, get_stand_entity(pos, node).object, true)
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
end, end,
on_rotate = function(pos, node, user, mode) on_rotate = function(pos, node, user, mode)
if mode == screwdriver.ROTATE_FACE then if mode == screwdriver.ROTATE_FACE then
node.param2 = (node.param2 + 1) % 4 node.param2 = (node.param2 + 1) % 4
minetest.swap_node(pos, node) minetest.swap_node(pos, node)
update_entity(pos) get_stand_entity(pos, node):update_rotation(node)
return true return true
end end
return false return false
@ -248,50 +95,44 @@ minetest.register_node("mcl_armor_stand:armor_stand", {
}) })
minetest.register_entity("mcl_armor_stand:armor_entity", { minetest.register_entity("mcl_armor_stand:armor_entity", {
physical = true, initial_properties = {
visual = "mesh", physical = true,
mesh = "3d_armor_entity.obj", visual = "mesh",
visual_size = {x=1, y=1}, mesh = "3d_armor_entity.obj",
collisionbox = {-0.1,-0.4,-0.1, 0.1,1.3,0.1}, visual_size = {x=1, y=1},
pointable = false, collisionbox = {-0.1,-0.4,-0.1, 0.1,1.3,0.1},
textures = {"blank.png"}, pointable = false,
pos = nil, textures = {"blank.png"},
timer = 0, timer = 0,
static_save = false,
},
on_activate = function(self) on_activate = function(self)
local pos = self.object:get_pos() self.object:set_armor_groups({immortal = 1})
self.object:set_armor_groups({immortal=1}) self.node_pos = vector.round(self.object:get_pos())
if pos then self.inventory = minetest.get_meta(self.node_pos):get_inventory()
self.pos = vector.round(pos) migrate_inventory(self.inventory)
update_entity(pos) mcl_armor.update(self.object)
end
end, end,
on_step = function(self, dtime) on_step = function(self, dtime)
if not self.pos then if minetest.get_node(self.node_pos).name ~= "mcl_armor_stand:armor_stand" 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)
self.object:remove() self.object:remove()
end end
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({ minetest.register_lbm({
label = "Respawn armor stand entities", label = "Respawn armor stand entities",
name = "mcl_armor_stand:respawn_entities", name = "mcl_armor_stand:respawn_entities",
nodenames = {"mcl_armor_stand:armor_stand"}, nodenames = {"mcl_armor_stand:armor_stand"},
run_at_every_load = true, run_at_every_load = true,
action = function(pos, node) action = function(pos, node)
update_entity(pos, node) spawn_stand_entity(pos, node)
end, end,
}) })
@ -304,7 +145,6 @@ minetest.register_craft({
} }
}) })
-- Legacy handling -- Legacy handling
minetest.register_alias("3d_armor_stand:armor_stand", "mcl_armor_stand:armor_stand") minetest.register_alias("3d_armor_stand:armor_stand", "mcl_armor_stand:armor_stand")
minetest.register_entity(":3d_armor_stand:armor_entity", { 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 _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. _stuckin=nil, --Position of node in which arow is stuck.
_shooter=nil, -- ObjectRef of player or mob who shot it _shooter=nil, -- ObjectRef of player or mob who shot it
_is_arrow = true,
_viscosity=0, -- Viscosity of node the arrow is currently in _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 _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. -- Punch target object but avoid hurting enderman.
if not lua or lua.name ~= "mobs_mc:enderman" then 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 if self._in_player == false then
damage_particles(self.object:get_pos(), self._is_critical) damage_particles(self.object:get_pos(), self._is_critical)
end 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) obj:set_yaw(yaw-math.pi/2)
local le = obj:get_luaentity() local le = obj:get_luaentity()
le._shooter = shooter le._shooter = shooter
le._source_object = shooter
le._damage = damage le._damage = damage
le._is_critical = is_critical le._is_critical = is_critical
le._startpos = pos 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, _mcl_node_death_message = lava_death_messages,
post_effect_color = {a=245, r=208, g=73, b=10}, post_effect_color = {a=245, r=208, g=73, b=10},
stack_max = 64, 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, _mcl_blast_resistance = 100,
-- Hardness intentionally set to infinite instead of 100 (Minecraft value) to avoid problems in creative mode -- Hardness intentionally set to infinite instead of 100 (Minecraft value) to avoid problems in creative mode
_mcl_hardness = -1, _mcl_hardness = -1,

View File

@ -10,25 +10,6 @@ local function increase_damage(damage_group, factor)
end end
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 -- implemented via on_enchant and additions in mobs_mc; Slowness IV part unimplemented
mcl_enchanting.enchantments.bane_of_arthropods = { mcl_enchanting.enchantments.bane_of_arthropods = {
name = S("Bane of Arthropods"), name = S("Bane of Arthropods"),
@ -48,25 +29,6 @@ mcl_enchanting.enchantments.bane_of_arthropods = {
inv_tool_tab = false, 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 -- requires missing MineClone2 feature
--[[mcl_enchanting.enchantments.channeling = { --[[mcl_enchanting.enchantments.channeling = {
name = S("Channeling"), name = S("Channeling"),
@ -86,25 +48,6 @@ mcl_enchanting.enchantments.blast_protection = {
inv_tool_tab = false, 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 -- implemented in mcl_death_drop
mcl_enchanting.enchantments.curse_of_vanishing = { mcl_enchanting.enchantments.curse_of_vanishing = {
name = S("Curse of Vanishing"), name = S("Curse of Vanishing"),
@ -164,24 +107,6 @@ mcl_enchanting.enchantments.efficiency = {
inv_tool_tab = true, 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 -- implemented in mcl_mobs and via register_on_punchplayer callback
mcl_enchanting.enchantments.fire_aspect = { mcl_enchanting.enchantments.fire_aspect = {
name = S("Fire Aspect"), name = S("Fire Aspect"),
@ -207,31 +132,12 @@ minetest.register_on_punchplayer(function(player, hitter, time_from_last_punch,
if wielditem then if wielditem then
local fire_aspect_level = mcl_enchanting.get_enchantment(wielditem, "fire_aspect") local fire_aspect_level = mcl_enchanting.get_enchantment(wielditem, "fire_aspect")
if fire_aspect_level > 0 then 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
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 = { mcl_enchanting.enchantments.flame = {
name = S("Flame"), name = S("Flame"),
max_level = 1, max_level = 1,
@ -530,44 +436,6 @@ mcl_enchanting.enchantments.power = {
inv_tool_tab = false, 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 -- implemented via minetest.calculate_knockback (together with the Knockback enchantment) and mcl_bows
mcl_enchanting.enchantments.punch = { mcl_enchanting.enchantments.punch = {
name = S("Punch"), name = S("Punch"),
@ -739,25 +607,6 @@ mcl_enchanting.enchantments.soul_speed = {
inv_tool_tab = false, 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 -- 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 = { mcl_enchanting.enchantments.unbreaking = {
name = S("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_creative_inventory = 1
new_def.groups.not_in_craft_guide = 1 new_def.groups.not_in_craft_guide = 1
new_def.groups.enchanted = 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._mcl_enchanting_enchanted_tool = new_name
new_def.after_use = get_after_use_callback(itemdef) new_def.after_use = get_after_use_callback(itemdef)
local register_list = register_item_list 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_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._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.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.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_factor = 0
pumpkin_face_base_def._mcl_armor_mob_range_mob = "mobs_mc:enderman" 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 pumpkin_face_base_def.groups.non_combat_armor=1
if minetest.get_modpath("mcl_armor") then 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 end
-- Register stem growth -- Register stem growth

View File

@ -5,7 +5,7 @@ local mod_screwdriver = minetest.get_modpath("screwdriver")
local equip_armor local equip_armor
if minetest.get_modpath("mcl_armor") then if minetest.get_modpath("mcl_armor") then
equip_armor = armor.on_armor_use equip_armor = mcl_armor.equip_on_use
end end
-- Heads system -- 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, }, { -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. -- The head textures are based off the textures of an actual mob.
tiles = { tiles = {
-- Note: bottom texture is overlaid over top texture to get rid of possible transparency. -- 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_mob = rangemob,
_mcl_armor_mob_range_factor = rangefactor, _mcl_armor_mob_range_factor = rangefactor,
_mcl_armor_element = "head",
_mcl_blast_resistance = 1, _mcl_blast_resistance = 1,
_mcl_hardness = 1, _mcl_hardness = 1,
}) })

View File

@ -1,6 +1,5 @@
local S = minetest.get_translator("mcl_nether") 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 mod_screwdriver = minetest.get_modpath("screwdriver") ~= nil
local on_rotate local on_rotate
if mod_screwdriver then if mod_screwdriver then
@ -111,10 +110,7 @@ minetest.register_node("mcl_nether:magma", {
end end
-- Hurt players standing on top of this block -- Hurt players standing on top of this block
if player:get_hp() > 0 then if player:get_hp() > 0 then
if mod_death_messages then mcl_util.deal_damage(player, 1, {type = "hot_floor"})
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" })
end end
end, end,
_mcl_blast_resistance = 0.5, _mcl_blast_resistance = 0.5,

View File

@ -1,3 +1,3 @@
name = mcl_nether name = mcl_nether
depends = mcl_core, mcl_sounds, mcl_util, walkover, doc_items, mcl_colors 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 player:get_pos() then mcl_potions._add_spawner(player, "#225533") end
if EF.poisoned[player].hit_timer >= EF.poisoned[player].step then if EF.poisoned[player].hit_timer >= EF.poisoned[player].step then
if mcl_util.get_hp(player) - 1 > 0 then
if entity and entity._cmi_is_mob then mcl_util.deal_damage(player, 1, {type = "magic"})
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
end end
EF.poisoned[player].hit_timer = 0
end end
if EF.poisoned[player] and EF.poisoned[player].timer >= EF.poisoned[player].dur then if EF.poisoned[player] and EF.poisoned[player].timer >= EF.poisoned[player].dur then
@ -351,37 +344,12 @@ minetest.register_globalstep(function(dtime)
end) 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 -- Prevent damage to player with Fire Resistance enabled
minetest.register_on_player_hpchange(function(player, hp_change, reason) 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
if EF.fire_proof[player] and hp_change < 0 then return 0
-- 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
return 0
else
return hp_change
end
else
return hp_change
end end
end, -50)
end, true)
@ -603,21 +571,18 @@ function mcl_potions.make_invisible(player, toggle)
return return
end end
if minetest.get_modpath("mcl_armor") and player:is_player() then if player:is_player() then
armor.textures[playername].skin = skin_file mcl_player.player_set_skin(player, "mobs_mc_empty.png")
armor:update_player_visuals(player) elseif not player:is_player() then
elseif not player:is_player() and minetest.get_modpath("mcl_armor") or not player:is_player() and not minetest.get_modpath("mcl_armor") then
player:set_properties({visual_size = {x = 0, y = 0}}) player:set_properties({visual_size = {x = 0, y = 0}})
end end
player:set_nametag_attributes({color = {a = 0}}) player:set_nametag_attributes({color = {a = 0}})
elseif EF.invisible[player] then -- show player elseif EF.invisible[player] then -- show player
if minetest.get_modpath("mcl_armor") and player:is_player() then if player:is_player() then
skin_file = mcl_skins.skins[playername] .. ".png" mcl_skins.update_player_skin(player)
armor.textures[playername].skin = skin_file elseif not player:is_player() then
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
player:set_properties({visual_size = EF.invisible[player].old_size}) player:set_properties({visual_size = EF.invisible[player].old_size})
end end
player:set_nametag_attributes({color = {r = 255, g = 255, b = 255, a = 255}}) 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 hp = -1
end end
if obj and obj._cmi_is_mob then mcl_util.deal_damage(obj, -hp, {type = "magic"})
obj.health = obj.health + hp
elseif player:is_player() then
player:set_hp(player:get_hp() + hp, { type = "punch", other = "harming" })
end
end end
end end

View File

@ -1,3 +1,3 @@
name = mcl_tnt name = mcl_tnt
depends = mcl_explosions, mcl_particles 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. local hud_totem = {}
-- TODO: Add full item definition here when status effects become a thing.
-- Add group for Creative Mode. minetest.register_on_leaveplayer(function(player)
minetest.override_item("mobs_mc:totem", {groups = { combat_item=1}}) 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 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 S = minetest.get_translator("mcl_commands")
local mod_death_messages = minetest.get_modpath("mcl_death_messages")
local function handle_kill_command(suspect, victim) local function handle_kill_command(suspect, victim)
if minetest.settings:get_bool("enable_damage") == false then 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 if wield:get_name() == "mobs_mc:totem" then
victimref:set_wielded_item("") victimref:set_wielded_item("")
end 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! -- DIE!
victimref:set_hp(0) victimref:set_hp(0, {_mcl_type = "out_of_world"})
-- Log -- Log
if not suspect == victim then if not suspect == victim then
minetest.log("action", string.format("%s killed %s using /kill", suspect, victim)) minetest.log("action", string.format("%s killed %s using /kill", suspect, victim))
@ -56,4 +46,4 @@ minetest.register_chatcommand("kill", {
return handle_kill_command(name, param) return handle_kill_command(name, param)
end end
end, end,
}) })

View File

@ -1,4 +1,3 @@
name = mcl_commands name = mcl_commands
author = Wuzzy author = Wuzzy
description = MCL2 commands 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", "main", true)
mcl_death_drop.register_dropped_list("PLAYER", "craft", 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("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) minetest.register_on_dieplayer(function(player)
local keep = minetest.settings:get_bool("mcl_keepInventory", false) local keep = minetest.settings:get_bool("mcl_keepInventory", false)
@ -50,7 +49,6 @@ minetest.register_on_dieplayer(function(player)
inv:set_list(listname, {}) inv:set_list(listname, {})
end end
end end
armor:set_player_armor(player) mcl_armor.update(player)
armor:update_inventory(player)
end end
end) end)

View File

@ -1,5 +1,4 @@
local S = minetest.get_translator("mcl_hunger") 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) -- 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) 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 -- Deal damage and exhaust player
-- TODO: Introduce fatal poison at higher difficulties -- TODO: Introduce fatal poison at higher difficulties
if player:get_hp()-damage > 0 then if player:get_hp()-damage > 0 then
if mod_death_messages then mcl_util.deal_damage(player, damage, {type = "hunger"})
mcl_death_messages.player_damage(player, S("@1 succumbed to the poison.", name))
end
player:set_hp(player:get_hp()-damage)
end end
mcl_hunger.exhaust(name, exhaustion) mcl_hunger.exhaust(name, exhaustion)

View File

@ -1,5 +1,4 @@
local S = minetest.get_translator("mcl_hunger") local S = minetest.get_translator("mcl_hunger")
local mod_death_messages = minetest.get_modpath("mcl_death_messages")
mcl_hunger = {} mcl_hunger = {}
@ -159,10 +158,7 @@ minetest.register_globalstep(function(dtime)
-- Damage hungry player down to 1 HP -- Damage hungry player down to 1 HP
-- TODO: Allow starvation at higher difficulty levels -- TODO: Allow starvation at higher difficulty levels
if hp-1 > 0 then if hp-1 > 0 then
if mod_death_messages then mcl_util.deal_damage(player, 1, {type = "starve"})
mcl_death_messages.player_damage(player, S("@1 starved to death.", name))
end
player:set_hp(hp-1)
end end
end end
end end

View File

@ -2,4 +2,3 @@ name = mcl_hunger
author = BlockMen author = BlockMen
description = Adds a simple hunger meachanic with satiation, food poisoning and different healing. description = Adds a simple hunger meachanic with satiation, food poisoning and different healing.
depends = hudbars 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 player_model[name] = model_name
end end
function mcl_player.player_set_textures(player, textures, preview) local function set_texture(player, index, texture)
local name = player:get_player_name() local textures = player_textures[player:get_player_name()]
player_textures[name] = textures textures[index] = texture
player:set_properties({textures = textures,}) player:set_properties({textures = textures})
if preview then end
player:get_meta():set_string("mcl_player:preview", preview)
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 end
function mcl_player.player_get_preview(player) function mcl_player.player_get_preview(player)
local preview = player:get_meta():get_string("mcl_player:preview") local preview = player:get_meta():get_string("mcl_player:skin_preview")
if preview == nil or preview == "" then if preview == "" then
return "player.png" preview = "player.png"
else
return preview
end 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 end
function mcl_player.get_player_formspec_model(player, x, y, w, h, fsname) function mcl_player.get_player_formspec_model(player, x, y, w, h, fsname)
@ -129,8 +148,10 @@ end
-- Update appearance when the player joins -- Update appearance when the player joins
minetest.register_on_joinplayer(function(player) 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") 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_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>>>> player:set_fov(86.1) -- see <https://minecraft.gamepedia.com/Options#Video_settings>>>>
end) end)
@ -222,62 +243,3 @@ minetest.register_globalstep(function(dtime)
end end
end 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 name = mcl_playerinfo
author = TenPlus1 author = TenPlus1
description = This is a helper mod for other mod to query the nodes around the player. 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 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) minetest.register_globalstep(function(dtime)
time = time + dtime time = time + dtime
@ -166,6 +135,7 @@ minetest.register_globalstep(function(dtime)
local parent = player:get_attach() local parent = player:get_attach()
local wielded = player:get_wielded_item() local wielded = player:get_wielded_item()
local player_velocity = player:get_velocity() or player:get_player_velocity() 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)) 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") playerphysics.remove_physics_factor(player, "gravity", "mcl_playerplus:elytra")
end 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() player_velocity_old = player:get_velocity() or player:get_player_velocity()
-- controls right and left arms pitch when shooting a bow -- 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 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)) 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 -- Check privilege, too
and (not check_player_privs(name, {noclip = true})) then and (not check_player_privs(name, {noclip = true})) then
if player:get_hp() > 0 then if player:get_hp() > 0 then
mcl_death_messages.player_damage(player, S("@1 suffocated to death.", name)) mcl_util.deal_damage(player, 1, {type = "in_wall"})
player:set_hp(player:get_hp() - 1)
end end
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) 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 dist < 1.1 or dist_feet < 1.1 then
if player:get_hp() > 0 then if player:get_hp() > 0 then
mcl_death_messages.player_damage(player, S("@1 was prickled to death by a cactus.", name)) mcl_util.deal_damage(player, 1, {type = "cactus"})
player:set_hp(player:get_hp() - 1, { type = "punch", from = "mod" })
end end
end end
end end
@ -545,3 +522,61 @@ minetest.register_on_leaveplayer(function(player)
mcl_playerplus_internal[name] = nil mcl_playerplus_internal[name] = nil
mcl_playerplus.elytra[player] = nil mcl_playerplus.elytra[player] = nil
end) 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 name = mcl_playerplus
author = TenPlus1 author = TenPlus1
description = Adds some simple player-related gameplay effects: Hurt by touching a cactus, suffocation and more. 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 S = minetest.get_translator("mcl_skins")
local has_mcl_armor = minetest.get_modpath("mcl_armor")
local has_mcl_inventory = minetest.get_modpath("mcl_inventory") local has_mcl_inventory = minetest.get_modpath("mcl_inventory")
-- load skin list and metadata -- load skin list and metadata
@ -115,10 +114,6 @@ mcl_skins.set_player_skin = function(player, skin_id)
mcl_skins.previews[playername] = preview mcl_skins.previews[playername] = preview
player:get_meta():set_string("mcl_skins:skin_id", tostring(skin_id)) player:get_meta():set_string("mcl_skins:skin_id", tostring(skin_id))
mcl_skins.update_player_skin(player) 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 if has_mcl_inventory then
mcl_inventory.update_inventory_formspec(player) mcl_inventory.update_inventory_formspec(player)
end end
@ -134,7 +129,7 @@ mcl_skins.update_player_skin = function(player)
return return
end end
local playername = player:get_player_name() 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 end
-- load player skin on join -- load player skin on join

View File

@ -2,4 +2,4 @@ name = mcl_skins
author = TenPlus1 author = TenPlus1
description = Mod that allows players to set their individual skins. description = Mod that allows players to set their individual skins.
depends = mcl_player 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 author = stujones11
description = Makes hand wielded items visible to other players. 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