Start working on the tinker's smeltery clone

This commit is contained in:
Evert Prants 2019-03-25 19:31:12 +02:00
parent 689e9fb437
commit 442d2fa977
Signed by: evert
GPG Key ID: 1688DA83D222D0B5
5 changed files with 477 additions and 220 deletions

186
multifurnace/faucet.lua Normal file
View File

@ -0,0 +1,186 @@
-- Faucet is a simple liquid transfer node
local FAUCET_PER_SECOND = 122
local function update_timer (pos)
local t = minetest.get_node_timer(pos)
if not t:is_started() then
t:start(1.0)
end
end
local function faucet_flow (pos, meta)
local angled = minetest.get_node(pos)
local back = vector.add(pos, minetest.facedir_to_dir(angled.param2))
local backnode = minetest.get_node(back)
local backreg = minetest.registered_nodes[backnode.name]
if not backreg.node_io_can_take_liquid or not backreg.node_io_can_take_liquid(back, backnode, "front")
or not backreg.node_io_take_liquid then
return false
end
local stack
if backreg.node_io_get_liquid_stack then
stack = backreg.node_io_get_liquid_stack(back, backnode, "front", 1)
end
if not stack or stack:is_empty() then
return false
end
return stack:get_name(), stack:get_count(), back
end
local function faucet_activate (pos)
local meta = minetest.get_meta(pos)
local source, amount, bhind = faucet_flow(pos, meta)
if meta:get_string("flowing") ~= "" then return false end
if not source or amount == 0 then return end
local e = minetest.add_entity(pos, "multifurnace:faucet_flow")
e:get_luaentity():set_faucet(pos)
e:get_luaentity():set_source(source)
meta:set_string("flowing", source)
meta:set_int("flowing_capacity", amount)
update_timer(pos)
end
local function faucet_timer (pos, elapsed)
local refresh = false
local meta = minetest.get_meta(pos)
local liquid = meta:get_string("flowing")
local source, amount, bhind = faucet_flow(pos, meta)
while true do
if liquid == "" then break end
if source ~= liquid or amount <= 0 then
liquid = ""
break
end
local bhindnode = minetest.get_node(bhind)
local bhindreg = minetest.registered_nodes[bhindnode.name]
local target = vector.subtract(pos, {x=0,y=1,z=0})
local tnode = minetest.get_node(target)
local treg = minetest.registered_nodes[tnode.name]
if not treg.node_io_can_put_liquid or not treg.node_io_can_put_liquid(target, tnode, "top")
or not treg.node_io_room_for_liquid then
liquid = ""
break
end
local flowcap = amount
if flowcap > FAUCET_PER_SECOND then
flowcap = FAUCET_PER_SECOND
end
local room = treg.node_io_room_for_liquid(target, tnode, "top", liquid, flowcap)
if room > 0 and treg.node_io_put_liquid then
local over = treg.node_io_put_liquid(target, tnode, "top", nil, liquid, room)
if treg.on_timer then
update_timer(target)
end
else
liquid = ""
break
end
bhindreg.node_io_take_liquid(bhind, bhindnode, "front", nil, source, room)
if bhindreg.on_timer then
update_timer(bhind)
end
refresh = true
break
end
meta:set_string("flowing", liquid)
return refresh
end
minetest.register_node("multifurnace:faucet", {
description = "Multifurnace Faucet",
tiles = {"metal_melter_heatbrick.png"},
groups = {cracky = 3, multifurnace_accessory = 1},
drawtype = "nodebox",
node_box = {
type = "fixed",
fixed = {
{-0.1875, -0.1875, 0.1250, 0.1875, -0.1250, 0.5000},
{-0.1875, -0.1250, 0.1250, -0.1250, 0.06250, 0.5000},
{0.1250, -0.1250, 0.1250, 0.1875, 0.06250, 0.5000}
}
},
paramtype = "light",
paramtype2 = "facedir",
is_ground_content = false,
on_rightclick = faucet_activate,
on_timer = faucet_timer,
})
-- Flow entity
minetest.register_entity("multifurnace:faucet_flow", {
initial_properties = {
physical = false,
collide_with_objects = false,
visual = "mesh",
mesh = "multifurnace_faucet_flow.obj",
visual_size = {x = 5, y = 5},
textures = {},
backface_culling = true,
pointable = false,
static_save = false,
},
faucet = nil,
source = "",
timer = 0,
set_faucet = function (self, faucet)
self.faucet = faucet
-- Set correct orientation in regards to the faucet
local node = minetest.get_node(faucet)
local orient = minetest.facedir_to_dir(node.param2)
orient = vector.multiply(orient, -1)
local angle = minetest.dir_to_yaw(orient)
self.object:set_yaw(angle)
end,
set_source = function (self, source)
self.source = source
-- Set appropriate fluid texture
local tiles = minetest.registered_nodes[source]
if not tiles.liquid_alternative_flowing then return end
local flowing = minetest.registered_nodes[tiles.liquid_alternative_flowing]
if not flowing.tiles or type(flowing.tiles[1]) ~= "string" then return end
self.object:set_properties({textures = {
flowing.tiles[1]
}})
end,
on_step = function (self, dt)
self.timer = self.timer + 1
-- Remove self when the faucet is destroyed or is no longer marked as flowing
if self.timer >= 10 then
local node = minetest.get_node(self.faucet)
if not node or node.name ~= "multifurnace:faucet" then
self.object:remove()
return
end
local meta = minetest.get_meta(self.faucet)
if meta:get_string("flowing") ~= self.source then
self.object:remove()
return
end
self.timer = 0
end
end
})

View File

@ -0,0 +1,224 @@
local furnaces = {}
local function update_timer (pos)
local t = minetest.get_node_timer(pos)
if not t:is_started() then
t:start(1.0)
end
end
-----------------------
-- Buffer operations --
-----------------------
-- List liquids in the controller
local function all_liquids (pos)
local meta = minetest.get_meta(pos)
local count = meta:get_int("buffers")
local stacks = {}
local total = 0
if count == 0 then return stacks, total end
for i = 1, count do
stacks[i] = ItemStack(meta:get_string("buffer" .. i))
total = total + stacks[i]:get_count()
end
return stacks, total
end
-- Set the bottom-most buffer
local function set_hot (pos, buf)
local meta = minetest.get_meta(pos)
local stacks, total = all_liquids(pos)
if not stacks[buf] or stacks[buf]:is_empty() then
return false
end
local current_one = stacks[1]
local new_one = stacks[buf]
meta:set_string("buffer1", new_one:to_string())
meta:set_string("buffer" .. buf, current_one:to_string())
return true
end
-- Reorganize the buffers, remove empty ones
local function clean_buffer_list (pos)
local meta = minetest.get_meta(pos)
local stacks, total = all_liquids(pos)
local new = {}
for i,v in pairs(stacks) do
if not v:is_empty() then
table.insert(new, v)
end
end
for i, v in pairs(new) do
meta:set_string("buffer" .. i, v:to_string())
end
meta:set_int("buffers", #new)
end
-- Returns how much of the first buffer fluid can be extracted
local function can_take_liquid (pos, want_mb)
local meta = minetest.get_meta(pos)
local stacks = all_liquids(pos)
local found = stacks[1]
if found and found:is_empty() then
clean_buffer_list(pos)
return "", 0
end
if not found then return "", 0 end
local count = 0
if found:get_count() < want_mb then
count = found:get_count()
else
count = want_mb
end
return found:get_name(), count
end
-- Take liquid from the first buffer
local function take_liquid (pos, want_mb)
local meta = minetest.get_meta(pos)
local stacks = all_liquids(pos)
local found = stacks[1]
local fluid,count = can_take_liquid(pos, want_mb)
if fluid == "" or count == 0 or fluid ~= found:get_name() then
return fluid, 0
end
found = ItemStack(fluid)
found:set_count(count)
meta:set_string("buffer1", found:to_string())
return fluid, count
end
-- Calculate furnace fluid capacity
local function total_capacity (pos)
return 8000 -- TODO
end
-- Can you fit this liquid inside the furnace
local function can_put_liquid (pos, liquid)
local stacks, storage = all_liquids(pos)
local total = total_capacity(pos)
local append = liquid:get_count()
if total == storage then
append = 0
elseif storage + liquid:get_count() > total then
append = total - storage
end
return append
end
-- Returns leftovers
local function put_liquid (pos, liquid)
local stacks, storage = all_liquids(pos)
local total = total_capacity(pos)
local append = can_put_liquid(pos, liquid)
local leftovers = liquid:get_count() - append
if append == 0 then
return leftovers
end
-- Find a buffer, if not available, create a new one
local buf = nil
for i,v in pairs(stacks) do
if v:get_name() == liquid:get_name() then
buf = i
break
end
end
if not buf then
buf = #stacks + 1
end
if stacks[buf] then
local st = stacks[buf]
local stc = st:get_count() + append
st:set_count(stc)
meta:set_string("buffer" .. buf, st:to_string())
else
liquid:set_count(append)
meta:set_string("buffer" .. buf, liquid:to_string())
end
return leftovers
end
--------------------------
-- Controller Operation --
--------------------------
-- Detect a structure based on controller
local function detect_structure (pos)
local node = minetest.get_node(pos)
local back = vector.add(pos, minetest.facedir_to_dir(node.param2))
local center = multifurnace.api.detect_center(back, 32)
-- TODO...
end
-- If pos is part of the structure, this will return a position
local function get_controller (pos)
-- body
end
local function controller_timer (pos, elapsed)
local refresh = false
local meta = minetest.get_meta(pos)
return refresh
end
-------------------
-- Registrations --
-------------------
minetest.register_node("multifurnace:controller", {
description = "Multifurnace Controller",
tiles = {
"metal_melter_heatbrick.png", "metal_melter_heatbrick.png", "metal_melter_heatbrick.png",
"metal_melter_heatbrick.png", "metal_melter_heatbrick.png", "metal_melter_heatbrick.png^multifurnace_controller_face.png",
},
groups = {cracky = 3, multifurnace = 1},
paramtype2 = "facedir",
is_ground_content = false,
on_timer = controller_timer,
on_rightclick = function (pos)
detect_structure(pos)
end
})
minetest.register_node("multifurnace:port", {
description = "Multifurnace Port",
tiles = {
"metal_melter_heatbrick.png", "metal_melter_heatbrick.png", "metal_melter_heatbrick.png",
"metal_melter_heatbrick.png", "metal_melter_heatbrick.png^multifurnace_intake_back.png",
"metal_melter_heatbrick.png^multifurnace_intake_face.png",
},
groups = {cracky = 3, multifurnace = 2},
paramtype2 = "facedir",
is_ground_content = false,
})

View File

@ -6,6 +6,9 @@ multifurnace = rawget(_G, "multifurnace") or {}
local modpath = minetest.get_modpath(minetest.get_current_modname())
multifurnace.modpath = modpath
dofile(modpath .. "/multi.lua")
dofile(modpath .. "/faucet.lua")
dofile(modpath .. "/furnace.lua")
dofile(modpath .. "/nodes.lua")
dofile(modpath .. "/crafting.lua")

64
multifurnace/multi.lua Normal file
View File

@ -0,0 +1,64 @@
multifurnace.api = {}
local function is_inner (pos)
local node = minetest.get_node_or_nil(pos)
return node and node.name == "air"
end
function multifurnace.api.detect_center (inside, limit)
-- "inside" is the position behind the controller, "inside the furnace"
-- adjust the x-position until the difference between the outer walls is at most 1
-- basically this means we center the position inside the furnace on the x axis.
local xd1 = 1 -- x-difference
local xd2 = 1
local zd1 = 1 -- z-difference
local zd2 = 1
for i = 1, limit do -- don't check farther than needed
-- expand the range on the x axis as long as one side has not met a wall
if is_inner(vector.add(inside, {x = -xd1, y = 0, z = 0})) then
xd1 = xd1 + 1
elseif is_inner(vector.add(inside, {x = xd2, y = 0, z = 0})) then
xd2 = xd2 + 1
end
-- if one side hit a wall and the other didn't we might have to re-center our x-position again
if xd1 - xd2 > 1 then
-- move x and offsets to the -x
xd1 = xd1 - 1
inside = vector.add(inside, {x = -1, y = 0, z = 0})
xd2 = xd2 + 1
end
-- or the right
if xd2 - xd1 > 1 then
xd2 = xd2 - 1
inside = vector.add(inside, {x = 1, y = 0, z = 0})
xd1 = xd1 + 1
end
-- also do exactly the same on the z axis
if is_inner(vector.add(inside, {x = 0, y = 0, z = -zd1})) then
zd1 = zd1 + 1
elseif is_inner(vector.add(inside, {x = 0, y = 0, z = zd2})) then
zd2 = zd2 + 1
end
if zd1 - zd2 > 1 then
-- move x and offsets to the -x
zd1 = zd1 - 1
inside = vector.add(inside, {x = 0, y = 0, z = -1})
zd2 = zd2 + 1
end
-- or the right
if zd2 - zd1 > 1 then
zd2 = zd2 - 1
inside = vector.add(inside, {x = 0, y = 0, z = 1})
zd1 = zd1 + 1
end
end
return inside
end

View File

@ -1,224 +1,4 @@
local FAUCET_PER_SECOND = 122
-- Node funtions
local function update_timer (pos)
local t = minetest.get_node_timer(pos)
if not t:is_started() then
t:start(1.0)
end
end
local function controller_timer (pos, elapsed)
local refresh = false
local meta = minetest.get_meta(pos)
return refresh
end
local function faucet_flow (pos, meta)
local angled = minetest.get_node(pos)
local back = vector.add(pos, minetest.facedir_to_dir(angled.param2))
local backnode = minetest.get_node(back)
local backreg = minetest.registered_nodes[backnode.name]
if not backreg.node_io_can_take_liquid or not backreg.node_io_can_take_liquid(back, backnode, "front")
or not backreg.node_io_take_liquid then
return false
end
local stack
if backreg.node_io_get_liquid_stack then
stack = backreg.node_io_get_liquid_stack(back, backnode, "front", 1)
end
if not stack or stack:is_empty() then
return false
end
return stack:get_name(), stack:get_count(), back
end
local function faucet_activate (pos)
local meta = minetest.get_meta(pos)
local source, amount, bhind = faucet_flow(pos, meta)
if meta:get_string("flowing") ~= "" then return false end
if not source or amount == 0 then return end
local e = minetest.add_entity(pos, "multifurnace:faucet_flow")
e:get_luaentity():set_faucet(pos)
e:get_luaentity():set_source(source)
meta:set_string("flowing", source)
meta:set_int("flowing_capacity", amount)
update_timer(pos)
end
local function faucet_timer (pos, elapsed)
local refresh = false
local meta = minetest.get_meta(pos)
local liquid = meta:get_string("flowing")
local source, amount, bhind = faucet_flow(pos, meta)
while true do
if liquid == "" then break end
if source ~= liquid or amount <= 0 then
liquid = ""
break
end
local bhindnode = minetest.get_node(bhind)
local bhindreg = minetest.registered_nodes[bhindnode.name]
local target = vector.subtract(pos, {x=0,y=1,z=0})
local tnode = minetest.get_node(target)
local treg = minetest.registered_nodes[tnode.name]
if not treg.node_io_can_put_liquid or not treg.node_io_can_put_liquid(target, tnode, "top")
or not treg.node_io_room_for_liquid then
liquid = ""
break
end
local flowcap = amount
if flowcap > FAUCET_PER_SECOND then
flowcap = FAUCET_PER_SECOND
end
local room = treg.node_io_room_for_liquid(target, tnode, "top", liquid, flowcap)
if room > 0 and treg.node_io_put_liquid then
local over = treg.node_io_put_liquid(target, tnode, "top", nil, liquid, room)
if treg.on_timer then
update_timer(target)
end
else
liquid = ""
break
end
bhindreg.node_io_take_liquid(bhind, bhindnode, "front", nil, source, room)
if bhindreg.on_timer then
update_timer(bhind)
end
refresh = true
break
end
meta:set_string("flowing", liquid)
return refresh
end
-- Node definitions
minetest.override_item("metal_melter:heated_bricks", {
groups = {cracky = 3, multifurnace = 1},
})
minetest.register_node("multifurnace:controller", {
description = "Multifurnace Controller",
tiles = {
"metal_melter_heatbrick.png", "metal_melter_heatbrick.png", "metal_melter_heatbrick.png",
"metal_melter_heatbrick.png", "metal_melter_heatbrick.png", "metal_melter_heatbrick.png^multifurnace_controller_face.png",
},
groups = {cracky = 3, multifurnace = 1},
paramtype2 = "facedir",
is_ground_content = false,
on_timer = controller_timer,
})
minetest.register_node("multifurnace:port", {
description = "Multifurnace Port",
tiles = {
"metal_melter_heatbrick.png", "metal_melter_heatbrick.png", "metal_melter_heatbrick.png",
"metal_melter_heatbrick.png", "metal_melter_heatbrick.png^multifurnace_intake_back.png",
"metal_melter_heatbrick.png^multifurnace_intake_face.png",
},
groups = {cracky = 3, multifurnace = 1},
paramtype2 = "facedir",
is_ground_content = false,
})
minetest.register_node("multifurnace:faucet", {
description = "Multifurnace Faucet",
tiles = {"metal_melter_heatbrick.png"},
groups = {cracky = 3, multifurnace_accessory = 1},
drawtype = "nodebox",
node_box = {
type = "fixed",
fixed = {
{-0.1875, -0.1875, 0.1250, 0.1875, -0.1250, 0.5000},
{-0.1875, -0.1250, 0.1250, -0.1250, 0.06250, 0.5000},
{0.1250, -0.1250, 0.1250, 0.1875, 0.06250, 0.5000}
}
},
paramtype = "light",
paramtype2 = "facedir",
is_ground_content = false,
on_rightclick = faucet_activate,
on_timer = faucet_timer,
})
-- Entity definitions
minetest.register_entity("multifurnace:faucet_flow", {
initial_properties = {
physical = false,
collide_with_objects = false,
visual = "mesh",
mesh = "multifurnace_faucet_flow.obj",
visual_size = {x = 5, y = 5},
textures = {},
backface_culling = true,
pointable = false,
static_save = false,
},
faucet = nil,
source = "",
timer = 0,
set_faucet = function (self, faucet)
self.faucet = faucet
-- Set correct orientation in regards to the faucet
local node = minetest.get_node(faucet)
local orient = minetest.facedir_to_dir(node.param2)
orient = vector.multiply(orient, -1)
local angle = minetest.dir_to_yaw(orient)
self.object:set_yaw(angle)
end,
set_source = function (self, source)
self.source = source
-- Set appropriate fluid texture
local tiles = minetest.registered_nodes[source]
if not tiles.liquid_alternative_flowing then return end
local flowing = minetest.registered_nodes[tiles.liquid_alternative_flowing]
if not flowing.tiles or type(flowing.tiles[1]) ~= "string" then return end
self.object:set_properties({textures = {
flowing.tiles[1]
}})
end,
on_step = function (self, dt)
self.timer = self.timer + 1
-- Remove self when the faucet is destroyed or is no longer marked as flowing
if self.timer >= 10 then
local node = minetest.get_node(self.faucet)
if not node or node.name ~= "multifurnace:faucet" then
self.object:remove()
return
end
local meta = minetest.get_meta(self.faucet)
if meta:get_string("flowing") ~= self.source then
self.object:remove()
return
end
self.timer = 0
end
end
})