lib_materials/lib_materials_water_dynamics.lua

540 lines
19 KiB
Lua
Raw Normal View History

2019-08-30 23:05:56 +02:00
-- Water Plus
-- By Rubenwardy
-- License: cc-by-sa
lib_materials.waterplus={}
-- Settings
lib_materials.waterplus.finite_water_steps=32 --how many finite water steps
lib_materials.waterplus.finite_water_inc_skip=1 --how many waters to skip before inc
2019-10-13 08:53:09 +02:00
lib_materials.waterplus.base_fluid = "lib_materials:liquid_water_rushing_source"
lib_materials.waterplus.base_fluid_flowing = "lib_materials:liquid_water_rushing_flowing"
2019-08-30 23:05:56 +02:00
-- Setup Finite
lib_materials.waterplus.finite_water_inc=1/(lib_materials.waterplus.finite_water_steps /(1+lib_materials.waterplus.finite_water_inc_skip))
lib_materials.waterplus.finite_water_max=math.floor(1.43/lib_materials.waterplus.finite_water_inc) --how many finite water values (give a new style water effect)
-- Debug
function dPrint(msg)
-- uncomment the following line to show debug text
--print(msg)
end
-- Debug log print settings
dPrint("Water steps: "..lib_materials.waterplus.finite_water_steps)
dPrint("Water max: "..lib_materials.waterplus.finite_water_max)
dPrint("Water inc: "..lib_materials.waterplus.finite_water_inc)
dPrint("Water inc_skip: "..lib_materials.waterplus.finite_water_inc_skip)
-- Locals
local h=lib_materials.waterplus.finite_water_inc
local c=1
dPrint("C: "..c)
dPrint("H: "..h)
-- Block create function
lib_materials.waterplus.finite_blocks = {}
lib_materials.waterplus.register_step = function(a,height)
print("Register finite block "..a.." with a height of "..height)
minetest.register_node("lib_materials:fluid_finite_"..a, {
description = "Finite Water "..a,
tiles = {
{name="lib_materials_fluid_water_rushing_source_animated.png", animation={type="vertical_frames", aspect_w=16, aspect_h=16, length=2.0}}
},
drawtype = "nodebox",
paramtype = "light",
use_texture_alpha = true,
walkable = false,
pointable = false,
diggable = false,
climbable = true,
buildable_to = true,
liquid_viscosity = 1, --added water-like viscosity
liquidtype = "source",
liquid_alternative_flowing = "lib_materials:fluid_finite_"..a,
liquid_alternative_source = "lib_materials:fluid_finite_"..a,
liquid_renewable = false,
liquid_range = 0,
post_effect_color = {a=64, r=100, g=100, b=200},
groups = {water=3,finite_water=((a/lib_materials.waterplus.finite_water_steps)*100), puts_out_fire=1},
node_box = {
type="fixed",
fixed={
{-0.5,-0.5,-0.5,0.5,height-0.5,0.5},
},
},
-- on_construct = function(pos)
-- minetest.get_node_timer(pos):start(math.random(6,12))
-- end,
-- on_timer = function(pos)
-- if not lib_ecology.can_grow(pos) then
-- -- try again 5 min later
-- minetest.get_node_timer(pos):start(300)
-- return
-- end
-- if string.find(grow, ",") then
-- local new_node_schems = grow:split(",", true)
-- local rnum = math.random(1,#new_node_schems)
-- local rname = new_node_schems[rnum]
-- minetest.place_schematic(pos, lib_ecology.schematics.select(rname), "random", nil, true, "place_center_x, place_center_z")
-- end
-- end,
})
table.insert(lib_materials.waterplus.finite_blocks,"lib_materials:fluid_finite_"..a)
lib_materials.register_liquid(
"lib_materials:fluid_finite_"..a,
"",
"lib_materials:tool_bucket_water_finite_"..a,
"lib_materials:tool_bucket_wood_water_finite_"..a,
"lib_materials:tool_bucket_steel_water_finite_"..a,
"lib_materials:tool_pot_clay_water_finite_"..a,
"lib_materials_fluid_water_river.png"
)
end
--Create blocks
for a=1, lib_materials.waterplus.finite_water_max do
c=c+1
if c>lib_materials.waterplus.finite_water_inc_skip then
c = 0
h = h + lib_materials.waterplus.finite_water_inc
end
lib_materials.waterplus.register_step(a,h)
lib_materials.waterplus.finite_water_max_id = a
end
lib_materials.waterplus.finite_water_max_name="lib_materials:fluid_finite_"..lib_materials.waterplus.finite_water_max_id
--The ABM
minetest.register_abm({
nodenames = lib_materials.waterplus.finite_blocks,
interval = 1/10,
chance = 1,
action = function(pos,node)
local node_id = getNumberFromName(node.name)
dPrint("")
dPrint("Waterplus [finite] - Calculating for "..node_id.." at "..pos.x..","..pos.y..","..pos.z)
local upc = {x=pos.x, y=pos.y+1, z=pos.z}
-- recieve pressure from up
local pressure = 1
if minetest.env:get_node(upc).name == lib_materials.waterplus.finite_water_max_name or minetest.env:get_node(upc).name == lib_materials.waterplus.base_fluid then
--pressure = minetest.env:get_meta(upc):get_int('pressure') or 1
--pressure = pressure_get(pos)
pressure = 2
end
dPrint("Waterplus [finite] - Calculating for "..node_id.." at "..pos.x..","..pos.y..","..pos.z..' press='..pressure)
local target = {x=pos.x,y=pos.y-1,z=pos.z}
dPrint(target.x..","..target.z)
--if performDrop(pos,target) then return end
if performDrop(pos,target) then
if minetest.env:get_node(upc).name == lib_materials.waterplus.base_fluid then
minetest.env:set_node(upc,{name = lib_materials.waterplus.finite_water_max_name})
end
pos=target
end
local source_name = minetest.env:get_node(pos).name
local source_id = getNumberFromName(source_name) or 0
local coords = {
{x=pos.x-1,y=pos.y-1,z=pos.z, f=1, d=1,}, -- vertical drop
{x=pos.x+1,y=pos.y-1,z=pos.z, f=1, d=1,}, -- f= can flow or drop
{x=pos.x,y=pos.y-1,z=pos.z-1, f=1, d=1,}, -- d= can drop
{x=pos.x,y=pos.y-1,z=pos.z+1, f=1, d=1,},
{x=pos.x-1,y=pos.y,z=pos.z,h=1, f=1, wi=1, iw=1,}, -- h=horisontal flow
{x=pos.x+1,y=pos.y,z=pos.z,h=1, f=1, wi=1, iw=1,}, -- wi= standard water infect
{x=pos.x,y=pos.y,z=pos.z-1,h=1, f=1, wi=1, iw=1,}, -- iw= water infects us
{x=pos.x,y=pos.y,z=pos.z+1,h=1, f=1, wi=1, iw=1,},
{x=pos.x,y=pos.y+1,z=pos.z, wi=1, u=1, b=1,}, -- look up b= bubble up
}
local can = 0
local can_water = 1
local can_max = 0
local can_min = 0
local infected = 0
--local high_nearby = 0;
-- step1: calculate possibility of flow with volumes
for i = 1,9 do
local name = minetest.env:get_node(coords[i]).name
coords[i].n = name
local target_id = getNumberFromName(name)
dPrint("test nei "..name ..' = '.. (target_id or 'NO'))
if infected < 1 and coords[i].wi and name==lib_materials.waterplus.base_fluid and source_id<lib_materials.waterplus.finite_water_max_id then
dPrint('convert up='..(coords[i].u or '')..' me=' .. source_id)
minetest.env:set_node(coords[i],{name = lib_materials.waterplus.finite_water_max_name})
target_id = lib_materials.waterplus.finite_water_max_id
--high_nearby = lib_materials.waterplus.finite_water_max_id
infected = infected + 1
end
if coords[i].f and name == "air" then
coords[i].v = lib_materials.waterplus.finite_water_max_id
coords[i].t = 0
can = 1
--elseif name=="lib_materials:fluid_water_finite_flowing" then
-- minetest.env:set_node(coords[i],{name = "lib_materials:fluid_finite_10"})
--high_nearby = math.max(high_nearby, 10);
elseif target_id == nil then
elseif coords[i].f and target_id >= 1 then
--coords[i].v = lib_materials.waterplus.finite_water_steps - target_id
coords[i].t = target_id
coords[i].o = target_id --original
if coords[i].h then --and pressure <= 1
if coords[i].t < source_id then
coords[i].v = source_id - target_id
end
else
coords[i].v = lib_materials.waterplus.finite_water_max_id - target_id
end
dPrint('test water ' .. (coords[i].wi or 'nwi') .. ' t=' .. target_id)
if coords[i].v and coords[i].v > 0 then can = 1 end
--high_nearby = math.max(high_nearby, target_id);
if coords[i].h and coords[i].t >= lib_materials.waterplus.finite_water_max_id then can_max = can_max + 1 end
end
if coords[i].d and (name==lib_materials.waterplus.base_fluid) then can_min = can_min + 1 end
--print('cmt me=' .. source_id .. ' to='.. (coords[i].d or 'no') .. ' n=' .. name .. ' r=' .. can_min )
if coords[i].h and coords[i].iw and ((target_id and target_id < lib_materials.waterplus.finite_water_max_id-1) or name == "air") then
-- do not convert to standard water if flow possible
can_water = 0
dPrint('cant water ' .. (target_id or 0) .. ' n='..name)
end
end
-- step2: perform flow and drop twice: first for drop then flow if something rest
for pass=0,1 do
while can>0 and source_id>0 do
local flowed = 0
for i = 1+(pass*4),4+(pass*4) do
local min = 0
--print('testpress ' .. (coords[i].h or 'vertical') .. ' p='.. pressure)
if coords[i].h and pressure <= 1 then
min = coords[i].t or 0
min = min + 1
-- trick: flow more if have higher nearby watre level: bad idea for now
--if high_nearby > source_id then
--min = math.ceil((high_nearby + source_id + min)/3)
--print('cheat min='..min ..' h=' .. high_nearby .. ' s='.. source_id)
--end
if not min or min < 1 then min = 1 end
end
dPrint ('flowto p='..pass..' i='..i.. ' v='..(coords[i].v or'NO') .. ' s='.. source_id .. ' min='.. min)
-- perform one-level flow
if coords[i].v and coords[i].v > 0 and source_id > min then
coords[i].v = coords[i].v - 1
source_id = source_id - 1
coords[i].a = (coords[i].a or 0) + 1
coords[i].t = coords[i].t + 1
flowed = 1
dPrint('flow p='..pass..' i='..i.. ' v=' .. coords[i].v ..' t='.. coords[i].t .. ' s='..source_id.. ' min='..min .. ' fl='..coords[i].a)
if source_id < 1 then break end
end
end
if source_id < 1 or flowed < 1 then break end
dPrint ('res flv='..flowed .. ' sid='..source_id)
end
end
for i = 1,9 do
-- bubble fast up
if coords[i].b and coords[i].n == lib_materials.waterplus.base_fluid then
--dPrint('r1' .. "lib_materials:fluid_finite_".."lib_materials:fluid_finite_"..source_id)
local set = "lib_materials:fluid_finite_"..source_id
if source_id < 1 then set = "air" end
minetest.env:set_node(coords[i],{name = set})
source_id = lib_materials.waterplus.finite_water_max_id
can_water = 1
--print ('bubble up '..source_id)
end
if coords[i].a and coords[i].o ~= coords[i].t then
dPrint ('repl '..(coords[i].o or 'air') ..' to' .. coords[i].t)
minetest.env:set_node(coords[i],{name = "lib_materials:fluid_finite_"..coords[i].t})
end
end
--canmax: trick for reduce finite blocks, add one if cant flow and max nearby 21+22 = 22+22
dPrint('canmax=' .. can_max..' s='..source_id.. ' cw='..can_water)
if can_max >= 1 and source_id == lib_materials.waterplus.finite_water_max_id - 1 then
--print('canmax '..source_id)
source_id = lib_materials.waterplus.finite_water_max_id
end
--canmin: remove last level if down nearby is full 1+22 = 22
--print('canmin=' .. can_min..' s='..source_id.. ' cw='..can_water)
if can_min >= 1 and source_id == 1 then
--print('canmin '..source_id)
source_id = 0
end
local set = "lib_materials:fluid_finite_"..source_id
if source_id < 1 then set = "air" end
-- can_max - cheat for decreasing finite blocks at top of ocean
dPrint('test canwater' .. can_water ..' me='.. source_id)
if can_water>0 and source_id == lib_materials.waterplus.finite_water_max_id then
set = lib_materials.waterplus.base_fluid
end
if set ~= source_name then
dPrint('src set ' .. ' was= '..source_name.. ' now '..source_id .. ' to '..set)
minetest.env:set_node(pos,{name = set})
end
--[[ not used
if source_id < 1 then return end
if 1 then return end
target = {x=pos.x,y=pos.y,z=pos.z}
target.x=target.x+1
dPrint(target.x..","..target.z)
performFlow(pos,target)
target = {x=pos.x,y=pos.y,z=pos.z}
target.x=target.x-1
dPrint(target.x..","..target.z)
performFlow(pos,target)
target = {x=pos.x,y=pos.y,z=pos.z}
target.z=target.z+1
dPrint(target.x..","..target.z)
performFlow(pos,target)
target = {x=pos.x,y=pos.y,z=pos.z}
target.z=target.z-1
dPrint(target.x..","..target.z)
performFlow(pos,target)
target = {x=pos.x,y=pos.y,z=pos.z}
target.x=target.x+1
target.z=target.z+1
dPrint(target.x..","..target.z)
performFlow(pos,target)
target = {x=pos.x,y=pos.y,z=pos.z}
target.x=target.x+1
target.z=target.z-1
dPrint(target.x..","..target.z)
performFlow(pos,target)
target = {x=pos.x,y=pos.y,z=pos.z}
target.x=target.x-1
target.z=target.z+1
dPrint(target.x..","..target.z)
performFlow(pos,target)
]]
dPrint("--Calculation Complete")
dPrint("")
end,
})
-- name (string)
function getNumberFromName(name)
return tonumber(string.gsub(name, "lib_materials:fluid_finite_", ""),10)
end
--from (pos): position of the node the abm is being run on
--to (pos): position of the node to check
--[[
function performFlow(from,to)
dPrint("> Flow Calculation")
local target = minetest.env:get_node(to).name
local target_id = getNumberFromName(target)
local source = minetest.env:get_node(from).name
local id = getNumberFromName(source)
if id == nil then
id = 0
end
if target ~= "air" and tonumber(target_id) == nil then
dPrint(" > Exit on is not finite liquid")
return
end
if target_id == nil then
target_id=0
end
dPrint(" > Testing Heights: "..id.." vs "..target_id)
if id == 1 and target_id == 0 and math.random(1,4) == 1 then
if performDrop(from, {x=to.x,y=to.y-1,z=to.z}) then
return
end
end
if id > target_id and id > 0 then
dPrint(" > Flowing")
local nh_to = "lib_materials:fluid_finite_"..(target_id+1)
local nh_from = "lib_materials:fluid_finite_"..(id-1)
if (id-1) < 1 or (target_id+1) > lib_materials.waterplus.finite_water_max then
dPrint(" > Exit on too high, or too low")
return
end
minetest.env:set_node(from,{name = nh_from})
minetest.env:set_node(to,{name = nh_to})
dPrint(" > Done")
end
end
]]
--from (pos): position of the node the abm is being run on
--to (pos): position of the node to check
function performDrop(from,to)
dPrint("> Drop Calculation")
local target = minetest.env:get_node(to).name
local target_id = getNumberFromName(target)
local source = minetest.env:get_node(from).name
local id = getNumberFromName(source)
if target ~= "air" and tonumber(target_id) == nil then
dPrint(" > Exit on is not finite liquid")
return
end
if target_id == nil then
target_id=0
end
if target_id >= lib_materials.waterplus.finite_water_max_id then
return
end
if id == nil then
id = 0
end
--dPrint('droptest '..target_id ..'+'.. id ..' maxid='.. lib_materials.waterplus.finite_water_max_id ..' max='.. lib_materials.waterplus.finite_water_max)
target_id = target_id + id
id=0
if target_id > lib_materials.waterplus.finite_water_max_id then
id = target_id - lib_materials.waterplus.finite_water_max_id
target_id = lib_materials.waterplus.finite_water_max_id
end
local nh_to = "lib_materials:fluid_finite_"..(target_id)
local nh_from = "lib_materials:fluid_finite_"..(id)
if id == 0 or id == nil then
nh_from = "air"
end
--print("drop ".. nh_from ..'->'..nh_to )
minetest.env:set_node(from,{name = nh_from})
minetest.env:set_node(to,{name = nh_to})
return 1
end
-- bug with set-get value, not used
function pressure_get(pos, recalc)
local node = minetest.env:get_node(pos)
if not (node.name == lib_materials.waterplus.finite_water_max_name or node.name == lib_materials.waterplus.base_fluid) then return 0 end
local p = minetest.env:get_meta(pos):get_int('pressure') or 0
--print('press read=' .. p .. ' xyz='..pos.x..","..pos.y..","..pos.z)
if p > 0 and not recalc then return p end
p = 1 + pressure_get({x=pos.x,y=pos.y+1,z=pos.z})
minetest.env:get_meta(pos):set_int('pressure', p)
--print('press save=' .. p ..' xyz='..pos.x..","..pos.y..","..pos.z)
return p;
end
--minetest.register_alias("lib_materials:fluid_water_finite_source","lib_materials:fluid_finite_20")
--minetest.register_alias("lib_materials:fluid_water_finite_flowing","lib_materials:fluid_finite_10")
minetest.register_abm({
nodenames = {lib_materials.waterplus.base_fluid_flowing},
interval = 1,
chance = 1,
action = function(pos,node)
local level = math.floor((node.param2/15)*lib_materials.waterplus.finite_water_max_id)
if level < 1 then level = 1 end
if level > lib_materials.waterplus.finite_water_max_id-3 then level = lib_materials.waterplus.finite_water_max_id-3 end
dPrint("Waterplus [finite] - transforming float water to finite ".." at "..pos.x..","..pos.y..","..pos.z .. ' p1='.. node.param1 .. ' p2='.. node.param2 .. ' level='.. level)
minetest.env:set_node(pos,{name = "lib_materials:fluid_finite_"..level, param1=node.param1, param2=node.param2})
end
})
minetest.register_craftitem("lib_materials:tool_bucket_fluid_water_finite", {
inventory_image = "bucket_water.png",
stack_max = 1,
liquids_pointable = true,
on_use = function(itemstack, user, pointed_thing)
-- Must be pointing to node
if pointed_thing.type ~= "node" then
return
end
-- Check if pointing to a buildable node
n = minetest.env:get_node(pointed_thing.under)
if minetest.registered_nodes[n.name].buildable_to then
-- buildable; replace the node
minetest.env:add_node(pointed_thing.under, {name="lib_materials:fluid_finite_20"})
else
-- not buildable to; place the liquid above
-- check if the node above can be replaced
n = minetest.env:get_node(pointed_thing.above)
if minetest.registered_nodes[n.name].buildable_to then
minetest.env:add_node(pointed_thing.above, {name="lib_materials:fluid_finite_20"})
else
-- do not remove the bucket with the liquid
return
end
end
return {name="lib_materials:tool_bucket_empty"}
end
})