mirror of
https://github.com/ShadMOrdre/lib_materials.git
synced 2024-11-14 06:30:26 +01:00
540 lines
19 KiB
Lua
540 lines
19 KiB
Lua
-- 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
|
|
|
|
|
|
lib_materials.waterplus.base_fluid = "default:river_water_source"
|
|
lib_materials.waterplus.base_fluid_flowing = "default:river_water_flowing"
|
|
|
|
|
|
-- 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
|
|
})
|