Redesign damage modifier execution

This commit is contained in:
Elias Fleckenstein 2021-04-18 20:08:08 +02:00
parent a2c3eb95bb
commit d9195cc520
4 changed files with 48 additions and 66 deletions

@ -15,7 +15,7 @@ mcl_damage = {
out_of_world = {bypasses_armor = true, bypasses_invulnerability = true}, out_of_world = {bypasses_armor = true, bypasses_invulnerability = true},
generic = {bypasses_armor = true}, generic = {bypasses_armor = true},
magic = {is_magic = true, bypasses_armor = true}, magic = {is_magic = true, bypasses_armor = true},
wither = {bypasses_armor = true}, -- unused wither = {bypasses_armor = true}, -- unused
anvil = {}, anvil = {},
falling_node = {}, -- unused falling_node = {}, -- unused
dragon_breath = {bypasses_armor = true}, -- unused dragon_breath = {bypasses_armor = true}, -- unused
@ -30,24 +30,45 @@ mcl_damage = {
} }
} }
local old_register_hpchange = minetest.register_on_player_hpchange
function minetest.register_on_player_hpchange(func, modifier)
if modifier then
mcl_damage.register_modifier(func, 0)
else
old_register_hpchange(func, modifier)
end
end
function mcl_damage.register_modifier(func, priority) function mcl_damage.register_modifier(func, priority)
table.insert(mcl_damage.modifiers, {func = func, priority = priority or 0}) table.insert(mcl_damage.modifiers, {func = func, priority = priority or 0})
end end
function mcl_damage.get_mcl_damage_reason(mt_reason) function mcl_damage.do_modifiers(player, damage, reason)
local mcl_reason = { for _, modf in ipairs(mcl_damage.modifiers) do
type = "generic", damage = modf.func(player, damage, reason) or damage
} if damage == 0 then
return 0
end
end
return damage
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)
local mcl_reason = {type = "generic"}
if mt_reason._mcl_type then if mt_reason._mcl_type then
mcl_reason.type = mt_reason._mcl_type mcl_reason.type = mt_reason._mcl_type
@ -56,22 +77,7 @@ function mcl_damage.get_mcl_damage_reason(mt_reason)
elseif mt_reason.type == "drown" then elseif mt_reason.type == "drown" then
mcl_reason.type = "drown" mcl_reason.type = "drown"
elseif mt_reason.type == "punch" then elseif mt_reason.type == "punch" then
mcl_reason.direct = mt_reason.object mcl_damage.from_punch(mcl_reason, mt_reason.object)
if mcl_reason.direct then
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
elseif mt_reason.type == "node_damage" and mt_reason.node then elseif mt_reason.type == "node_damage" and mt_reason.node then
if minetest.get_item_group(mt_reason.node, "fire") > 0 then if minetest.get_item_group(mt_reason.node, "fire") > 0 then
mcl_reason.type = "in_fire" mcl_reason.type = "in_fire"
@ -87,8 +93,7 @@ function mcl_damage.get_mcl_damage_reason(mt_reason)
end end
end end
mcl_reason.source = mcl_reason.source or mcl_reason.direct mcl_damage.finish_reason(mcl_reason)
mcl_reason.flags = mcl_damage.types[mcl_reason.type]
return mcl_reason return mcl_reason
end end
@ -97,16 +102,10 @@ function mcl_damage.register_type(name, def)
mcl_damage.types[name] = def mcl_damage.types[name] = def
end end
old_register_hpchange(function(player, hp_change, mt_reason) minetest.register_on_player_hpchange(function(player, hp_change, mt_reason)
local mcl_reason = mcl_damage.get_mcl_damage_reason(mt_reason) if hp_change < 0 then
hp_change = -mcl_damage.do_modifiers(player, -hp_change, mcl_damage.from_mt(mt_reason))
for _, modf in ipairs(mcl_damage.modifiers) do
hp_change = modf.func(player, hp_change, mt_reason, mcl_reason) or hp_change
if hp_change == 0 then
return 0
end
end end
return hp_change return hp_change
end, true) end, true)

@ -1,13 +1,8 @@
function mcl_armor.damage_modifier(obj, hp_change, reason) mcl_damage.register_modifier(function(obj, damage, reason)
if hp_change > 0 then
return hp_change
end
local damage = -hp_change
local flags = reason.flags local flags = reason.flags
if flags.bypasses_armor and flags.bypasses_magic then if flags.bypasses_armor and flags.bypasses_magic then
return hp_change return damage
end end
local uses = math.max(1, math.floor(damage / 4)) local uses = math.max(1, math.floor(damage / 4))
@ -95,5 +90,5 @@ function mcl_armor.damage_modifier(obj, hp_change, reason)
mcl_armor.update(obj) mcl_armor.update(obj)
return -math.floor(damage + 0.5) return math.floor(damage + 0.5)
end end, 0)

@ -155,7 +155,3 @@ end)
minetest.register_on_leaveplayer(function(player) minetest.register_on_leaveplayer(function(player)
mcl_armor.player_view_range_factors[player] = nil mcl_armor.player_view_range_factors[player] = nil
end) end)
mcl_damage.register_modifier(function(player, hp_change, _, reason)
return mcl_armor.damage_modifier(player, hp_change, reason)
end)

@ -1,8 +1,5 @@
mcl_criticals = {} mcl_damage.register_modifier(function(obj, damage, reason)
if reason.type == "player" then
function mcl_criticals.modifier(obj, hp_change, reason)
local damage = -hp_change
if damage > 0 and reason.type == "player" then
local hitter = reason.direct local hitter = reason.direct
if mcl_sprint.is_sprinting(hitter) then if mcl_sprint.is_sprinting(hitter) then
obj:add_velocity(hitter:get_velocity()) obj:add_velocity(hitter:get_velocity())
@ -27,12 +24,7 @@ function mcl_criticals.modifier(obj, hp_change, reason)
}) })
minetest.sound_play("mcl_criticals_hit", {object = obj}) minetest.sound_play("mcl_criticals_hit", {object = obj})
-- the minecraft wiki is actually wrong about a crit dealing 150% damage, see minecraft source code -- the minecraft wiki is actually wrong about a crit dealing 150% damage, see minecraft source code
damage = damage + math.random(0, math.floor(damage * 1.5 + 2)) return damage + math.random(0, math.floor(damage * 1.5 + 2))
end end
end end
return -damage
end
mcl_damage.register_modifier(function(player, hp_change, _, mcl_reason)
return mcl_criticals.modifier(player, hp_change, mcl_reason)
end, -100) end, -100)