From d479f749f04930bf4c0ae385908227a2fd81ec1d Mon Sep 17 00:00:00 2001 From: the-real-herowl Date: Sun, 7 Jan 2024 22:56:58 +0100 Subject: [PATCH] Implemented missing potion registering functionality * improved support for custom (non-status) effects * added support for splash potions * added support for lingering potions * added support for tipped arrows * removed the old registration --- mods/ITEMS/mcl_potions/lingering.lua | 92 ++++++++++++++----- mods/ITEMS/mcl_potions/potions.lua | 112 ++++++++++++++++++------ mods/ITEMS/mcl_potions/splash.lua | 70 +++++++++++---- mods/ITEMS/mcl_potions/tipped_arrow.lua | 65 ++++++++++++-- 4 files changed, 268 insertions(+), 71 deletions(-) diff --git a/mods/ITEMS/mcl_potions/lingering.lua b/mods/ITEMS/mcl_potions/lingering.lua index 46d94cad3..68da35146 100644 --- a/mods/ITEMS/mcl_potions/lingering.lua +++ b/mods/ITEMS/mcl_potions/lingering.lua @@ -11,8 +11,8 @@ end local lingering_effect_at = {} -local function add_lingering_effect(pos, color, def, is_water, instant) - lingering_effect_at[pos] = {color = color, timer = 30, def = def, is_water = is_water} +local function add_lingering_effect(pos, color, def, is_water, potency, plus) + lingering_effect_at[pos] = {color = color, timer = 30, def = def, is_water = is_water, potency = potency, plus = plus} end local function linger_particles(pos, d, texture, color) @@ -55,23 +55,52 @@ minetest.register_globalstep(function(dtime) end linger_particles(pos, d, texture, vals.color) - -- Extinguish fire if water bottle - if vals.is_water then - if mcl_potions._extinguish_nearby_fire(pos, d) then - vals.timer = vals.timer - 3.25 - end +-- -- Extinguish fire if water bottle +-- if vals.is_water then +-- if mcl_potions._extinguish_nearby_fire(pos, d) then +-- vals.timer = vals.timer - 3.25 +-- end +-- end + + if vals.def.while_lingering and vals.def.while_lingering(pos, d, vals.potency+1) then + vals.timer = vals.timer - 3.25 end -- Affect players and mobs for _, obj in pairs(minetest.get_objects_inside_radius(pos, d)) do local entity = obj:get_luaentity() - if obj:is_player() or entity.is_mob then + if obj:is_player() or entity and entity.is_mob then + local applied = false + if vals.def._effect_list then + local ef_level + local dur + for name, details in pairs(vals.def._effect_list) do + if details.uses_level then + ef_level = details.level + details.level_scaling * (vals.potency) + else + ef_level = details.level + end + if details.dur_variable then + dur = details.dur * math.pow(mcl_potions.PLUS_FACTOR, vals.plus) + if vals.potency>0 and details.uses_level then + dur = dur / math.pow(mcl_potions.POTENT_FACTOR, vals.potency) + end + else + dur = details.dur + end + dur = dur * mcl_potions.SPLASH_FACTOR + if mcl_potions.give_effect_by_level(name, obj, ef_level, dur) then + applied = true + end + end + end - vals.def.potion_fun(obj) - -- TODO: Apply timer penalty only if the potion effect was acutally applied - vals.timer = vals.timer - 3.25 + if vals.def.custom_effect and vals.def.custom_effect(obj, vals.potency+1) then + applied = true + end + if applied then vals.timer = vals.timer - 3.25 end end end @@ -87,31 +116,42 @@ end) function mcl_potions.register_lingering(name, descr, color, def) - local id = "mcl_potions:"..name.."_lingering" - local longdesc = def.longdesc + local longdesc = def._longdesc if not def.no_effect then - longdesc = S("A throwable potion that will shatter on impact, where it creates a magic cloud that lingers around for a while. Any player or mob inside the cloud will receive the potion's effect, possibly repeatedly.") + longdesc = S("A throwable potion that will shatter on impact, where it creates a magic cloud that lingers around for a while. Any player or mob inside the cloud will receive the potion's effect or set of effects, possibly repeatedly.") if def.longdesc then - longdesc = longdesc .. "\n" .. def.longdesc + longdesc = longdesc .. "\n" .. def._longdesc end end minetest.register_craftitem(id, { description = descr, - _tt_help = def.tt, + _tt_help = def._tt, + _dynamic_tt = def._dynamic_tt, _doc_items_longdesc = longdesc, _doc_items_usagehelp = S("Use the “Punch” key to throw it."), + stack_max = def.stack_max, + _effect_list = def._effect_list, + uses_level = def.uses_level, + has_potent = def.has_potent, + has_plus = def.has_plus, + _default_potent_level = def._default_potent_level, + _default_extend_level = def._default_extend_level, inventory_image = lingering_image(color), - groups = {brewitem=1, not_in_creative_inventory=0, bottle=1}, + groups = {brewitem=1, bottle=1, _mcl_potion=1}, on_use = function(item, placer, pointed_thing) local velocity = 10 local dir = placer:get_look_dir(); local pos = placer:getpos(); minetest.sound_play("mcl_throwing_throw", {pos = pos, gain = 0.4, max_hear_distance = 16}, true) local obj = minetest.add_entity({x=pos.x+dir.x,y=pos.y+2+dir.y,z=pos.z+dir.z}, id.."_flying") - obj:setvelocity({x=dir.x*velocity,y=dir.y*velocity,z=dir.z*velocity}) - obj:setacceleration({x=dir.x*-3, y=-9.8, z=dir.z*-3}) - obj:get_luaentity()._thrower = placer:get_player_name() + obj:set_velocity({x=dir.x*velocity,y=dir.y*velocity,z=dir.z*velocity}) + obj:set_acceleration({x=dir.x*-3, y=-9.8, z=dir.z*-3}) + local ent = obj:get_luaentity() + ent._thrower = placer:get_player_name() + ent._potency = item:get_meta():get_int("mcl_potions:potion_potent") + ent._plus = item:get_meta():get_int("mcl_potions:potion_plus") + ent._effect_list = def._effect_list if not minetest.is_creative_enabled(placer:get_player_name()) then item:take_item() end @@ -126,6 +166,10 @@ function mcl_potions.register_lingering(name, descr, color, def) local velocity = 22 obj:set_velocity({x=dropdir.x*velocity,y=dropdir.y*velocity,z=dropdir.z*velocity}) obj:set_acceleration({x=dropdir.x*-3, y=-9.8, z=dropdir.z*-3}) + local ent = obj:get_luaentity() + ent._potency = item:get_meta():get_int("mcl_potions:potion_potent") + ent._plus = item:get_meta():get_int("mcl_potions:potion_plus") + ent._effect_list = def._effect_list end }) @@ -148,7 +192,9 @@ function mcl_potions.register_lingering(name, descr, color, def) end if n ~= "air" and n ~= "mcl_portals:portal" and n ~= "mcl_portals:portal_end" and g == 0 or mcl_potions.is_obj_hit(self, pos) then minetest.sound_play("mcl_potions_breaking_glass", {pos = pos, max_hear_distance = 16, gain = 1}) - add_lingering_effect(pos, color, def, name == "water") + local potency = self._potency or 0 + local plus = self._plus or 0 + add_lingering_effect(pos, color, def, name == "water", potency, plus) local texture if name == "water" then texture = "mcl_particles_droplet_bottle.png" @@ -160,9 +206,7 @@ function mcl_potions.register_lingering(name, descr, color, def) end end linger_particles(pos, d, texture, color) - if name == "water" then - mcl_potions._extinguish_nearby_fire(pos, d) - end + if def.on_splash then def.on_splash(pos, potency+1) end self.object:remove() end end, diff --git a/mods/ITEMS/mcl_potions/potions.lua b/mods/ITEMS/mcl_potions/potions.lua index 6e022f497..1b66a955d 100644 --- a/mods/ITEMS/mcl_potions/potions.lua +++ b/mods/ITEMS/mcl_potions/potions.lua @@ -145,7 +145,7 @@ end -- stack_max - int - max stack size - defaults to 1 -- image - string - name of a custom texture of the potion icon -- color - string - colorstring for potion icon when image is not defined - defaults to #0000FF --- groups - table - item groups definition - +-- groups - table - item groups definition for the regular potion, not splash or lingering - -- - must contain _mcl_potion=1 for tooltip to include dynamic_tt and effects -- - defaults to {brewitem=1, food=3, can_eat_when_full=1, _mcl_potion=1} -- _effect_list - table - all the effects dealt by the potion in the format of tables @@ -168,10 +168,10 @@ end -- has_potent - bool - whether there is a potent (e.g. II) variant - defaults to the value of uses_level -- default_potent_level - int - potion level used for the default potent variant - defaults to 2 -- default_extend_level - int - extention level (amount of +) used for the default extended variant - defaults to 1 --- custom_on_use - function(user, level) - called when the potion is drunk --- custom_effect - function(object, level) - called when the potion effects are applied --- custom_splash_effect - function(pos, level) - called when the splash potion explodes --- custom_linger_effect - function(pos, radius, level) - called on the lingering potion step +-- custom_on_use - function(user, level) - called when the potion is drunk, returns true on success +-- custom_effect - function(object, level) - called when the potion effects are applied, returns true on success +-- custom_splash_effect - function(pos, level) - called when the splash potion explodes, returns true on success +-- custom_linger_effect - function(pos, radius, level) - called on the lingering potion step, returns true on success function mcl_potions.register_potion(def) local modname = minetest.get_current_modname() local name = def.name @@ -201,25 +201,28 @@ function mcl_potions.register_potion(def) local effect local uses_level = false local has_plus = false - for name, details in pairs(def._effect_list) do - effect = mcl_potions.registered_effects[name] - if effect then - local ulvl - if details.uses_level ~= nil then ulvl = details.uses_level - else ulvl = effect.uses_factor end - if ulvl then uses_level = true end - local durvar = true - if details.dur_variable ~= nil then durvar = details.dur_variable end - if durvar then has_plus = true end - pdef._effect_list[name] = { - uses_level = ulvl, - level = details.level or 1, - level_scaling = details.level_scaling or 1, - dur = details.dur or mcl_potions.DURATION, - dur_variable = durvar, - } - else - error("Unable to register potion: effect not registered") + if def._effect_list then + for name, details in pairs(def._effect_list) do + no_effects = false + effect = mcl_potions.registered_effects[name] + if effect then + local ulvl + if details.uses_level ~= nil then ulvl = details.uses_level + else ulvl = effect.uses_factor end + if ulvl then uses_level = true end + local durvar = true + if details.dur_variable ~= nil then durvar = details.dur_variable end + if durvar then has_plus = true end + pdef._effect_list[name] = { + uses_level = ulvl, + level = details.level or 1, + level_scaling = details.level_scaling or 1, + dur = details.dur or mcl_potions.DURATION, + dur_variable = durvar, + } + else + error("Unable to register potion: effect not registered") + end end end if def.uses_level ~= nil then uses_level = def.uses_level end @@ -238,6 +241,59 @@ function mcl_potions.register_potion(def) minetest.register_craftitem(modname..":"..name, pdef) + if def.has_splash or def.has_splash == nil then + local splash_desc = S("Splash @1 Potion @2", def.desc_prefix, def.desc_suffix) + local sdef = {} + sdef._tt = def._tt + sdef._dynamic_tt = def._dynamic_tt + sdef._longdesc = def._longdesc + sdef.stack_max = pdef.stack_max + sdef._effect_list = pdef._effect_list + sdef.uses_level = uses_level + sdef.has_potent = pdef.has_potent + sdef.has_plus = has_plus + sdef._default_potent_level = pdef._default_potent_level + sdef._default_extend_level = pdef._default_extend_level + sdef.custom_effect = def.custom_effect + sdef.on_splash = def.custom_splash_effect + if not def._effect_list then sdef.instant = true end + mcl_potions.register_splash(name, splash_desc, color, sdef) + end + + if def.has_lingering or def.has_lingering == nil then + local ling_desc = S("Lingering @1 Potion @2", def.desc_prefix, def.desc_suffix) + local ldef = {} + ldef._tt = def._tt + ldef._longdesc = def._longdesc + ldef.stack_max = pdef.stack_max + ldef._effect_list = pdef._effect_list + ldef.uses_level = uses_level + ldef.has_potent = pdef.has_potent + ldef.has_plus = has_plus + ldef._default_potent_level = pdef._default_potent_level + ldef._default_extend_level = pdef._default_extend_level + ldef.custom_effect = def.custom_effect + ldef.on_splash = def.custom_splash_effect + ldef.while_lingering = def.custom_linger_effect + if not def._effect_list then ldef.instant = true end + mcl_potions.register_lingering(name, ling_desc, color, ldef) + end + + if def.has_arrow then + local arr_desc = S("@1 Arrow @2", def.desc_prefix, def.desc_suffix) + local adef = {} + adef._tt = def._tt + adef._longdesc = def._longdesc + adef._effect_list = pdef._effect_list + adef.uses_level = uses_level + adef.has_potent = pdef.has_potent + adef.has_plus = has_plus + adef._default_potent_level = pdef._default_potent_level + adef._default_extend_level = pdef._default_extend_level + adef.custom_effect = def.custom_effect + if not def._effect_list then adef.instant = true end + mcl_potions.register_arrow(name, arr_desc, color, adef) + end end mcl_potions.register_potion({ @@ -264,6 +320,8 @@ mcl_potions.register_potion({ }, default_potent_level = 5, default_extend_level = 3, + custom_splash_effect = mcl_potions._extinguish_nearby_fire, + has_arrow = true, }) @@ -811,9 +869,9 @@ local defs = { awkward_def, mundane_def, thick_def, dragon_breath_def, slowness_def, leaping_def, withering_def, poison_def, regeneration_def, invisibility_def, water_breathing_def, fire_resistance_def} -for _, def in ipairs(defs) do - register_potion(def) -end +-- for _, def in ipairs(defs) do +-- register_potion(def) +-- end diff --git a/mods/ITEMS/mcl_potions/splash.lua b/mods/ITEMS/mcl_potions/splash.lua index 0b8aedeab..33515c161 100644 --- a/mods/ITEMS/mcl_potions/splash.lua +++ b/mods/ITEMS/mcl_potions/splash.lua @@ -13,20 +13,28 @@ end function mcl_potions.register_splash(name, descr, color, def) local id = "mcl_potions:"..name.."_splash" - local longdesc = def.longdesc + local longdesc = def._longdesc if not def.no_effect then - longdesc = S("A throwable potion that will shatter on impact, where it gives all nearby players and mobs a status effect.") - if def.longdesc then - longdesc = longdesc .. "\n" .. def.longdesc + longdesc = S("A throwable potion that will shatter on impact, where it gives all nearby players and mobs a status effect or a set of status effects.") + if def._longdesc then + longdesc = longdesc .. "\n" .. def._longdesc end end minetest.register_craftitem(id, { description = descr, - _tt_help = def.tt, + _tt_help = def._tt, + _dynamic_tt = def._dynamic_tt, _doc_items_longdesc = longdesc, _doc_items_usagehelp = S("Use the “Punch” key to throw it."), + stack_max = def.stack_max, + _effect_list = def._effect_list, + uses_level = def.uses_level, + has_potent = def.has_potent, + has_plus = def.has_plus, + _default_potent_level = def._default_potent_level, + _default_extend_level = def._default_extend_level, inventory_image = splash_image(color), - groups = {brewitem=1, not_in_creative_inventory=0, bottle=1}, + groups = {brewitem=1, bottle=1, _mcl_potion=1}, on_use = function(item, placer, pointed_thing) local velocity = 10 local dir = placer:get_look_dir(); @@ -35,7 +43,11 @@ function mcl_potions.register_splash(name, descr, color, def) local obj = minetest.add_entity({x=pos.x+dir.x,y=pos.y+2+dir.y,z=pos.z+dir.z}, id.."_flying") obj:set_velocity({x=dir.x*velocity,y=dir.y*velocity,z=dir.z*velocity}) obj:set_acceleration({x=dir.x*-3, y=-9.8, z=dir.z*-3}) - obj:get_luaentity()._thrower = placer:get_player_name() + local ent = obj:get_luaentity() + ent._thrower = placer:get_player_name() + ent._potency = item:get_meta():get_int("mcl_potions:potion_potent") + ent._plus = item:get_meta():get_int("mcl_potions:potion_plus") + ent._effect_list = def._effect_list if not minetest.is_creative_enabled(placer:get_player_name()) then item:take_item() end @@ -50,6 +62,10 @@ function mcl_potions.register_splash(name, descr, color, def) local velocity = 22 obj:set_velocity({x=dropdir.x*velocity,y=dropdir.y*velocity,z=dropdir.z*velocity}) obj:set_acceleration({x=dropdir.x*-3, y=-9.8, z=dropdir.z*-3}) + local ent = obj:get_luaentity() + ent._potency = item:get_meta():get_int("mcl_potions:potion_potent") + ent._plus = item:get_meta():get_int("mcl_potions:potion_plus") + ent._effect_list = def._effect_list end }) @@ -103,10 +119,10 @@ function mcl_potions.register_splash(name, descr, color, def) texture = texture.."^[colorize:"..color..":127" }) - if name == "water" then - mcl_potions._extinguish_nearby_fire(pos) - end - self.object:remove() + local potency = self._potency or 0 + local plus = self._plus or 0 + + if def.on_splash then def.on_splash(pos, potency+1) end for _,obj in pairs(minetest.get_objects_inside_radius(pos, 4)) do local entity = obj:get_luaentity() @@ -114,13 +130,37 @@ function mcl_potions.register_splash(name, descr, color, def) local pos2 = obj:get_pos() local rad = math.floor(math.sqrt((pos2.x-pos.x)^2 + (pos2.y-pos.y)^2 + (pos2.z-pos.z)^2)) - if rad > 0 then - def.potion_fun(obj, redux_map[rad]) - else - def.potion_fun(obj, 1) + + if def._effect_list then + local ef_level + local dur + for name, details in pairs(def._effect_list) do + if details.uses_level then + ef_level = details.level + details.level_scaling * (potency) + else + ef_level = details.level + end + if details.dur_variable then + dur = details.dur * math.pow(mcl_potions.PLUS_FACTOR, plus) + if potency>0 and details.uses_level then + dur = dur / math.pow(mcl_potions.POTENT_FACTOR, potency) + end + else + dur = details.dur + end + dur = dur * mcl_potions.SPLASH_FACTOR + if rad > 0 then + mcl_potions.give_effect_by_level(name, obj, ef_level, redux_map[rad]*dur) + else + mcl_potions.give_effect_by_level(name, obj, ef_level, dur) + end + end end + + if def.custom_effect then def.custom_effect(obj, potency+1) end -- TODO use redux_map end end + self.object:remove() end end, diff --git a/mods/ITEMS/mcl_potions/tipped_arrow.lua b/mods/ITEMS/mcl_potions/tipped_arrow.lua index 53a37705e..6db2e6531 100644 --- a/mods/ITEMS/mcl_potions/tipped_arrow.lua +++ b/mods/ITEMS/mcl_potions/tipped_arrow.lua @@ -37,16 +37,23 @@ local arrow_tt = minetest.registered_items["mcl_bows:arrow"]._tt_help or "" function mcl_potions.register_arrow(name, desc, color, def) - local longdesc = def.longdesc or "" + local longdesc = def._longdesc or "" + local tt = def._tt or "" minetest.register_craftitem("mcl_potions:"..name.."_arrow", { description = desc, - _tt_help = arrow_tt .. "\n" .. def.tt, + _tt_help = arrow_tt .. "\n" .. tt, _doc_items_longdesc = arrow_longdesc .. "\n" .. S("This particular arrow is tipped and will give an effect when it hits a player or mob.") .. "\n" .. longdesc, _doc_items_usagehelp = how_to_shoot, + _effect_list = def._effect_list, + uses_level = def.uses_level, + has_potent = def.has_potent, + has_plus = def.has_plus, + _default_potent_level = def._default_potent_level, + _default_extend_level = def._default_extend_level, inventory_image = "mcl_bows_arrow_inv.png^(mcl_potions_arrow_inv.png^[colorize:"..color..":100)", - groups = { ammo=1, ammo_bow=1, brewitem=1}, + groups = { ammo=1, ammo_bow=1, brewitem=1, _mcl_potion=1}, _on_dispense = function(itemstack, dispenserpos, droppos, dropnode, dropdir) -- Shoot arrow local shootpos = vector.add(dispenserpos, vector.multiply(dropdir, 0.51)) @@ -264,6 +271,9 @@ function mcl_potions.register_arrow(name, desc, color, def) end end + local potency = self._potency or 0 + local plus = self._plus or 0 + -- Punch target object but avoid hurting enderman. if lua then if lua.name ~= "mobs_mc:enderman" then @@ -271,14 +281,59 @@ function mcl_potions.register_arrow(name, desc, color, def) full_punch_interval=1.0, damage_groups={fleshy=self._damage}, }, nil) - def.potion_fun(obj) + if def._effect_list then + local ef_level + local dur + for name, details in pairs(def._effect_list) do + if details.uses_level then + ef_level = details.level + details.level_scaling * (potency) + else + ef_level = details.level + end + if details.dur_variable then + dur = details.dur * math.pow(mcl_potions.PLUS_FACTOR, plus) + if potency>0 and details.uses_level then + dur = dur / math.pow(mcl_potions.POTENT_FACTOR, potency) + end + else + dur = details.dur + end + mcl_potions.give_effect_by_level(name, obj, ef_level, dur) + end + end + if def.custom_effect then def.custom_effect(obj, potency+1) end end else obj:punch(self.object, 1.0, { full_punch_interval=1.0, damage_groups={fleshy=self._damage}, }, nil) - def.potion_fun(obj) + if def._effect_list then + local ef_level + local dur + for name, details in pairs(def._effect_list) do + if details.uses_level then + ef_level = details.level + details.level_scaling * (potency) + else + ef_level = details.level + end + if details.dur_variable then + dur = details.dur * math.pow(mcl_potions.PLUS_FACTOR, plus) + if potency>0 and details.uses_level then + dur = dur / math.pow(mcl_potions.POTENT_FACTOR, potency) + end + else + dur = details.dur + end + dur = dur * mcl_potions.SPLASH_FACTOR + if rad > 0 then + mcl_potions.give_effect_by_level(name, obj, ef_level, redux_map[rad]*dur) + else + mcl_potions.give_effect_by_level(name, obj, ef_level, dur) + end + end + end + if def.custom_effect then def.custom_effect(obj, potency+1) end end if is_player then