melterns/fluidity/tanks.lua
2018-06-18 21:26:56 +03:00

326 lines
9.6 KiB
Lua

-- Register tanks for each fluid
fluidity.bucket_cache = {}
fluidity.tanks = {}
-- Get fluid source block name for bucket item.
function fluidity.get_fluid_for_bucket(itemname)
for i,v in pairs(fluidity.bucket_cache) do
if v == itemname then
return i
end
end
end
-- Get bucket item name for fluid source block.
function fluidity.get_bucket_for_fluid(source)
return fluidity.bucket_cache[source]
end
-- Ensure that this fluid node exists.
function fluidity.get_fluid_node(name)
return minetest.registered_nodes[name]
end
-- Get a nodedef field.
local function get_nodedef_field(nodename, fieldname)
if not minetest.registered_nodes[nodename] then
return nil
end
return minetest.registered_nodes[nodename][fieldname]
end
-- Ensure that the node is a tank.
function fluidity.tanks.get_is_tank(node)
return minetest.get_item_group(node, "fluidity_tank") > 0
end
-- Ensure that the node is an empty tank.
function fluidity.tanks.get_is_empty_tank(node)
return minetest.get_item_group(node, "fluidity_tank_empty") > 0
end
-- Get tank data at position.
-- Returns fluid name, fluid level, capacity, base tank name and the mod it was added from.
-- Base tank name and mod name are used to construct different variants of this tank type.
function fluidity.tanks.get_tank_at(pos)
local meta = minetest.get_meta(pos)
local node = minetest.get_node(pos)
if not fluidity.tanks.get_is_tank(node.name) then return nil end
local ffluid = get_nodedef_field(node.name, "fluidity_fluid")
local fcapacity = get_nodedef_field(node.name, "_capacity")
local fbasetank = get_nodedef_field(node.name, "_dataname")
local fmod = get_nodedef_field(node.name, "_mod")
local fluidcount = meta:get_int("fluid")
return ffluid, fluidcount, fcapacity, fbasetank, fmod
end
-- Check to see if a fluid can go in the tank and pos.
function fluidity.tanks.can_fluid_go_in_tank(pos, fluid)
local fluid_name, count, capacity, base_tank, mod = fluidity.tanks.get_tank_at(pos)
if not fluid_name then return true end
if fluid_name ~= fluid then return false end
if count == capacity then return false end
local source_node = fluidity.get_fluid_node(fluid)
local fluid_desc = fluidity.fluid_name(source_node.description)
local shorthand_name = fluidity.fluid_short(fluid_desc)
if not minetest.registered_nodes[mod..":"..base_tank.."_"..shorthand_name] then return false end
return true
end
-- Fill the tank at pos with fluid.
-- Overfilling means it will return an integer as the second variable that shows the amount over the capacity.
function fluidity.tanks.fill_tank_at(pos, fluid, amount, overfill)
local fluid_name, count, capacity, base_tank, mod = fluidity.tanks.get_tank_at(pos)
if not fluid_name == fluid and fluid_name ~= nil then return nil end
local node = minetest.get_node(pos)
local meta = minetest.get_meta(pos)
local node_name = mod..":"..base_tank
local remainder = 0
if count + amount > capacity then
if overfill then
remainder = capacity - count
count = capacity
else
return nil
end
else
count = count + amount
end
local source_node = fluidity.get_fluid_node(fluid)
local fluid_desc = fluidity.fluid_name(source_node.description)
local shorthand_name = fluidity.fluid_short(fluid_desc)
node_name = mod..":"..base_tank.."_"..shorthand_name
if not minetest.registered_nodes[node_name] then return nil end
meta:set_int("fluid", count)
meta:set_string("infotext", "Tank of "..fluid_desc.."("..count.."/"..capacity.." mB)")
local param2 = math.min((count/capacity)*63, 63)
minetest.swap_node(pos, {name=node_name,param1=node.param1,param2=param2})
return fluid, remainder
end
-- Take some fluid from the tank at pos.
-- Underfill returns an integer as the second variable indicating level below zero.
function fluidity.tanks.take_from_tank_at(pos, amount, underfill)
local fluid_name, count, capacity, base_tank, mod = fluidity.tanks.get_tank_at(pos)
if not fluid_name then return nil end
local node = minetest.get_node(pos)
local meta = minetest.get_meta(pos)
local node_name = mod..":"..base_tank
local fluid = fluid_name
local leftover = 0
if count - amount < 0 then
if underfill then
leftover = (count - amount) * -1
count = 0
else
return nil
end
else
count = count - amount
end
if count == 0 then
fluid = nil
end
meta:set_int("fluid", count)
if fluid then
local source_node = fluidity.get_fluid_node(fluid)
local fluid_desc = fluidity.fluid_name(source_node.description)
local shorthand_name = fluidity.fluid_short(fluid_desc)
node_name = mod..":"..base_tank.."_"..shorthand_name
meta:set_string("infotext", "Tank of "..fluid_desc.."("..count.."/"..capacity.." mB)")
else
meta:set_string("infotext", "Empty Tank")
end
local param2 = math.min((count/capacity)*63, 63)
minetest.swap_node(pos, {name=node_name,param1=node.param1,param2=param2})
return fluid_name, leftover
end
local function bucket_fill(pos, node, clicker, itemstack, pointed_thing)
local stackname = itemstack:get_name()
local stack = "bucket:bucket_empty"
if not stackname:find("bucket") then
return itemstack
end
if stackname == "bucket:bucket_empty" then
if fluidity.tanks.get_is_empty_tank(node.name) then
return itemstack
end
local fluid = fluidity.tanks.take_from_tank_at(pos, 1000)
if not fluid then
return itemstack
end
stack = fluidity.get_bucket_for_fluid(fluid)
else
local srcnode = fluidity.get_fluid_for_bucket(stackname)
if not fluidity.tanks.can_fluid_go_in_tank(pos, srcnode) then
return itemstack
end
local fluid = fluidity.tanks.fill_tank_at(pos, srcnode, 1000)
if fluid == nil then
return itemstack
end
end
return ItemStack(stack)
end
-- Preserve fluid count in the item stack dropped
local function preserve_metadata(pos, oldnode, oldmeta, drops)
local fluid_name, count, capacity = fluidity.tanks.get_tank_at(pos)
local meta = minetest.get_meta(pos)
local fluid_cnt = meta:get_int("fluid")
local nodedesc = get_nodedef_field(oldnode.name, "description")
for i,stack in pairs(drops) do
local stack_meta = stack:get_meta()
stack_meta:set_int("fluid", fluid_cnt)
stack_meta:set_string("description", nodedesc.."\nContains "..count.."/"..capacity.." mB")
drops[i] = stack
end
return drops
end
-- Retrieve fluid count from itemstack when placed
local function after_place_node(pos, placer, itemstack, pointed_thing)
local item_meta = itemstack:get_meta()
local fluid_cnt = item_meta:get_int("fluid")
local fluid = get_nodedef_field(itemstack:get_name(), "fluidity_fluid")
if fluid_cnt then
-- Fill the tank to the count specified in item meta, don't care about overfill or what it returns.
fluidity.tanks.fill_tank_at(pos, fluid, fluid_cnt, true)
end
return false
end
-- Register a tank for a specific fluid
local function register_tankfluid(data)
local source_node = fluidity.get_fluid_node(data.source_name)
local fluid = fluidity.fluid_name(source_node.description)
local internal = fluidity.fluid_short(fluid)
local nodename = data.mod_name..":"..data.tank_name.."_"..internal
if minetest.registered_nodes[nodename] then
return
end
minetest.register_node(nodename, {
description = data.tank_description.." ("..fluid..")",
drawtype = "glasslike_framed_optional",
paramtype = "light",
paramtype2 = "glasslikeliquidlevel",
fluidity_fluid = data.source_name,
place_param2 = 0,
special_tiles = source_node.tiles,
is_ground_content = false,
sunlight_propagates = true,
on_rightclick = bucket_fill,
preserve_metadata = preserve_metadata,
after_place_node = after_place_node,
_mod = data.mod_name,
_dataname = data.tank_name,
_capacity = data.capacity,
groups = {cracky = 1, not_in_creative_inventory = 1, oddly_breakable_by_hand = 3, fluidity_tank = 1},
tiles = data.tiles
})
end
-- Register a new tank
function fluidity.tanks.register_fluid_tank(data)
local modname = data.mod_name or minetest.get_current_modname()
local tankname = data.tank_name or 'fluid_tank'
local tankdesc = data.tank_description or 'Fluid Tank'
local tiles = data.tiles or {"default_glass.png", "default_glass_detail.png"}
local capacity = data.capacity or 64000
local tanknode = modname..":"..tankname
if not minetest.registered_nodes[tanknode] then
minetest.register_node(tanknode, {
description = tankdesc,
drawtype = "glasslike_framed_optional",
paramtype = "light",
paramtype2 = "glasslikeliquidlevel",
is_ground_content = false,
sunlight_propagates = true,
fluidity_fluid = nil,
on_construct = function ( pos )
local meta = minetest.get_meta(pos)
meta:set_int("fluid", 0)
meta:set_string("infotext", "Empty "..tankdesc)
end,
on_rightclick = bucket_fill,
_mod = modname,
_dataname = tankname,
_capacity = capacity,
groups = {cracky = 1, oddly_breakable_by_hand = 3, fluidity_tank = 1, fluid_tank_empty = 1},
tiles = tiles
})
end
if data.fluids then
-- This tank only uses certain fluids
for _, v in pairs(data.fluids) do
register_tankfluid({
mod_name = modname,
tank_name = tankname,
tank_description = tankdesc,
tiles = tiles,
capacity = capacity,
source_name = v
})
end
else
-- Get all fluids and buckets and cache them
for i, v in pairs(bucket.liquids) do
if (i:find("source") ~= nil) then
-- Cache bucket
fluidity.bucket_cache[v["source"]] = v.itemname
-- Add tank
register_tankfluid({
mod_name = modname,
tank_name = tankname,
tank_description = tankdesc,
tiles = tiles,
capacity = capacity,
source_name = v["source"]
})
end
end
end
end