2021-05-29 14:12:33 +00:00
local S = minetest.get_translator ( minetest.get_current_modname ( ) )
2020-07-10 11:01:21 +00:00
2022-02-26 21:44:50 +00:00
local mod_target = minetest.get_modpath ( " mcl_target " )
2021-05-29 14:12:33 +00:00
local function lingering_image ( colorstring , opacity )
2020-06-18 11:43:50 +00:00
if not opacity then
opacity = 127
end
2020-07-05 21:36:18 +00:00
return " mcl_potions_splash_overlay.png^[colorize: " .. colorstring .. " : " .. tostring ( opacity ) .. " ^mcl_potions_lingering_bottle.png "
2020-06-18 11:43:50 +00:00
end
2020-06-27 00:32:03 +00:00
local lingering_effect_at = { }
2024-01-07 21:56:58 +00:00
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 }
2020-06-27 22:50:08 +00:00
end
2020-06-27 00:32:03 +00:00
2020-08-22 09:18:45 +00:00
local function linger_particles ( pos , d , texture , color )
minetest.add_particlespawner ( {
amount = 10 * d ^ 2 ,
time = 1 ,
minpos = { x = pos.x - d , y = pos.y + 0.5 , z = pos.z - d } ,
maxpos = { x = pos.x + d , y = pos.y + 1 , z = pos.z + d } ,
minvel = { x =- 0.5 , y = 0 , z =- 0.5 } ,
maxvel = { x = 0.5 , y = 0.5 , z = 0.5 } ,
minacc = { x =- 0.2 , y = 0 , z =- 0.2 } ,
maxacc = { x = 0.2 , y = .05 , z = 0.2 } ,
minexptime = 1 ,
maxexptime = 2 ,
minsize = 2 ,
maxsize = 4 ,
collisiondetection = true ,
vertical = false ,
texture = texture .. " ^[colorize: " .. color .. " :127 " ,
} )
end
2020-06-27 00:32:03 +00:00
2020-06-27 22:50:08 +00:00
local lingering_timer = 0
minetest.register_globalstep ( function ( dtime )
2020-06-27 00:32:03 +00:00
2020-06-27 22:50:08 +00:00
lingering_timer = lingering_timer + dtime
if lingering_timer >= 1 then
2020-06-27 00:32:03 +00:00
2020-06-27 22:50:08 +00:00
for pos , vals in pairs ( lingering_effect_at ) do
2020-06-27 00:32:03 +00:00
2020-06-27 22:50:08 +00:00
vals.timer = vals.timer - lingering_timer
local d = 4 * ( vals.timer / 30.0 )
2020-08-05 17:26:51 +00:00
local texture
if vals.is_water then
2020-08-19 12:12:51 +00:00
texture = " mcl_particles_droplet_bottle.png "
2020-08-19 15:37:41 +00:00
elseif vals.def . instant then
texture = " mcl_particles_instant_effect.png "
2020-08-05 17:26:51 +00:00
else
2020-08-19 12:12:51 +00:00
texture = " mcl_particles_effect.png "
2020-08-05 17:26:51 +00:00
end
2020-08-22 09:18:45 +00:00
linger_particles ( pos , d , texture , vals.color )
2020-08-05 17:26:51 +00:00
2024-01-07 21:56:58 +00:00
-- -- 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
2020-08-05 16:33:53 +00:00
end
-- Affect players and mobs
2020-06-27 22:50:08 +00:00
for _ , obj in pairs ( minetest.get_objects_inside_radius ( pos , d ) ) do
2020-06-27 01:27:17 +00:00
2020-06-27 22:50:08 +00:00
local entity = obj : get_luaentity ( )
2024-01-07 21:56:58 +00:00
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
2024-01-07 23:25:30 +00:00
dur = dur * mcl_potions.LINGERING_FACTOR
2024-01-07 21:56:58 +00:00
else
dur = details.dur
end
2024-04-22 02:51:01 +00:00
if details.effect_stacks then
ef_level = ef_level + mcl_potions.get_effect_level ( obj , name )
end
2024-01-07 21:56:58 +00:00
if mcl_potions.give_effect_by_level ( name , obj , ef_level , dur ) then
applied = true
end
end
end
2020-06-27 00:32:03 +00:00
2024-01-07 23:25:30 +00:00
if vals.def . custom_effect
2024-04-22 02:51:01 +00:00
and vals.def . custom_effect ( obj , ( vals.potency + 1 ) * mcl_potions.LINGERING_FACTOR , plus ) then
2024-01-07 23:25:30 +00:00
applied = true
2024-01-07 21:56:58 +00:00
end
2020-06-27 00:32:03 +00:00
2024-01-07 21:56:58 +00:00
if applied then vals.timer = vals.timer - 3.25 end
2020-06-27 00:32:03 +00:00
end
end
2020-08-08 08:00:16 +00:00
if vals.timer <= 0 then
lingering_effect_at [ pos ] = nil
end
2020-06-27 22:50:08 +00:00
end
lingering_timer = 0
end
end )
2020-06-27 00:32:03 +00:00
2020-07-12 11:59:29 +00:00
function mcl_potions . register_lingering ( name , descr , color , def )
2020-08-08 08:00:16 +00:00
local id = " mcl_potions: " .. name .. " _lingering "
2024-01-07 21:56:58 +00:00
local longdesc = def._longdesc
2020-08-08 08:00:16 +00:00
if not def.no_effect then
2024-01-07 21:56:58 +00:00
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. " )
2020-08-08 08:00:16 +00:00
if def.longdesc then
2024-01-07 21:56:58 +00:00
longdesc = longdesc .. " \n " .. def._longdesc
2020-08-08 08:00:16 +00:00
end
end
2024-01-07 23:41:08 +00:00
local groups = { brewitem = 1 , bottle = 1 , ling_potion = 1 , _mcl_potion = 1 }
if def.nocreative then groups.not_in_creative_inventory = 1 end
2020-08-08 08:00:16 +00:00
minetest.register_craftitem ( id , {
2022-02-26 21:44:50 +00:00
description = descr ,
2024-01-07 21:56:58 +00:00
_tt_help = def._tt ,
_dynamic_tt = def._dynamic_tt ,
2022-02-26 21:44:50 +00:00
_doc_items_longdesc = longdesc ,
_doc_items_usagehelp = S ( " Use the “Punch” key to throw it. " ) ,
2024-01-07 21:56:58 +00:00
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 ,
2022-02-26 21:44:50 +00:00
inventory_image = lingering_image ( color ) ,
2024-01-07 23:41:08 +00:00
groups = groups ,
2022-02-26 21:44:50 +00:00
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 " )
2024-01-07 21:56:58 +00:00
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
2022-02-26 21:44:50 +00:00
if not minetest.is_creative_enabled ( placer : get_player_name ( ) ) then
item : take_item ( )
end
return item
end ,
stack_max = 1 ,
_on_dispense = function ( stack , dispenserpos , droppos , dropnode , dropdir )
local s_pos = vector.add ( dispenserpos , vector.multiply ( dropdir , 0.51 ) )
local pos = { x = s_pos.x + dropdir.x , y = s_pos.y + dropdir.y , z = s_pos.z + dropdir.z }
minetest.sound_play ( " mcl_throwing_throw " , { pos = pos , gain = 0.4 , max_hear_distance = 16 } , true )
local obj = minetest.add_entity ( pos , id .. " _flying " )
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 } )
2024-01-07 21:56:58 +00:00
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
2020-08-08 08:00:16 +00:00
end
2022-02-26 21:44:50 +00:00
} )
local w = 0.7
minetest.register_entity ( id .. " _flying " , {
textures = { lingering_image ( color ) } ,
hp_max = 1 ,
visual_size = { x = w / 2 , y = w / 2 } ,
collisionbox = { - 0.1 , - 0.1 , - 0.1 , 0.1 , 0.1 , 0.1 } ,
pointable = false ,
on_step = function ( self , dtime )
local pos = self.object : get_pos ( )
local node = minetest.get_node ( pos )
local n = node.name
local g = minetest.get_item_group ( n , " liquid " )
local d = 4
if mod_target and n == " mcl_target:target_off " then
mcl_target.hit ( vector.round ( pos ) , 0.4 ) --4 redstone ticks
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 } )
2024-01-07 21:56:58 +00:00
local potency = self._potency or 0
local plus = self._plus or 0
add_lingering_effect ( pos , color , def , name == " water " , potency , plus )
2022-02-26 21:44:50 +00:00
local texture
if name == " water " then
texture = " mcl_particles_droplet_bottle.png "
2020-08-19 15:37:41 +00:00
else
2022-02-26 21:44:50 +00:00
if def.instant then
texture = " mcl_particles_instant_effect.png "
else
texture = " mcl_particles_effect.png "
end
2020-08-19 15:37:41 +00:00
end
2022-02-26 21:44:50 +00:00
linger_particles ( pos , d , texture , color )
2024-01-07 21:56:58 +00:00
if def.on_splash then def.on_splash ( pos , potency + 1 ) end
2022-02-26 21:44:50 +00:00
self.object : remove ( )
2020-06-26 23:08:41 +00:00
end
2022-02-26 21:44:50 +00:00
end ,
} )
2020-06-18 11:43:50 +00:00
end