From e7be186e76fa7d765628ce6f8ffe8479b5497c6f Mon Sep 17 00:00:00 2001 From: the-real-herowl Date: Thu, 11 Jan 2024 00:23:41 +0100 Subject: [PATCH] Improved effects HUD and fixes * Fixed some effects not being replaced correctly with higher levels * Implemented an old FIXME (MTE 5.3.0 fixed underlying bug) * Added a way to obtain an approximate level of effect from factor * Added effect level to HUD under the icon * Added effect timer to HUD under the icon --- mods/ITEMS/mcl_potions/functions.lua | 115 +++++++++++++++++++++------ 1 file changed, 89 insertions(+), 26 deletions(-) diff --git a/mods/ITEMS/mcl_potions/functions.lua b/mods/ITEMS/mcl_potions/functions.lua index efc4896fa..51236c17d 100644 --- a/mods/ITEMS/mcl_potions/functions.lua +++ b/mods/ITEMS/mcl_potions/functions.lua @@ -33,6 +33,14 @@ local function generate_linear_lvl_to_fac(l1, l2) end end +local function generate_linear_fac_to_lvl(l1, l2) + local a = 1/(l2 - l1) + local b = -(2*l1 - l2) * a + return function(factor) + return math.round(a*factor + b) + end +end + local function generate_rational_lvl_to_fac(l1, l2) local a = (l1 - l2) * 2 local b = 2*l2 - l1 @@ -42,6 +50,15 @@ local function generate_rational_lvl_to_fac(l1, l2) end end +local function generate_rational_fac_to_lvl(l1, l2) + local a = (l1 - l2) * 2 + local b = 2*l2 - l1 + return function(factor) + if factor == 0 then return math.huge end + return math.round(a/(factor - b)) + end +end + local function generate_modifier_func(name, dmg_flag, mod_func) return function(object, damage, reason) if EF[name][object] and not reason.flags.bypasses_magic and reason.flags[dmg_flag] then @@ -118,8 +135,12 @@ function mcl_potions.register_effect(def) local l2 = def.lvl2_factor or 2*l1 if l1 < l2 then pdef.level_to_factor = generate_linear_lvl_to_fac(l1, l2) + pdef.factor_to_level = generate_linear_fac_to_lvl(l1, l2) + pdef.inv_factor = false elseif l1 > l2 then pdef.level_to_factor = generate_rational_lvl_to_fac(l1, l2) + pdef.factor_to_level = generate_rational_fac_to_lvl(l1, l2) + pdef.inv_factor = true else error("Can't extrapolate levels from lvl1 and lvl2 bearing the same factor") end @@ -417,7 +438,8 @@ local function potions_init_icons(player) icon_ids[name] = {} for e=1, EFFECT_TYPES do local x = -52 * e - 2 - local id = player:hud_add({ + local id = {} + id.img = player:hud_add({ hud_elem_type = "image", text = "blank.png", position = { x = 1, y = 0 }, @@ -426,6 +448,28 @@ local function potions_init_icons(player) alignment = { x = 1, y = 1 }, z_index = 100, }) + id.label = player:hud_add({ + hud_elem_type = "text", + text = "", + position = { x = 1, y = 0 }, + offset = { x = x+22, y = 50 }, + scale = { x = 50, y = 15 }, + alignment = { x = 0, y = 1 }, + z_index = 100, + style = 1, + number = 0xFFFFFF, + }) + id.timestamp = player:hud_add({ + hud_elem_type = "text", + text = "", + position = { x = 1, y = 0 }, + offset = { x = x+22, y = 65 }, + scale = { x = 50, y = 15 }, + alignment = { x = 0, y = 1 }, + z_index = 100, + style = 1, + number = 0xFFFFFF, + }) table.insert(icon_ids[name], id) end end @@ -438,19 +482,38 @@ local function potions_set_icons(player) local active_effects = {} for effect_name, effect in pairs(EF) do if effect[player] then - table.insert(active_effects, effect_name) + active_effects[effect_name] = effect[player] end end - for i=1, EFFECT_TYPES do - local icon = icon_ids[name][i] - local effect_name = active_effects[i] - if effect_name == nil then - player:hud_change(icon, "text", "blank.png") - else - player:hud_change(icon, "text", "mcl_potions_effect_"..effect_name..".png^[resize:128x128") + local i = 1 + for effect_name, def in pairs(registered_effects) do + local icon = icon_ids[name][i].img + local label = icon_ids[name][i].label + local timestamp = icon_ids[name][i].timestamp + local vals = active_effects[effect_name] + if vals then + player:hud_change(icon, "text", def.icon .. "^[resize:128x128") + if def.uses_factor then + local level = def.factor_to_level(vals.factor) + if level == math.huge then level = "∞" + else level = mcl_util.to_roman(level) end + player:hud_change(label, "text", level) + else + player:hud_change(label, "text", "") + end + local dur = math.round(vals.dur-vals.timer) + player:hud_change(timestamp, "text", math.floor(dur/60)..string.format(":%02d",math.floor(dur % 60))) + EF[effect_name][player].hud_index = i + i = i + 1 end end + while i < EFFECT_TYPES do + player:hud_change(icon_ids[name][i].img, "text", "blank.png") + player:hud_change(icon_ids[name][i].label, "text", "") + player:hud_change(icon_ids[name][i].timestamp, "text", "") + i = i + 1 + end end local function potions_set_hud(player) @@ -496,6 +559,10 @@ minetest.register_globalstep(function(dtime) meta:set_string("mcl_potions:"..name, minetest.serialize(EF[name][object])) potions_set_hud(object) end + elseif object:is_player() then + local dur = math.round(vals.dur-vals.timer) + object:hud_change(icon_ids[object:get_player_name()][vals.hud_index].timestamp, + "text", math.floor(dur/60)..string.format(":%02d",math.floor(dur % 60))) end end end @@ -665,15 +732,7 @@ minetest.register_on_joinplayer( function(player) mcl_potions._reset_player_effects(player, false) -- make sure there are no weird holdover effects mcl_potions._load_player_effects(player) potions_init_icons(player) - -- .after required because player:hud_change doesn't work when called - -- in same tick as player:hud_add - -- (see ) - -- FIXME: Remove minetest.after - minetest.after(3, function(player) - if player and player:is_player() then - potions_set_hud(player) - end - end, player) + potions_set_hud(player) end) minetest.register_on_shutdown(function() @@ -833,14 +892,18 @@ function mcl_potions.give_effect(name, object, factor, duration) if edef.on_start then edef.on_start(object, factor) end else local present = EF[name][object] - if not edef.uses_factor or (edef.uses_factor and factor >= present.factor) then - present.dur = math.max(duration, present.dur - present.timer) - present.timer = 0 - if edef.uses_factor then - present.factor = factor - if edef.timer_uses_factor then present.step = factor end - if edef.on_start then edef.on_start(object, factor) end - end + if not edef.uses_factor or (edef.uses_factor and + (not edef.inv_factor and factor >= present.factor + or edef.inv_factor and factor <= present.factor)) then + present.dur = math.max(duration, present.dur - present.timer) + present.timer = 0 + if edef.uses_factor then + present.factor = factor + if edef.timer_uses_factor then present.step = factor end + if edef.on_start then edef.on_start(object, factor) end + end + else + return false end end