2017-01-26 21:12:13 +00:00
dynamic_liquid = { } -- global table to expose liquid_abm for other mods' usage
2017-01-23 06:45:00 +00:00
2017-02-03 03:27:54 +00:00
-- internationalization boilerplate
local MP = minetest.get_modpath ( minetest.get_current_modname ( ) )
local S , NS = dofile ( MP .. " /intllib.lua " )
2017-01-24 08:02:33 +00:00
-- By making this giant table of all possible permutations of horizontal direction we can avoid
-- lots of redundant calculations.
local all_direction_permutations = {
{ { x = 0 , z = 1 } , { x = 0 , z =- 1 } , { x = 1 , z = 0 } , { x =- 1 , z = 0 } } ,
{ { x = 0 , z = 1 } , { x = 0 , z =- 1 } , { x =- 1 , z = 0 } , { x = 1 , z = 0 } } ,
{ { x = 0 , z = 1 } , { x = 1 , z = 0 } , { x = 0 , z =- 1 } , { x =- 1 , z = 0 } } ,
{ { x = 0 , z = 1 } , { x = 1 , z = 0 } , { x =- 1 , z = 0 } , { x = 0 , z =- 1 } } ,
{ { x = 0 , z = 1 } , { x =- 1 , z = 0 } , { x = 0 , z =- 1 } , { x = 1 , z = 0 } } ,
{ { x = 0 , z = 1 } , { x =- 1 , z = 0 } , { x = 1 , z = 0 } , { x = 0 , z =- 1 } } ,
{ { x = 0 , z =- 1 } , { x = 0 , z = 1 } , { x =- 1 , z = 0 } , { x = 1 , z = 0 } } ,
{ { x = 0 , z =- 1 } , { x = 0 , z = 1 } , { x = 1 , z = 0 } , { x =- 1 , z = 0 } } ,
{ { x = 0 , z =- 1 } , { x = 1 , z = 0 } , { x =- 1 , z = 0 } , { x = 0 , z = 1 } } ,
{ { x = 0 , z =- 1 } , { x = 1 , z = 0 } , { x = 0 , z = 1 } , { x =- 1 , z = 0 } } ,
{ { x = 0 , z =- 1 } , { x =- 1 , z = 0 } , { x = 1 , z = 0 } , { x = 0 , z = 1 } } ,
{ { x = 0 , z =- 1 } , { x =- 1 , z = 0 } , { x = 0 , z = 1 } , { x = 1 , z = 0 } } ,
{ { x = 1 , z = 0 } , { x = 0 , z = 1 } , { x = 0 , z =- 1 } , { x =- 1 , z = 0 } } ,
{ { x = 1 , z = 0 } , { x = 0 , z = 1 } , { x =- 1 , z = 0 } , { x = 0 , z =- 1 } } ,
{ { x = 1 , z = 0 } , { x = 0 , z =- 1 } , { x = 0 , z = 1 } , { x =- 1 , z = 0 } } ,
{ { x = 1 , z = 0 } , { x = 0 , z =- 1 } , { x =- 1 , z = 0 } , { x = 0 , z = 1 } } ,
{ { x = 1 , z = 0 } , { x =- 1 , z = 0 } , { x = 0 , z = 1 } , { x = 0 , z =- 1 } } ,
{ { x = 1 , z = 0 } , { x =- 1 , z = 0 } , { x = 0 , z =- 1 } , { x = 0 , z = 1 } } ,
{ { x =- 1 , z = 0 } , { x = 0 , z = 1 } , { x = 1 , z = 0 } , { x = 0 , z =- 1 } } ,
{ { x =- 1 , z = 0 } , { x = 0 , z = 1 } , { x = 0 , z =- 1 } , { x = 1 , z = 0 } } ,
{ { x =- 1 , z = 0 } , { x = 0 , z =- 1 } , { x = 1 , z = 0 } , { x = 0 , z = 1 } } ,
{ { x =- 1 , z = 0 } , { x = 0 , z =- 1 } , { x = 0 , z = 1 } , { x = 1 , z = 0 } } ,
{ { x =- 1 , z = 0 } , { x = 1 , z = 0 } , { x = 0 , z =- 1 } , { x = 0 , z = 1 } } ,
{ { x =- 1 , z = 0 } , { x = 1 , z = 0 } , { x = 0 , z = 1 } , { x = 0 , z =- 1 } } ,
}
2017-01-23 06:45:00 +00:00
2017-01-24 08:20:45 +00:00
local get_node = minetest.get_node
local set_node = minetest.set_node
2017-01-26 21:12:13 +00:00
dynamic_liquid.liquid_abm = function ( liquid , flowing_liquid , chance )
2017-01-23 06:45:00 +00:00
minetest.register_abm ( {
nodenames = { liquid } ,
neighbors = { flowing_liquid } ,
interval = 1 ,
chance = chance or 1 ,
catch_up = false ,
2017-01-25 03:04:28 +00:00
action = function ( pos , node ) -- Do everything possible to optimize this method
2017-01-24 08:02:33 +00:00
local check_pos = { x = pos.x , y = pos.y - 1 , z = pos.z }
2017-01-24 08:20:45 +00:00
local check_node = get_node ( check_pos )
2017-01-25 19:10:48 +00:00
local check_node_name = check_node.name
if check_node_name == flowing_liquid or check_node_name == " air " then
2017-01-24 08:20:45 +00:00
set_node ( pos , check_node )
set_node ( check_pos , node )
2017-01-23 06:45:00 +00:00
return
end
2017-01-24 22:20:46 +00:00
local perm = all_direction_permutations [ math.random ( 24 ) ]
2017-01-24 16:34:30 +00:00
local dirs -- declare outside of loop so it won't keep entering/exiting scope
2017-01-24 08:02:33 +00:00
for i = 1 , 4 do
2017-01-24 16:34:30 +00:00
dirs = perm [ i ]
-- reuse check_pos to avoid allocating a new table
check_pos.x = pos.x + dirs.x
check_pos.y = pos.y
check_pos.z = pos.z + dirs.z
2017-01-24 08:20:45 +00:00
check_node = get_node ( check_pos )
2017-01-25 19:10:48 +00:00
check_node_name = check_node.name
if check_node_name == flowing_liquid or check_node_name == " air " then
2017-01-24 08:20:45 +00:00
set_node ( pos , check_node )
set_node ( check_pos , node )
2017-01-24 16:34:30 +00:00
return
2017-01-24 08:02:33 +00:00
end
2017-01-23 06:45:00 +00:00
end
end
} )
end
2017-01-29 22:28:48 +00:00
if not minetest.get_modpath ( " default " ) then
return
end
2017-01-26 21:12:13 +00:00
local water = minetest.setting_getbool ( " dynamic_liquid_water " )
water = water or water == nil -- default true
2017-02-02 18:26:51 +00:00
local river_water = minetest.setting_getbool ( " dynamic_liquid_river_water " ) -- default false
2017-01-26 21:12:13 +00:00
local lava = minetest.setting_getbool ( " dynamic_liquid_lava " )
lava = lava or lava == nil -- default true
2017-01-28 03:47:22 +00:00
local water_probability = tonumber ( minetest.setting_get ( " dynamic_liquid_water_flow_propability " ) )
if water_probability == nil then
water_probability = 1
end
local river_water_probability = tonumber ( minetest.setting_get ( " dynamic_liquid_river_water_flow_propability " ) )
if river_water_probability == nil then
river_water_probability = 1
end
2017-01-26 21:12:13 +00:00
local lava_probability = tonumber ( minetest.setting_get ( " dynamic_liquid_lava_flow_propability " ) )
if lava_probability == nil then
lava_probability = 5
end
local springs = minetest.setting_getbool ( " dynamic_liquid_springs " )
springs = springs or springs == nil -- default true
if water then
-- override water_source and water_flowing with liquid_renewable set to false
2017-02-14 06:50:07 +00:00
local override_def = { liquid_renewable = false }
minetest.override_item ( " default:water_source " , override_def )
minetest.override_item ( " default:water_flowing " , override_def )
2017-01-26 21:12:13 +00:00
end
2017-01-23 06:45:00 +00:00
if lava then
2017-01-26 21:12:13 +00:00
dynamic_liquid.liquid_abm ( " default:lava_source " , " default:lava_flowing " , lava_probability )
2017-01-23 06:45:00 +00:00
end
if water then
2017-01-28 03:47:22 +00:00
dynamic_liquid.liquid_abm ( " default:water_source " , " default:water_flowing " , water_probability )
2017-01-23 06:45:00 +00:00
end
if river_water then
2017-01-28 03:47:22 +00:00
dynamic_liquid.liquid_abm ( " default:river_water_source " , " default:river_water_flowing " , river_water_probability )
2017-01-23 06:45:00 +00:00
end
2017-02-14 06:50:07 +00:00
local duplicate_def = function ( name )
local old_def = minetest.registered_nodes [ name ]
local new_def = { }
for param , value in pairs ( old_def ) do
new_def [ param ] = value
end
return new_def
end
2017-01-23 06:45:00 +00:00
-- register damp clay whether we're going to set the ABM or not, if the user disables this feature we don't want existing
-- spring clay to turn into unknown nodes.
local clay_def = duplicate_def ( " default:clay " )
2017-02-03 03:27:54 +00:00
clay_def.description = S ( " Damp Clay " )
2017-01-24 22:11:29 +00:00
if not springs then
clay_def.groups . not_in_creative_inventory = 1 -- take it out of creative inventory though
end
2017-01-23 06:45:00 +00:00
minetest.register_node ( " dynamic_liquid:clay " , clay_def )
2017-01-27 06:12:06 +00:00
local data = { }
2017-01-23 06:45:00 +00:00
if springs then
local c_clay = minetest.get_content_id ( " default:clay " )
local c_spring_clay = minetest.get_content_id ( " dynamic_liquid:clay " )
2017-01-27 05:07:09 +00:00
local water_level = minetest.get_mapgen_params ( ) . water_level
2017-01-23 23:53:50 +00:00
-- Turn mapgen clay into spring clay
2017-01-23 06:45:00 +00:00
minetest.register_on_generated ( function ( minp , maxp , seed )
2017-01-27 06:03:27 +00:00
if minp.y >= water_level or maxp.y <= - 15 then
2017-01-23 06:45:00 +00:00
return
end
local vm , emin , emax = minetest.get_mapgen_object ( " voxelmanip " )
2017-01-27 06:12:06 +00:00
vm : get_data ( data )
2017-01-23 06:45:00 +00:00
for voxelpos , voxeldata in pairs ( data ) do
if voxeldata == c_clay then
data [ voxelpos ] = c_spring_clay
end
end
vm : set_data ( data )
2017-01-27 06:12:06 +00:00
vm : write_to_map ( )
2017-01-23 06:45:00 +00:00
end )
minetest.register_abm ( {
nodenames = { " dynamic_liquid:clay " } ,
2017-01-23 23:53:50 +00:00
neighbors = { " air " , " default:water_source " , " default:water_flowing " } ,
2017-01-23 06:45:00 +00:00
interval = 1 ,
chance = 1 ,
catch_up = false ,
action = function ( pos , node )
2017-01-24 16:34:30 +00:00
local check_node
local check_node_name
2017-01-27 05:07:09 +00:00
while pos.y < water_level do
2017-01-23 23:53:50 +00:00
pos.y = pos.y + 1
2017-01-24 16:34:30 +00:00
check_node = get_node ( pos )
check_node_name = check_node.name
if check_node_name == " air " or check_node_name == " default:water_flowing " then
2017-01-24 08:27:18 +00:00
set_node ( pos , { name = " default:water_source " } )
2017-01-24 16:34:30 +00:00
elseif check_node_name ~= " default:water_source " then
2017-01-23 23:53:50 +00:00
--Something's been put on top of this clay, don't send water through it
break
end
2017-01-23 06:45:00 +00:00
end
end
} )
2017-01-24 22:11:29 +00:00
-- This is a creative-mode only node that produces a modest amount of water continuously no matter where it is.
-- Allow this one to turn into "unknown node" when this feature is disabled, since players had to explicitly place it.
minetest.register_node ( " dynamic_liquid:spring " , {
2017-02-12 19:58:16 +00:00
description = S ( " Spring " ) ,
_doc_items_longdesc = S ( " A natural spring that generates an endless stream of water source blocks " ) ,
_doc_items_usagehelp = S ( " Generates one source block of water directly on top of itself once per second, provided the space is clear. If this natural spring is dug out the flow stops and it is turned into ordinary cobble. " ) ,
drops = " default:gravel " ,
tiles = { " default_cobble.png^[combine:16x80:0,-48=crack_anylength.png " ,
" default_cobble.png " , " default_cobble.png " , " default_cobble.png " , " default_cobble.png " , " default_cobble.png " ,
} ,
is_ground_content = false ,
groups = { cracky = 3 , stone = 2 } ,
sounds = default.node_sound_gravel_defaults ( ) ,
2017-01-24 22:11:29 +00:00
} )
minetest.register_abm ( {
nodenames = { " dynamic_liquid:spring " } ,
neighbors = { " air " , " default:water_flowing " } ,
interval = 1 ,
chance = 1 ,
catch_up = false ,
action = function ( pos , node )
pos.y = pos.y + 1
2017-01-24 22:20:46 +00:00
local check_node = get_node ( pos )
local check_node_name = check_node.name
2017-01-24 22:11:29 +00:00
if check_node_name == " air " or check_node_name == " default:water_flowing " then
set_node ( pos , { name = " default:water_source " } )
end
end
} )
2017-01-23 06:45:00 +00:00
end