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
This commit is contained in:
the-real-herowl 2024-01-07 22:56:58 +01:00
parent 83530b4298
commit 7d3e2d3dbc
4 changed files with 268 additions and 71 deletions

View File

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

View File

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

View File

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

View File

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