minetest_bitumen/fluids.lua

664 lines
15 KiB
Lua

local function combine_table(a, b)
a = a or {}
for k,v in pairs(a) do
b[k] = v
end
return b
end
local function register_fluid(modname, name, info)
local fname = modname..":"..name
local full_fname = modname..":"..name.."_full"
local gname = modname.."_"..name.."_fluid"
local groups = { liquid = 3, [gname]=1}
for n,l in pairs(info.groups) do
groups[n] = l
end
local full_groups = {not_in_creative_inventory = 1}
for n,l in pairs(groups) do
full_groups[n] = l
end
minetest.register_node(fname, combine_table(info.def, {
description = info.desc,
drawtype = "nodebox",
paramtype = "light",
paramtype2 = "leveled",
tiles = {
{
name = "default_river_water_source_animated.png"..info.colorize,
animation = {
type = "vertical_frames",
aspect_w = 16,
aspect_h = 16,
length = 2.0,
},
},
},
special_tiles = {
{
name = "default_river_water_source_animated.png"..info.colorize,
animation = {
type = "vertical_frames",
aspect_w = 16,
aspect_h = 16,
length = 2.0,
},
backface_culling = false,
},
},
leveled = 64,
alpha = 160,
drop = "",
drowning = 1,
walkable = false, -- because viscosity doesn't work for regular nodes, and the liquid hack can't be leveled
climbable = true, -- because viscosity doesn't work for regular nodes, and the liquid hack can't be leveled
pointable = false,
diggable = false,
buildable_to = true,
post_effect_color = info.post_effect_color,
groups = groups,
nonfull_name = fname,
sounds = default.node_sound_water_defaults(),
node_box = {
type = "leveled",
fixed = {
{-0.5, -0.5, -0.5, 0.5, 0.5, 0.5}, -- NodeBox1
}
}
}))
-- this is a special node used to optimize large pools of water
-- its flowing abm runs much less frequently
minetest.register_node(full_fname, combine_table(info.def, {
description = info.desc,
drawtype = "nodebox",
paramtype = "light",
paramtype2 = "leveled",
tiles = {
{
name = "default_river_water_source_animated.png"..info.colorize,
animation = {
type = "vertical_frames",
aspect_w = 16,
aspect_h = 16,
length = 2.0,
},
},
},
special_tiles = {
{
name = "default_river_water_source_animated.png"..info.colorize,
animation = {
type = "vertical_frames",
aspect_w = 16,
aspect_h = 16,
length = 2.0,
},
backface_culling = false,
},
},
leveled = 64,
alpha = 160,
drop = "",
drowning = 1,
walkable = false, -- because viscosity doesn't work for regular nodes, and the liquid hack can't be leveled
climbable = true, -- because viscosity doesn't work for regular nodes, and the liquid hack can't be leveled
pointable = false,
diggable = false,
buildable_to = true,
post_effect_color = info.post_effect_color,
groups = full_groups,
nonfull_name = fname,
sounds = default.node_sound_water_defaults(),
node_box = {
type = "leveled",
fixed = {
{-0.5, -0.5, -0.5, 0.5, 0.5, 0.5}, -- NodeBox1
}
}
}))
local default_soak = {
["default:cobble"] = 10,
["default:desert_cobble"] = 10,
["default:mossycobble"] = 9,
["default:dirt"] = 2,
["default:dirt_with_grass"] = 2,
["default:dirt_with_grass_footsteps"] = 2,
["default:dirt_with_dry_grass"] = 2,
["default:dirt_with_coniferous_litter"] = 2,
["default:dirt_with_rainforest_litter"] = 1,
["default:gravel"] = 8,
["default:coral_orange"] = 6,
["default:coral_brown"] = 6,
["default:coral_skeleton"] = 6,
["default:sand"] = 6,
["default:sand_with_kelp"] = 6,
["default:desert_sand"] = 7,
["default:silver_sand"] = 7,
["default:snow"] = 4,
["default:snowblock"] = 4,
["default:leaves"] = 60,
["default:bush_leaves"] = 60,
["default:jungleleaves"] = 60,
["default:pine_needles"] = 60,
["default:acacia_leaves"] = 60,
["default:acacia_bush_leaves"] = 60,
["default:aspen_leaves"] = 60,
-- dilution
["default:water_source"] = 65,
["default:water_flowing"] = 65,
["default:river_water_source"] = 65,
["default:river_water_flowing"] = 65,
-- boiling -- TODO: steam effect
["default:lava_source"] = 65,
["default:lava_flowing"] = 65,
-- no ladder hacks
["default:ladder_wood"] = 65,
-- ["default:ladder_steel"] = 65, -- need to figure out a way for water to flow through ladders
["default:sign_wall_wood"] = 65,
["default:sign_wall_steel"] = 65,
["default:fence_wood"] = 65,
["default:fence_acacia_wood"] = 65,
["default:fence_junglewood"] = 65,
["default:fence_pine_wood"] = 65,
["default:fence_aspen_wood"] = 65,
["default:torch"] = 65,
["carts:rail"] = 65,
["carts:brakerail"] = 65,
["carts:powerrail"] = 65,
}
local soak_names = {}
local soak = {}
if info.no_default_soak ~= true then
soak = default_soak
for n,_ in pairs(soak) do
table.insert(soak_names, n)
end
end
-- todo: superflammability
-- boil-off for water near fire
-- vapors or explosions
if info.evap_chance > 0 then
if info.vapor == true then
-- evaporation to flammable vapors
minetest.register_abm({
nodenames = {"group:"..gname},
neighbors = {"air"},
interval = info.evap_interval,
chance = info.evap_chance,
action = function(pos)
local mylevel = minetest.get_node_level(pos)
if math.random(16 - minetest.get_node_light(pos)) == 1 then
if mylevel > info.evap_rate then
local vn = minetest.find_node_near(pos, 1, {"air"})
if vn then
-- only evaporate if there is somewhere to evaporate to
minetest.set_node_level(pos, mylevel - info.evap_rate)
minetest.set_node(vn, {name = "bitumen:vapor_2"})
end
else
minetest.set_node(pos, {name = "bitumen:vapor_2"})
end
end
end
})
else
-- normal evaporation
minetest.register_abm({
nodenames = {"group:"..gname},
neighbors = {"air"},
interval = info.evap_interval,
chance = info.evap_chance,
action = function(pos)
local mylevel = minetest.get_node_level(pos)
if math.random(16 - minetest.get_node_light(pos)) == 1 then
if mylevel > info.evap_rate then
minetest.set_node_level(pos, mylevel - info.evap_rate)
else
minetest.set_node(pos, {name = "air"})
end
end
end
})
end
end
-- de-stagnation (faster flowing)
minetest.register_abm({
nodenames = {full_fname},
neighbors = {"air"},
interval = info.reflow_interval or 5,
chance = info.flow_chance or 1,
action = function(pos)
-- if it's near air it might flow
minetest.set_node(pos, {name = fname})
end
})
-- flowing
minetest.register_abm({
nodenames = {fname},
neighbors = {"group:"..gname, "air", "group:bitumen_vapor"},
interval = info.flow_interval or 1,
chance = info.flow_chance or 1,
action = function(pos)
local mylevel = minetest.get_node_level(pos)
-- print("\n mylevel ".. mylevel)
-- falling
local below = {x=pos.x, y=pos.y - 1, z=pos.z}
local nbelow = minetest.get_node(below).name
if nbelow == "air" then
minetest.set_node(below, {name=fname})
minetest.set_node_level(below, mylevel)
minetest.set_node(pos, {name="air"})
return
elseif (minetest.registered_nodes[nbelow].groups.bitumen_vapor or 0) > 0 then
-- fall through vapors
minetest.set_node(below, {name=fname})
minetest.set_node_level(below, mylevel)
minetest.set_node(pos, {name=nbelow})
elseif nbelow == fname then
local blevel = minetest.get_node_level(below)
if blevel < 64 then
local sum = mylevel + blevel
minetest.set_node_level(below, math.min(64, sum))
if sum > 64 then
mylevel = sum - 64
minetest.set_node_level(pos, mylevel)
-- keep flowing the liquid. this speeds up cascades
else
minetest.set_node(pos, {name="air"})
return
end
end
else -- check soaking
local rate = soak[nbelow]
if rate ~= nil then
local remains = mylevel - rate
if remains > 0 then
minetest.set_node_level(pos, remains)
else
minetest.set_node(pos, {name="air"})
end
if 1 == math.random(120 / mylevel) then
minetest.set_node(below, {name = "air"})
end
mylevel = remains
--return -- keep the fluid mechanics
end
end
local air_nodes = minetest.find_nodes_in_area(
{x=pos.x - 1, y=pos.y - 1, z=pos.z - 1},
{x=pos.x + 1, y=pos.y, z=pos.z + 1},
{"air", "group:bitumen_vapor"}
)
-- print("x: "..pos.x.." y: "..pos.y.." z: "..pos.z)
-- print("air list len ".. #air_nodes)
local off = math.random(#air_nodes)
for i = 1,#air_nodes do
--local theirlevel = minetest.get_node_level(fp)
local fp = air_nodes[((i + off) % #air_nodes) + 1]
if mylevel >= 2 then
local half = math.ceil(mylevel / 2)
minetest.set_node_level(pos, mylevel - half)
minetest.set_node(fp, {name= fname})
minetest.set_node_level(fp, half)
-- minetest.check_for_falling(fp)
return
end
end
local flow_nodes = minetest.find_nodes_in_area(
{x=pos.x - 1, y=pos.y , z=pos.z - 1},
{x=pos.x + 1, y=pos.y, z=pos.z + 1},
"group:"..gname
)
-- print("x: "..pos.x.." y: "..pos.y.." z: "..pos.z)
-- print("list len ".. #flow_nodes)
local off = math.random(#flow_nodes)
for i = 1,#flow_nodes do
local fp = flow_nodes[((i + off) % #flow_nodes) + 1]
local theirlevel = minetest.get_node_level(fp)
-- print("theirlevel "..theirlevel)
if mylevel - theirlevel >= 2 then
local diff = (mylevel - theirlevel)
local half = math.ceil(diff / 2)
minetest.set_node_level(pos, mylevel - half)
minetest.set_node_level(fp, theirlevel + (diff - half))
return
end
end
-- local n = minetest.get_node(fp);
-- -- check above to make sure it can get here
-- local na = minetest.get_node({x=fp.x, y=fp.y+1, z=fp.z})
--
-- -- print("name: " .. na.name .. " l: " ..g)
-- if na.name == "default:river_water_flowing" or na.name == "default:river_water_flowing" then
-- minetest.set_node(fp, {name=node.name})
-- minetest.set_node(pos, {name=n.name})
-- return
-- end
-- end
-- stagnation: this may not work
if mylevel == 64 then
--print("stagnating ".. pos.x .. ","..pos.y..","..pos.z)
minetest.set_node(pos, {name = full_fname})
end
end
})
end
bitumen.register_fluid = register_fluid
-- distillation products
register_fluid("bitumen", "mineral_spirits", {
desc = "Mineral Spirits",
groups = {flammable=1, petroleum=1, flash_ignite=3},
colorize = "^[colorize:white:160",
post_effect_color = {a = 103, r = 30, g = 76, b = 90},
vapor = true,
evap_interval = 10,
evap_chance = 10,
evap_rate = 5,
})
register_fluid("bitumen", "gasoline", {
desc = "Gasoline",
groups = {flammable=1, petroleum=1, flash_ignite=2},
colorize = "^[colorize:yellow:160",
post_effect_color = {a = 103, r = 30, g = 76, b = 90},
vapor = true,
evap_interval = 20,
evap_chance = 10,
evap_rate = 5,
})
register_fluid("bitumen", "diesel", {
desc = "Diesel",
groups = {flammable=1, petroleum=1},
colorize = "^[colorize:red:160",
post_effect_color = {a = 103, r = 230, g = 76, b = 90},
evap_interval = 20,
evap_chance = 20,
evap_rate = 2,
})
register_fluid("bitumen", "kerosene", {
desc = "Kerosene",
groups = {flammable=1, petroleum=1},
colorize = "^[colorize:white:100",
post_effect_color = {a = 103, r = 80, g = 76, b = 190},
vapor = true,
evap_interval = 20,
evap_chance = 20,
evap_rate = 8,
})
register_fluid("bitumen", "light_oil", {
desc = "Light Oil",
groups = {flammable=1, petroleum=1},
colorize = "^[colorize:brown:220",
post_effect_color = {a = 103, r = 80, g = 76, b = 90},
evap_chance = 0,
})
register_fluid("bitumen", "heavy_oil", {
desc = "Heavy Oil",
groups = {flammable=1, petroleum=1},
colorize = "^[colorize:brown:240",
post_effect_color = {a = 103, r = 80, g = 76, b = 90},
evap_chance = 0,
})
register_fluid("bitumen", "tar", {
desc = "Tar",
groups = {flammable=1, petroleum=1},
colorize = "^[colorize:black:210",
post_effect_color = {a = 103, r = 80, g = 76, b = 90},
evap_chance = 0,
})
-- oil itself
register_fluid("bitumen", "crude_oil", {
desc = "Crude Oil",
groups = {flammable=1, petroleum=1},
reflow_interval = 5,
reflow_chance = 2,
flow_interval = 3,
flow_chance = 2,
-- oil has its own special soaking code
no_default_soak = true,
colorize = "^[colorize:black:240",
post_effect_color = {a = 103, r = 80, g = 76, b = 90},
evap_chance = 0,
})
-- other
bitumen.register_fluid("bitumen", "drill_mud", {
desc = "Drilling Mud",
groups = {petroleum=1},
reflow_interval = 5,
reflow_chance = 1,
flow_interval = 1,
flow_chance = 1,
colorize = "^[colorize:brown:40",
post_effect_color = {a = 103, r = 80, g = 76, b = 90},
evap_chance = 0,
})
bitumen.register_fluid("bitumen", "drill_mud_dirty", {
desc = "Dirty Drilling Mud",
groups = {petroleum=1},
reflow_interval = 5,
reflow_chance = 1,
flow_interval = 1,
flow_chance = 1,
colorize = "^[colorize:brown:140",
post_effect_color = {a = 103, r = 80, g = 76, b = 90},
evap_chance = 0,
})
-- the default fire spreads too slow for gasoline...
minetest.register_abm({
nodenames = {"group:flash_ignite"},
neighbors = {
"fire:basic_flame",
"fire:permanent_flame",
"default:torch",
"default:lava_source",
"default:lava_flowing",
"tnt:gunpowder_burning",
},
interval = 5,
chance = 1,
action = function(pos, node, active_object_count, active_object_count_wider)
local airs = minetest.find_nodes_in_area(
{x=pos.x-2, y=pos.y-2, z=pos.z-2},
{x=pos.x+2, y=pos.y+2, z=pos.z+2},
{"air"}
)
if not airs then
return
end
local count = math.min(#airs, math.random(3,6))
for i = 1, count do
local ap = airs[math.random(#airs)]
minetest.set_node(ap, {name="fire:basic_flame"})
end
end
})
minetest.register_node("bitumen:mapgen_crude_oil", {
description = "mapgen crude oil placeholder. you should not see this. if you do, wait 60 seconds.",
tiles = { "default_copper_block.png" },
groups = { cracky = 3 },
})
-- build a shell around crude oil blobs
-- this keeps the oild from gushing into caves, both escaping and killing performance
minetest.register_lbm({
name = "bitumen:crude_shell_gen",
nodenames = {"bitumen:mapgen_crude_oil"},
run_at_every_load = true,
action = function(pos, node)
local airs = minetest.find_nodes_in_area(
vector.add(pos, {x=-1, y=-1, z=-1}),
vector.add(pos, {x=1, y=1, z=1}),
{"air"}
)
for _,p in ipairs(airs) do
minetest.set_node(p, {name="default:stone"})
end
minetest.set_node(pos, {name = "bitumen:crude_oil_full"})
minetest.set_node_level(pos, 64)
end
})
minetest.register_abm({
nodenames = {"bitumen:mapgen_crude_oil"},
interval = 60,
chance = 1,
action = function(pos, node)
local airs = minetest.find_nodes_in_area(
vector.add(pos, {x=-1, y=-1, z=-1}),
vector.add(pos, {x=1, y=1, z=1}),
{"air"}
)
for _,p in ipairs(airs) do
minetest.set_node(p, {name="default:stone"})
end
minetest.set_node(pos, {name = "bitumen:crude_oil_full"})
minetest.set_node_level(pos, 64)
end
})
--temp hack for dev
minetest.register_node("bitumen:crudesource", {
description = "thing",
tiles = { "default_copper_block.png" },
groups = { cracky = 3 },
})
minetest.register_abm({
nodenames = {"bitumen:crudesource"},
interval = 1,
chance = 1,
action = function(pos, node, active_object_count, active_object_count_wider)
pos.y = pos.y - 1
minetest.set_node(pos, {name = "bitumen:crude_oil"})
minetest.set_node_level(pos, 64)
end
})