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 })