2021-05-29 16:12:33 +02:00
local S = minetest.get_translator ( minetest.get_current_modname ( ) )
2020-07-10 13:01:21 +02:00
2024-09-06 14:27:10 +02:00
local PARTICLE_DENSITY = 4
2022-02-26 22:44:50 +01:00
local mod_target = minetest.get_modpath ( " mcl_target " )
2021-05-29 16:12:33 +02:00
local function lingering_image ( colorstring , opacity )
2020-06-18 13:43:50 +02:00
if not opacity then
opacity = 127
end
2020-07-05 23:36:18 +02:00
return " mcl_potions_splash_overlay.png^[colorize: " .. colorstring .. " : " .. tostring ( opacity ) .. " ^mcl_potions_lingering_bottle.png "
2020-06-18 13:43:50 +02:00
end
2020-06-27 02:32:03 +02:00
local lingering_effect_at = { }
2024-01-07 22:56:58 +01: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-28 00:50:08 +02:00
end
2020-06-27 02:32:03 +02:00
2020-08-22 11:18:45 +02: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 02:32:03 +02:00
2020-06-28 00:50:08 +02:00
local lingering_timer = 0
minetest.register_globalstep ( function ( dtime )
2020-06-27 02:32:03 +02:00
2020-06-28 00:50:08 +02:00
lingering_timer = lingering_timer + dtime
if lingering_timer >= 1 then
2020-06-27 02:32:03 +02:00
2020-06-28 00:50:08 +02:00
for pos , vals in pairs ( lingering_effect_at ) do
2020-06-27 02:32:03 +02:00
2020-06-28 00:50:08 +02:00
vals.timer = vals.timer - lingering_timer
local d = 4 * ( vals.timer / 30.0 )
2020-08-05 19:26:51 +02:00
local texture
if vals.is_water then
2020-08-19 14:12:51 +02:00
texture = " mcl_particles_droplet_bottle.png "
2020-08-19 17:37:41 +02:00
elseif vals.def . instant then
texture = " mcl_particles_instant_effect.png "
2020-08-05 19:26:51 +02:00
else
2020-08-19 14:12:51 +02:00
texture = " mcl_particles_effect.png "
2020-08-05 19:26:51 +02:00
end
2024-09-06 14:27:10 +02:00
linger_particles ( pos , PARTICLE_DENSITY , texture , vals.color )
2020-08-05 19:26:51 +02:00
2024-01-07 22:56:58 +01: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 18:33:53 +02:00
end
-- Affect players and mobs
2020-06-28 00:50:08 +02:00
for _ , obj in pairs ( minetest.get_objects_inside_radius ( pos , d ) ) do
2020-06-27 03:27:17 +02:00
2020-06-28 00:50:08 +02:00
local entity = obj : get_luaentity ( )
2024-01-07 22:56:58 +01: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-08 00:25:30 +01:00
dur = dur * mcl_potions.LINGERING_FACTOR
2024-01-07 22:56:58 +01:00
else
dur = details.dur
end
2024-04-22 04:51:01 +02:00
if details.effect_stacks then
ef_level = ef_level + mcl_potions.get_effect_level ( obj , name )
end
2024-01-07 22:56:58 +01:00
if mcl_potions.give_effect_by_level ( name , obj , ef_level , dur ) then
applied = true
end
end
end
2020-06-27 02:32:03 +02:00
2024-01-08 00:25:30 +01:00
if vals.def . custom_effect
2024-04-22 04:51:01 +02:00
and vals.def . custom_effect ( obj , ( vals.potency + 1 ) * mcl_potions.LINGERING_FACTOR , plus ) then
2024-01-08 00:25:30 +01:00
applied = true
2024-01-07 22:56:58 +01:00
end
2020-06-27 02:32:03 +02:00
2024-01-07 22:56:58 +01:00
if applied then vals.timer = vals.timer - 3.25 end
2020-06-27 02:32:03 +02:00
end
end
2020-08-08 10:00:16 +02:00
if vals.timer <= 0 then
lingering_effect_at [ pos ] = nil
end
2020-06-28 00:50:08 +02:00
end
lingering_timer = 0
end
end )
2020-06-27 02:32:03 +02:00
2020-07-12 13:59:29 +02:00
function mcl_potions . register_lingering ( name , descr , color , def )
2020-08-08 10:00:16 +02:00
local id = " mcl_potions: " .. name .. " _lingering "
2024-01-07 22:56:58 +01:00
local longdesc = def._longdesc
2020-08-08 10:00:16 +02:00
if not def.no_effect then
2024-01-07 22:56:58 +01: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 10:00:16 +02:00
if def.longdesc then
2024-01-07 22:56:58 +01:00
longdesc = longdesc .. " \n " .. def._longdesc
2020-08-08 10:00:16 +02:00
end
end
2024-01-08 00:41:08 +01: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 10:00:16 +02:00
minetest.register_craftitem ( id , {
2022-02-26 22:44:50 +01:00
description = descr ,
2024-01-07 22:56:58 +01:00
_tt_help = def._tt ,
_dynamic_tt = def._dynamic_tt ,
2022-02-26 22:44:50 +01:00
_doc_items_longdesc = longdesc ,
_doc_items_usagehelp = S ( " Use the “Punch” key to throw it. " ) ,
2024-01-07 22:56:58 +01: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 22:44:50 +01:00
inventory_image = lingering_image ( color ) ,
2024-01-08 00:41:08 +01:00
groups = groups ,
2022-02-26 22:44:50 +01: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 22:56:58 +01: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 22:44:50 +01: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 22:56:58 +01:00
local ent = obj : get_luaentity ( )
2024-05-30 10:02:59 +02:00
ent._potency = stack : get_meta ( ) : get_int ( " mcl_potions:potion_potent " )
ent._plus = stack : get_meta ( ) : get_int ( " mcl_potions:potion_plus " )
2024-01-07 22:56:58 +01:00
ent._effect_list = def._effect_list
2020-08-08 10:00:16 +02:00
end
2022-02-26 22:44:50 +01:00
} )
local w = 0.7
2024-09-06 14:27:10 +02:00
local particle_texture
if name == " water " then
particle_texture = " mcl_particles_droplet_bottle.png "
else
if def.instant then
particle_texture = " mcl_particles_instant_effect.png "
else
particle_texture = " mcl_particles_effect.png "
end
end
local function on_collide ( self , pos )
local potency = self._potency or 0
local plus = self._plus or 0
add_lingering_effect ( pos , color , def , name == " water " , potency , plus )
linger_particles ( pos , PARTICLE_DENSITY , particle_texture , color )
if def.on_splash then def.on_splash ( pos , potency + 1 ) end
end
vl_projectile.register ( id .. " _flying " , {
2022-02-26 22:44:50 +01:00
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 ,
2024-09-06 14:27:10 +02:00
_vl_projectile = {
behaviors = {
vl_projectile.collides_with_entities ,
vl_projectile.collides_with_solids ,
} ,
on_collide_with_entity = on_collide ,
on_collide_with_solid = function ( self , pos , node )
if mod_target and n == " mcl_target:target_off " then
mcl_target.hit ( vector.round ( pos ) , 0.4 ) --4 redstone ticks
2020-08-19 17:37:41 +02:00
end
2024-09-06 14:27:10 +02:00
on_collide ( self , pos )
end ,
sounds = {
{ " mcl_potions_breaking_glass " , { max_hear_distance = 16 , gain = 1 } } ,
} ,
} ,
2022-02-26 22:44:50 +01:00
} )
2020-06-18 13:43:50 +02:00
end