]> git.lizzy.rs Git - Crafter.git/blobdiff - mods/utility/furnace.lua
remove server debug
[Crafter.git] / mods / utility / furnace.lua
index 875c373856d884ef55699f72457b8eeb4608d520..122db203660e58545a16f4f816c86bc2537430c2 100644 (file)
---[[
-Mechanic ideology
-
-spawn 3 entities - cook fuel output
-
-detect on x or z axis
-
-use recipe cook time
-
-then pass output to cooked entity
-
-when player hits entity then drop item towards player
-
-when cooking have fire and smoke on cooking item
-
-]]--
-
---furnace class
-minetest.register_craftitem("utility:nothing", {
-       description = "Nothing",
-       inventory_image = "wood.png",
-})
-
 local furnace = {}
---gap = 0.55
-local fuel_height = 0.75
-local cook_height = 1.3
-local output_height = 1.85
-
---furnace
-function furnace.get_hotbar_bg(x,y)
-       local out = ""
-       for i=0,7,1 do
-               out = out .."image["..x+i..","..y..";1,1;gui_furnace_arrow_bg.png]"
-       end
-       return(out)
+
+function furnace.get_furnace_active_formspec(fuel_percent, item_percent)
+       return "size[9,8.75]"..
+               "background[-0.19,-0.25;9.41,9.49;gui_hb_bg.png]"..
+               "listcolors[#8b8a89;#c9c3c6;#3e3d3e;#000000;#FFFFFF]"..
+               "list[context;src;2.75,0.5;1,1;]"..
+               "list[context;fuel;2.75,2.5;1,1;]"..
+               "image[2.75,1.5;1,1;default_furnace_fire_bg.png^[lowpart:"..
+               (fuel_percent)..":default_furnace_fire_fg.png]"..
+               "image[3.75,1.5;1,1;gui_furnace_arrow_bg.png^[lowpart:"..
+               (item_percent)..":gui_furnace_arrow_fg.png^[transformR270]"..
+               "list[context;dst;4.75,0.96;2,2;]"..
+               "list[current_player;main;0,4.5;9,1;]".. --hotbar
+               "list[current_player;main;0,6;9,3;9]".. --inventory
+               
+               "listring[context;dst]"..
+               "listring[current_player;main]"..
+               "listring[context;src]"..
+               "listring[current_player;main]"..
+               "listring[context;fuel]"..
+               "listring[current_player;main]"
+               --furnace.get_hotbar_bg(0, 4.25)
 end
 
-function furnace.get_inventory_drops(pos, inventory, drops)
-       local inv = minetest.get_meta(pos):get_inventory()
-       local n = #drops
-       for i = 1, inv:get_size(inventory) do
-               local stack = inv:get_stack(inventory, i)
-               if stack:get_count() > 0 then
-                       drops[n+1] = stack:to_table()
-                       n = n + 1
-               end
-       end
+function furnace.get_furnace_inactive_formspec()
+       return "size[9,8.75]"..
+               "background[-0.19,-0.25;9.41,9.49;gui_hb_bg.png]"..
+               "listcolors[#8b8a89;#c9c3c6;#3e3d3e;#000000;#FFFFFF]"..
+               "list[context;src;2.75,0.5;1,1;]"..
+               "list[context;fuel;2.75,2.5;1,1;]"..
+               "image[2.75,1.5;1,1;default_furnace_fire_bg.png]"..
+               "image[3.75,1.5;1,1;gui_furnace_arrow_bg.png^[transformR270]"..
+               "list[context;dst;4.75,0.96;2,2;]"..
+               "list[current_player;main;0,4.5;9,1;]"..
+               "list[current_player;main;0,6;9,3;9]"..
+               "listring[context;dst]"..
+               "listring[current_player;main]"..
+               "listring[context;src]"..
+               "listring[current_player;main]"..
+               "listring[context;fuel]"..
+               "listring[current_player;main]"
+               --furnace.get_hotbar_bg(0, 4.25)
 end
---local aftercooked
---cooked, aftercooked = minetest.get_craft_result({method = "cooking", width = 1, items = srclist})
---cookable = cooked.time ~= 0
+
 --
--- Node definitions
+-- Node callback functions that are the same for active and inactive furnace
 --
 
-local function furnace_setup(pos)
-       local obj = minetest.add_entity(vector.new(pos.x,pos.y+fuel_height,pos.z), "utility:fuel")
-       obj:get_luaentity().set_item(obj:get_luaentity(),"utility:nothing")
-       local obj = minetest.add_entity(vector.new(pos.x,pos.y+cook_height,pos.z), "utility:cook")
-       obj:get_luaentity().set_item(obj:get_luaentity(),"utility:nothing")
-       local obj = minetest.add_entity(vector.new(pos.x,pos.y+output_height,pos.z), "utility:output")
-       obj:get_luaentity().set_item(obj:get_luaentity(),"utility:nothing")
+--[[
+local function can_dig(pos, player)
+       local meta = minetest.get_meta(pos);
+       local inv = meta:get_inventory()
+       return inv:is_empty("fuel") and inv:is_empty("dst") and inv:is_empty("src")
 end
+]]--
 
-local function furnace_remove(pos)
-       for _,object in ipairs(minetest.get_objects_inside_radius(vector.new(pos.x,pos.y+fuel_height,pos.z), 0.1)) do
-               if not object:is_player() and object:get_luaentity() and object:get_luaentity().name == "utility:fuel" then
-                       local pos = object:getpos()
-                       local item = object:get_luaentity().itemstring
-                       if item ~= "utility:nothing" then
-                               local obj = minetest.add_item(pos,item)
-                               obj:get_luaentity().collection_timer = 2                                
-                       end
-                       object:remove()
-               end
-       end
-       for _,object in ipairs(minetest.get_objects_inside_radius(vector.new(pos.x,pos.y+cook_height,pos.z), 0.1)) do
-               if not object:is_player() and object:get_luaentity() and object:get_luaentity().name == "utility:cook" then
-                       local pos = object:getpos()
-                       local item = object:get_luaentity().itemstring
-                       if item ~= "utility:nothing" then
-                               local obj = minetest.add_item(pos,item)
-                               obj:get_luaentity().collection_timer = 2
-                       end
-                       object:remove()
-               end
+local function allow_metadata_inventory_put(pos, listname, index, stack, player)
+       if minetest.is_protected(pos, player:get_player_name()) then
+               return 0
        end
-       for _,object in ipairs(minetest.get_objects_inside_radius(vector.new(pos.x,pos.y+output_height,pos.z), 0.1)) do
-               if not object:is_player() and object:get_luaentity() and object:get_luaentity().name == "utility:output" then
-                       local pos = object:getpos()
-                       local item = object:get_luaentity().itemstring
-                       if item ~= "utility:nothing" then
-                               local obj = minetest.add_item(pos,item)
-                               obj:get_luaentity().collection_timer = 2
-                       end
-                       object:remove()
+       local meta = minetest.get_meta(pos)
+       local inv = meta:get_inventory()
+       if listname == "fuel" then
+               if minetest.get_craft_result({method="fuel", width=1, items={stack}}).time ~= 0 then
+                       --if inv:is_empty("src") then
+                       --      meta:set_string("infotext", "Furnace is empty")
+                       --end
+                       return stack:get_count()
+               else
+                       return 0
                end
+       elseif listname == "src" then
+               return stack:get_count()
+       elseif listname == "dst" then
+               return 0
        end
 end
 
-minetest.register_node("utility:furnace", {
-       description = "Furnace",
-       tiles = {
-               "furnace_top.png", "furnace_bottom.png",
-               "furnace_side.png", "furnace_side.png",
-               "furnace_side.png", "furnace_front.png"
-       },
-       paramtype2 = "facedir",
-       groups = {stone=2},
-       legacy_facedir_simple = true,
-       is_ground_content = false,
-       sounds = main.stoneSound(),
-       on_construct = function(pos)
-               furnace_setup(pos)
-       end,
-       on_destruct = function(pos)
-               furnace_remove(pos)
-       end,
-})
-
-minetest.register_craft({
-       output = "utility:furnace",
-       recipe = {
-               {"main:stone", "main:stone", "main:stone"},
-               {"main:stone", "",           "main:stone"},
-               {"main:stone", "main:stone", "main:stone"},
-       }
-})
-
---------------------------------------------------------------------------------------------------
---[[
-
-minetest.get_craft_result({method = "cooking", width = 1, items = srclist}) --check if cookable
-
-minetest.get_craft_result({method = "fuel", width = 1, items = fuellist}) --check if fuel
-
-space in between = 0.55
-
-]]--
-
-
---fuel entity
-minetest.register_entity("utility:fuel", {
-       initial_properties = {
-               hp_max = 1,
-               physical = true,
-               collide_with_objects = false,
-               collisionbox = {-0.3, -0.3, -0.3, 0.3, 0.3, 0.3},
-               visual = "wielditem",
-               visual_size = {x = 0.6, y = 0.6},
-               textures = {""},
-               spritediv = {x = 1, y = 1},
-               initial_sprite_basepos = {x = 0, y = 0},
-               is_visible = false,
-               pointable = true,
-       },
+local function allow_metadata_inventory_move(pos, from_list, from_index, to_list, to_index, count, player)
+       local meta = minetest.get_meta(pos)
+       local inv = meta:get_inventory()
+       local stack = inv:get_stack(from_list, from_index)
+       return allow_metadata_inventory_put(pos, to_list, to_index, stack, player)
+end
 
-       itemstring = "",
-       count = 0,
-       cooking = false,
-       cook_timer = false,
-       fuel_timer = 0,
-
-       set_item = function(self, item)
-               local stack = ItemStack(item or self.itemstring)
-               self.itemstring = stack:to_string()
-               --if self.itemstring == "" then
-                       -- item not yet known
-               --      return
-               --end
-               
-               local count = stack:get_count()
-               self.count = count
-
-               -- Backwards compatibility: old clients use the texture
-               -- to get the type of the item
-               local itemname = stack:is_known() and stack:get_name() or "unknown"
-
-               local max_count = stack:get_stack_max()
-               local size = 0.25
-               local coll_height = size * 0.75
-               local def = minetest.registered_nodes[itemname]
-               --local glow = def and def.light_source
-
-               self.object:set_properties({
-                       is_visible = true,
-                       visual = "wielditem",
-                       textures = {itemname},
-                       visual_size = {x = size, y = size},
-                       --collisionbox = {-size, -coll_height, -size,
-                       --      size, coll_height, size},
-                       selectionbox = {-size, -size, -size, size, size, size},
-                       automatic_rotate = math.pi * 0.5 * 0.2 / size,
-                       wield_item = self.itemstring,
-                       glow = glow,
-               })
-       end,
+local function allow_metadata_inventory_take(pos, listname, index, stack, player)
+       if minetest.is_protected(pos, player:get_player_name()) then
+               return 0
+       end
+       return stack:get_count()
+end
 
-       get_staticdata = function(self)
-               return minetest.serialize({
-                       itemstring = self.itemstring,
-                       count = self.count,                     
-               })
-       end,
+local function swap_node(pos, name)
+       local node = minetest.get_node(pos)
+       if node.name == name then
+               return
+       end
+       node.name = name
+       minetest.swap_node(pos, node)
+end
 
-       on_activate = function(self, staticdata, dtime_s)
-               if string.sub(staticdata, 1, string.len("return")) == "return" then
-                       local data = minetest.deserialize(staticdata)
-                       if data and type(data) == "table" then
-                               self.itemstring = data.itemstring
-                               self.count = data.count
-                       end
-               else
-                       self.itemstring = staticdata
-               end
-               self.object:set_armor_groups({immortal = 1})
-               self.object:set_velocity({x = 0, y = 0, z = 0})
-               self.object:set_acceleration({x = 0, y = 0, z = 0})
-               self:set_item()
-       end,
-       
-       on_rightclick = function(self, clicker)
-               
-               if not clicker or not clicker:is_player() then
-                       return
-               end
-               
-               local stack = clicker:get_wielded_item()
-               
-               local item = stack:get_name()
-               local count = stack:get_count()
-               if stack:get_name() == "utility:nothing" then
-                       count = 0
-               end
-               
-               --shoot out existing item
-               if self.itemstring ~= item.." "..count and self.itemstring ~= "utility:nothing" then
-                       local pos = self.object:getpos()
-                       local pos2 = clicker:getpos()
-                       pos2.y = pos2.y + 1.25
-                       local obj = minetest.add_item(pos,self.itemstring)
-                       local dir = vector.subtract(pos2,pos)
-                       vector.multiply(dir,5)
-                       
-                       if obj then
-                               obj:setvelocity(vector.new(dir.x,dir.y+3.5,dir.z))
-                               obj:get_luaentity().collection_timer = 2
-                       else
-                               print("ERROR FURNACE RELEASED NON ITEM")
-                       end
-               end
-               
-               if (item == "" or item == "hand:player") then
-                       self.set_item(self,"utility:nothing")
-                       self.object:set_nametag_attributes({
-                               color = "red",
-                               text = "",
-                       })
-                       return
-               end
-                               
-               self.set_item(self, item.." "..count)
-               
-               self.object:set_nametag_attributes({
-                       color = "red",
-                       text = minetest.registered_items[item].description.." "..count,
-               })
-               
-               stack = stack:clear()
-               clicker:set_wielded_item("")
-       end,
-       
-       on_punch = function(self, puncher, time_from_last_punch, tool_capabilities, dir)
-               if not puncher or not puncher:is_player() then
-                       return
-               end
-               
-               if self.itemstring == "utility:nothing" then
-                       return
-               end
-               
-               local pos = self.object:getpos()
-               local pos2 = puncher:getpos()
-               pos2.y = pos2.y + 1.25
-                               
-               local obj = minetest.add_item(pos,self.itemstring)
-               local dir = vector.subtract(pos2,pos)
-               vector.multiply(dir,5)
-               
-               self.set_item(self,"utility:nothing")
-               self.object:set_nametag_attributes({
-                       color = "red",
-                       text = "",
-               })
-               
-               if obj then
-                       obj:setvelocity(vector.new(dir.x,dir.y+3.5,dir.z))
-                       obj:get_luaentity().collection_timer = 2
-               else
-                       print("ERROR FURNACE RELEASED NON ITEM")
+local function furnace_node_timer(pos, elapsed)
+       --
+       -- Initialize metadata
+       --
+       local meta = minetest.get_meta(pos)
+       local fuel_time = meta:get_float("fuel_time") or 0
+       local src_time = meta:get_float("src_time") or 0
+       local fuel_totaltime = meta:get_float("fuel_totaltime") or 0
+
+       local inv = meta:get_inventory()
+       local srclist, fuellist
+       local dst_full = false
+
+       local cookable, cooked
+       local fuel
+
+       local update = true
+       while elapsed > 0 and update do
+               update = false
+
+               srclist = inv:get_list("src")
+               fuellist = inv:get_list("fuel")
+
+               --
+               -- Cooking
+               --
+
+               -- Check if we have cookable content
+               local aftercooked
+               cooked, aftercooked = minetest.get_craft_result({method = "cooking", width = 1, items = srclist})
+               cookable = cooked.time ~= 0
+
+               local el = math.min(elapsed, fuel_totaltime - fuel_time)
+               if cookable then -- fuel lasts long enough, adjust el to cooking duration
+                       el = math.min(el, cooked.time - src_time)
                end
-       end,
 
-       check_cook = function(self)
-               local pos = self.object:getpos()
-               --check the cook timer
-               for _,object in ipairs(minetest.get_objects_inside_radius(vector.new(pos.x,pos.y+0.55,pos.z), 0.1)) do
-                       if not object:is_player() and object:get_luaentity() and object:get_luaentity().name == "utility:cook" then
-                               local item = object:get_luaentity().itemstring
-                               return(minetest.get_craft_result({method = "cooking", width = 1, items = {ItemStack(item)}}).time)
-                       end
-               end
-       end,
-       
-       cook_item = function(self)
-               local pos = self.object:getpos()
-               for _,object in ipairs(minetest.get_objects_inside_radius(vector.new(pos.x,pos.y+0.55,pos.z), 0.1)) do
-                       if not object:is_player() and object:get_luaentity() and object:get_luaentity().name == "utility:cook" then
-                               local item = ItemStack(object:get_luaentity().itemstring)
-                               if not item then
-                                       return
-                               end
-                               local count = object:get_luaentity().count
-                               local output = minetest.get_craft_result({method = "cooking", width = 1, items = {ItemStack(item)}}).item
-                               local outputitem =  output:get_name()
-                               local outputcount = output:get_count()
-                               
-                               
-                               local itemname = item:get_name()
-                               
-                               count = count - 1
-                               
-                               object:get_luaentity().count = count
-                               
-                               local pos = self.object:getpos()
-                               
-                               --add to output
-                               for _,object2 in ipairs(minetest.get_objects_inside_radius(vector.new(pos.x,pos.y+1.10,pos.z), 0.1)) do
-                                       if not object2:is_player() and object2:get_luaentity() and object2:get_luaentity().name == "utility:output" then
-                                               local goal_item = ItemStack(object2:get_luaentity().itemstring)
-                                               local goal_item_name = goal_item:get_name()
-                                               local goal_item_count = goal_item:get_count()
-                                               
-                                               --cancel out if player took item
-                                               if outputitem == "" then
-                                                       return
-                                               end
-                                               
-                                               --add item to output or throw existing item out if not matched
-                                               if goal_item_name ~= outputitem and goal_item_name ~= "utility:nothing" then
-                                                       local pos2 = object2:get_pos()
-                                                       local obj = minetest.add_item(pos2,object2:get_luaentity().itemstring)
-                                                       local dir = vector.new(math.random(-3,3),math.random(3,6),math.random(-3,3))
-                                                       --dir = vector.multiply(dir,2)
-                                                                                                               
-                                                       if obj then
-                                                               obj:setvelocity(vector.new(dir.x,dir.y,dir.z))
-                                                               obj:get_luaentity().collection_timer = 2
-                                                       else
-                                                               print("ERROR FURNACE RELEASED NON ITEM")
-                                                       end
-                                                       object2:get_luaentity().count = 0
-                                               end
-                                               
-                                               object2:get_luaentity().count =  object2:get_luaentity().count + outputcount
-                                               object2:get_luaentity().set_item(object2:get_luaentity(), outputitem.." "..object2:get_luaentity().count)
-                                               object2:set_nametag_attributes({
-                                                       color = "blue",
-                                                       text = outputitem.." "..object2:get_luaentity().count,
-                                               })
-                                               
+               -- Check if we have enough fuel to burn
+               if fuel_time < fuel_totaltime then
+                       -- The furnace is currently active and has enough fuel
+                       fuel_time = fuel_time + el
+                       -- If there is a cookable item then check if it is ready yet
+                       if cookable then
+                               src_time = src_time + el
+                               if src_time >= cooked.time then
+                                       -- Place result in dst list if possible
+                                       if inv:room_for_item("dst", cooked.item) then
+                                               inv:add_item("dst", cooked.item)
+                                               inv:set_stack("src", 1, aftercooked.items[1])
+                                               src_time = src_time - cooked.time
+                                               update = true
+                                               local dir = vector.divide(minetest.facedir_to_dir(minetest.get_node(pos).param2),-1.95)
+                                               local newpos = vector.add(pos,dir)
+                                               minetest.throw_experience(newpos, 1)
+                                       else
+                                               dst_full = true
                                        end
-                               end
-                               
-                               --update count and nametag
-                               if object:get_luaentity().count == 0 then
-                                       object:get_luaentity().set_item(object:get_luaentity(), "utility:nothing")
-                                       object:set_nametag_attributes({
-                                               color = "blue",
-                                               text = "",
-                                       })
                                else
-                                       object:get_luaentity().set_item(object:get_luaentity(), itemname.." "..count)
-                                       object:set_nametag_attributes({
-                                               color = "blue",
-                                               text = itemname.." "..count,
-                                       })
+                                       -- Item could not be cooked: probably missing fuel
+                                       update = true
                                end
                        end
-               end
-       end,
-       
-       spawn_particles = function(self,time)
-               --print("time:"..time)
-               local pos = self.object:getpos()
-               minetest.add_particlespawner({
-                       amount = math.floor(100*time),
-                       time = time,
-                       minpos = vector.new(pos.x-0.3,pos.y-0.3,pos.z-0.3),
-                       maxpos = vector.new(pos.x+0.3,pos.y+0.3,pos.z+0.3),
-                       minvel = {x=0, y=0.2, z=0},
-                       maxvel = {x=0, y=0.7, z=0},
-                       minacc = {x=0, y=0, z=0},
-                       maxacc = {x=0, y=0, z=0},
-                       minexptime = 1.1,
-                       maxexptime = 1.5,
-                       minsize = 1,
-                       maxsize = 2,
-                       collisiondetection = false,
-                       vertical = true,
-                       texture = "flame.png",
-               })
-               
-               
-               minetest.add_particlespawner({
-                       amount = math.floor(50*time),
-                       time = time,
-                       minpos = vector.new(pos.x-0.3,pos.y+0.3,pos.z-0.3),
-                       maxpos = vector.new(pos.x+0.3,pos.y+0.6,pos.z+0.3),
-                       minvel = {x=0, y=0.2, z=0},
-                       maxvel = {x=0, y=0.7, z=0},
-                       minacc = {x=0, y=0, z=0},
-                       maxacc = {x=0, y=0, z=0},
-                       minexptime = 1.1,
-                       maxexptime = 1.5,
-                       minsize = 1,
-                       maxsize = 2,
-                       collisiondetection = false,
-                       vertical = false,
-                       texture = "smoke.png",
-               })
-       end,
-       
-       
-       
-       --check if item is in the input then cook if so
-       on_step = function(self, dtime)
-               if self.cooking == true then
-                       self.cooking_timer = self.cooking_timer - dtime
-                       if self.cooking_timer < 0 then
-                               self.cooking_timer = 0
-                               self.cook_item(self)
-                               self.cooking = false
-                       end                                     
-               end
-               
-               --check to start cooking countdown
-               if self.cooking == false then
-                       local stack = ItemStack(self.itemstring)
-                       local fuel = minetest.get_craft_result({method =  "fuel", width = 1, items = {stack}}).time
-                       if fuel ~= 0 then
-                               local cookie = self.check_cook(self)
-                               if cookie ~= 0 then
-                                       --print("starting timer")
-                                       self.spawn_particles(self,fuel)
-                                       self.cooking_timer = cookie
-                                       self.cooking = true
-                                       --set up the fuel timer
-                                       if self.fuel_timer == 0 then
-                                               self.fuel_timer = fuel
+               else
+                       -- Furnace ran out of fuel
+                       if cookable then
+                               -- We need to get new fuel
+                               local afterfuel
+                               fuel, afterfuel = minetest.get_craft_result({method = "fuel", width = 1, items = fuellist})
+
+                               if fuel.time == 0 then
+                                       -- No valid fuel in fuel list
+                                       fuel_totaltime = 0
+                                       src_time = 0
+                               else
+                                       -- Take fuel from fuel list
+                                       inv:set_stack("fuel", 1, afterfuel.items[1])
+                                       -- Put replacements in dst list or drop them on the furnace.
+                                       local replacements = fuel.replacements
+                                       if replacements[1] then
+                                               local leftover = inv:add_item("dst", replacements[1])
+                                               if not leftover:is_empty() then
+                                                       local above = vector.new(pos.x, pos.y + 1, pos.z)
+                                                       local drop_pos = minetest.find_node_near(above, 1, {"air"}) or above
+                                                       minetest.item_drop(replacements[1], nil, drop_pos)
+                                               end
                                        end
+                                       update = true
+                                       fuel_totaltime = fuel.time + (fuel_totaltime - fuel_time)
                                end
-                       end
-               end
-               
-               --deplete fuel
-               if self.fuel_timer >= 0 then
-                       self.fuel_timer = self.fuel_timer - dtime
-                       --print(self.fuel_timer)
-               elseif self.fuel_timer < 0 then
-                       if ItemStack(self.itemstring):get_name() == "utility:nothing" then
-                               return
-                       end
-                       if self.cooking == false then
-                               return
-                       end
-                       self.count = self.count - 1
-                       
-                       local count = self.count
-                       local itemname = ItemStack(self.itemstring):get_name()
-                       
-                       if self.count == 0 then
-                               self.set_item(self, "utility:nothing")
-                               self.object:set_nametag_attributes({
-                                       color = "red",
-                                       text = "",
-                               })
                        else
-                               self.set_item(self, itemname.." "..count)
-                               self.object:set_nametag_attributes({
-                                       color = "red",
-                                       text = itemname.." "..count,
-                               })
-                       end
-                       
-                       if self.count == 0 then 
-                               return
-                       end
-                       
-                       --reset timer
-                       if self.cooking == true then
-                               --print("resetting timer")
-                               local time = minetest.get_craft_result({method =  "fuel", width = 1, items = {ItemStack(self.itemstring)}}).time
-                               self.fuel_timer = time
+                               -- We don't need to get new fuel since there is no cookable item
+                               fuel_totaltime = 0
+                               src_time = 0
                        end
+                       fuel_time = 0
                end
-       end,    
-})
-
-----------------------------------------------------------------------------
---cook entity
-minetest.register_entity("utility:cook", {
-       initial_properties = {
-               hp_max = 1,
-               physical = true,
-               collide_with_objects = false,
-               collisionbox = {-0.3, -0.3, -0.3, 0.3, 0.3, 0.3},
-               visual = "wielditem",
-               visual_size = {x = 0.6, y = 0.6},
-               textures = {""},
-               spritediv = {x = 1, y = 1},
-               initial_sprite_basepos = {x = 0, y = 0},
-               is_visible = false,
-               pointable = true,
-       },
-
-       itemstring = "",
-       count = 0,
 
-       set_item = function(self, item)
-               local stack = ItemStack(item or self.itemstring)
-               self.itemstring = stack:to_string()
-               --if self.itemstring == "" then
-                       -- item not yet known
-               --      return
-               --end
-               
-               local count = stack:get_count()
-               if stack:get_name() == "utility:nothing" then
-                       count = 0
-               end
-               self.count = count
-
-               -- Backwards compatibility: old clients use the texture
-               -- to get the type of the item
-               local itemname = stack:is_known() and stack:get_name() or "unknown"
-
-               local max_count = stack:get_stack_max()
-               local size = 0.25
-               local coll_height = size * 0.75
-               local def = minetest.registered_nodes[itemname]
-               --local glow = def and def.light_source
-
-               self.object:set_properties({
-                       is_visible = true,
-                       visual = "wielditem",
-                       textures = {itemname},
-                       visual_size = {x = size, y = size},
-                       --collisionbox = {-size, -coll_height, -size,
-                       --      size, coll_height, size},
-                       selectionbox = {-size, -size, -size, size, size, size},
-                       automatic_rotate = math.pi * 0.5 * 0.2 / size,
-                       wield_item = self.itemstring,
-                       glow = glow,
-               })
-       end,
+               elapsed = elapsed - el
+       end
 
-       get_staticdata = function(self)
-               return minetest.serialize({
-                       itemstring = self.itemstring,
-                       count = self.count,                     
-               })
-       end,
+       if fuel and fuel_totaltime > fuel.time then
+               fuel_totaltime = fuel.time
+       end
+       if srclist and srclist[1]:is_empty() then
+               src_time = 0
+       end
 
-       on_activate = function(self, staticdata, dtime_s)
-               if string.sub(staticdata, 1, string.len("return")) == "return" then
-                       local data = minetest.deserialize(staticdata)
-                       if data and type(data) == "table" then
-                               self.itemstring = data.itemstring
-                               self.count = data.count
-                       end
+       --
+       -- Update formspec, infotext and node
+       --
+       local formspec
+       local item_state
+       local item_percent = 0
+       if cookable then
+               item_percent = math.floor(src_time / cooked.time * 100)
+               if dst_full then
+                       item_state = ("100% (output full)")
                else
-                       self.itemstring = staticdata
-               end
-               self.object:set_armor_groups({immortal = 1})
-               self.object:set_velocity({x = 0, y = 0, z = 0})
-               self.object:set_acceleration({x = 0, y = 0, z = 0})
-               self:set_item()
-       end,
-       
-       on_rightclick = function(self, clicker)
-               
-               if not clicker or not clicker:is_player() then
-                       return
+                       item_state = (item_percent)
                end
-               
-               local stack = clicker:get_wielded_item()
-               
-               local item = stack:get_name()
-               local count = stack:get_count()
-               
-               --shoot out existing item
-               if self.itemstring ~= item.." "..count and self.itemstring ~= "utility:nothing" then
-                       local pos = self.object:getpos()
-                       local pos2 = clicker:getpos()
-                       pos2.y = pos2.y + 1.25
-                       local obj = minetest.add_item(pos,self.itemstring)
-                       local dir = vector.subtract(pos2,pos)
-                       vector.multiply(dir,5)
-                       
-                       if obj then
-                               obj:setvelocity(vector.new(dir.x,dir.y+3.5,dir.z))
-                               obj:get_luaentity().collection_timer = 2
-                       else
-                               print("ERROR FURNACE RELEASED NON ITEM")
-                       end
-               end
-               
-               if (item == "" or item == "hand:player") then
-                       self.set_item(self,"utility:nothing")
-                       self.object:set_nametag_attributes({
-                               color = "blue",
-                               text = "",
-                       })
-                       return
-               end
-                               
-               self.set_item(self, item.." "..count)
-               
-               self.object:set_nametag_attributes({
-                       color = "blue",
-                       text = minetest.registered_items[item].description.." "..count,
-               })
-               
-               stack = stack:clear()
-               clicker:set_wielded_item("")
-       end,
-       
-       on_punch = function(self, puncher, time_from_last_punch, tool_capabilities, dir)
-               if not puncher or not puncher:is_player() then
-                       return
+       else
+               if srclist and not srclist[1]:is_empty() then
+                       item_state = ("Not cookable")
+               else
+                       item_state = ("Empty")
                end
-               
-               if self.itemstring == "utility:nothing" then
-                       return
+       end
+
+       local fuel_state = ("Empty")
+       local active = false
+       local result = false
+
+       if fuel_totaltime ~= 0 then
+               active = true
+               local fuel_percent = 100 - math.floor(fuel_time / fuel_totaltime * 100)
+               fuel_state = (fuel_percent)
+               formspec = furnace.get_furnace_active_formspec(fuel_percent, item_percent)
+               swap_node(pos, "utility:furnace_active")
+               -- make sure timer restarts automatically
+               result = true
+       else
+               if fuellist and not fuellist[1]:is_empty() then
+                       fuel_state = (0)
                end
-               
-               local pos = self.object:getpos()
-               local pos2 = puncher:getpos()
-               pos2.y = pos2.y + 1.25
-                               
-               local obj = minetest.add_item(pos,self.itemstring)
-               local dir = vector.subtract(pos2,pos)
-               vector.multiply(dir,5)
-               
-               self.set_item(self,"utility:nothing")
-               self.object:set_nametag_attributes({
-                       color = "blue",
-                       text = "",
-               })
-               
-               if obj then
-                       obj:setvelocity(vector.new(dir.x,dir.y+3.5,dir.z))
-                       obj:get_luaentity().collection_timer = 2
-               else
-                       print("ERROR FURNACE RELEASED NON ITEM")
+               formspec = furnace.get_furnace_inactive_formspec()
+               swap_node(pos, "utility:furnace")
+               -- stop timer on the inactive furnace
+               minetest.get_node_timer(pos):stop()
+       end
+
+
+       --[[
+       local infotext
+       if active then
+               infotext = ("Furnace active")
+       else
+               infotext = ("Furnace inactive")
+       end
+       infotext = infotext .. "\n" .. "Item:"..item_state.. "Fuel:"..fuel_state
+       ]]--
+       --
+       -- Set meta values
+       --
+       meta:set_float("fuel_totaltime", fuel_totaltime)
+       meta:set_float("fuel_time", fuel_time)
+       meta:set_float("src_time", src_time)
+       meta:set_string("formspec", formspec)
+       --meta:set_string("infotext", infotext)
+
+       return result
+end
+--throw all items in furnace out on destroy
+local function destroy_furnace(pos)
+       local meta = minetest.get_meta(pos)
+       local inv = meta:get_inventory()
+       local lists = inv:get_lists()
+       for listname,_ in pairs(lists) do
+               local size = inv:get_size(listname)
+               for i = 1,size do
+                       local stack = inv:get_stack(listname, i)
+                       minetest.add_item(pos, stack)
                end
-       end,
+       end
+end
 
+--
+-- Node definitions
+--
 
-       on_step = function(self, dtime)
-               --set glow if cooking
-               --local glow = def and def.light_source
-       end,
-})
-----------------------------------------------------------------------------
---ouput entity
-minetest.register_entity("utility:output", {
-       initial_properties = {
-               hp_max = 1,
-               physical = true,
-               collide_with_objects = false,
-               collisionbox = {-0.3, -0.3, -0.3, 0.3, 0.3, 0.3},
-               visual = "wielditem",
-               visual_size = {x = 0.6, y = 0.6},
-               textures = {""},
-               spritediv = {x = 1, y = 1},
-               initial_sprite_basepos = {x = 0, y = 0},
-               is_visible = false,
-               pointable = true,
+minetest.register_node("utility:furnace", {
+       description = ("Furnace"),
+       tiles = {
+               "furnace_top.png", "furnace_bottom.png",
+               "furnace_side.png", "furnace_side.png",
+               "furnace_side.png", "furnace_front.png"
        },
+       paramtype2 = "facedir",
+       groups = {stone=2},
+       legacy_facedir_simple = true,
+       is_ground_content = false,
+       sounds = main.stoneSound(),
 
-       itemstring = "",
-       count = 0,
+       --can_dig = can_dig,
 
-       set_item = function(self, item)
-               local stack = ItemStack(item or self.itemstring)
-               self.itemstring = stack:to_string()
-               --if self.itemstring == "" then
-                       -- item not yet known
-               --      return
-               --end
-               
-               local count = stack:get_count()
-               if stack:get_name() == "utility:nothing" then
-                       count = 0
-               end
-               self.count = count
-
-               -- Backwards compatibility: old clients use the texture
-               -- to get the type of the item
-               local itemname = stack:is_known() and stack:get_name() or "unknown"
-
-               local max_count = stack:get_stack_max()
-               local size = 0.25
-               local coll_height = size * 0.75
-               local def = minetest.registered_nodes[itemname]
-               --local glow = def and def.light_source
-
-               self.object:set_properties({
-                       is_visible = true,
-                       visual = "wielditem",
-                       textures = {itemname},
-                       visual_size = {x = size, y = size},
-                       --collisionbox = {-size, -coll_height, -size,
-                       --      size, coll_height, size},
-                       selectionbox = {-size, -size, -size, size, size, size},
-                       automatic_rotate = math.pi * 0.5 * 0.2 / size,
-                       wield_item = self.itemstring,
-                       glow = glow,
-               })
-       end,
+       on_timer = furnace_node_timer,
 
-       get_staticdata = function(self)
-               return minetest.serialize({
-                       itemstring = self.itemstring,
-                       count = self.count,                     
-               })
+       on_construct = function(pos)
+               local meta = minetest.get_meta(pos)
+               local inv = meta:get_inventory()
+               inv:set_size('src', 1)
+               inv:set_size('fuel', 1)
+               inv:set_size('dst', 4)
+               furnace_node_timer(pos, 0)
        end,
 
-       on_activate = function(self, staticdata, dtime_s)
-               if string.sub(staticdata, 1, string.len("return")) == "return" then
-                       local data = minetest.deserialize(staticdata)
-                       if data and type(data) == "table" then
-                               self.itemstring = data.itemstring
-                               self.count = data.count
-                       end
-               else
-                       self.itemstring = staticdata
+       on_metadata_inventory_move = function(pos)
+               local timer = minetest.get_node_timer(pos)
+               if timer:is_started() == false then
+                       timer:start(1.0)
                end
-               self.object:set_armor_groups({immortal = 1})
-               self.object:set_velocity({x = 0, y = 0, z = 0})
-               self.object:set_acceleration({x = 0, y = 0, z = 0})
-               self:set_item()
        end,
-               
-       on_punch = function(self, puncher, time_from_last_punch, tool_capabilities, dir)
-               if not puncher or not puncher:is_player() then
-                       return
-               end
-               
-               if self.itemstring == "utility:nothing" then
-                       return
-               end
-               
-               self.count = 0
-               
-               local pos = self.object:getpos()
-               local pos2 = puncher:getpos()
-               pos2.y = pos2.y + 1.25
-                               
-               local obj = minetest.add_item(pos,self.itemstring)
-               local dir = vector.subtract(pos2,pos)
-               vector.multiply(dir,5)
-               
-               self.set_item(self,"utility:nothing")
-               self.object:set_nametag_attributes({
-                       color = "blue",
-                       text = "",
-               })
-               
-               if obj then
-                       obj:setvelocity(vector.new(dir.x,dir.y+3.5,dir.z))
-                       obj:get_luaentity().collection_timer = 2
-               else
-                       print("ERROR FURNACE RELEASED NON ITEM")
+       on_metadata_inventory_put = function(pos)
+               -- start timer function, it will sort out whether furnace can burn or not.
+               local timer = minetest.get_node_timer(pos)
+               if timer:is_started() == false then
+                       timer:start(1.0)
                end
        end,
+       --[[
+       on_blast = function(pos)
+               local drops = {}
+               furnace.get_inventory_drops(pos, "src", drops)
+               furnace.get_inventory_drops(pos, "fuel", drops)
+               furnace.get_inventory_drops(pos, "dst", drops)
+               drops[#drops+1] = "utility:furnace"
+               minetest.remove_node(pos)
+               return drops
+       end,
+       ]]--
+       on_destruct = function(pos)
+               destroy_furnace(pos)
+       end,
+       allow_metadata_inventory_put = allow_metadata_inventory_put,
+       allow_metadata_inventory_move = allow_metadata_inventory_move,
+       allow_metadata_inventory_take = allow_metadata_inventory_take,
+})
 
+minetest.register_node("utility:furnace_active", {
+       description = ("Furnace"),
+       tiles = {
+               "furnace_top.png", "furnace_bottom.png",
+               "furnace_side.png", "furnace_side.png",
+               "furnace_side.png",
+               {
+                       image = "furnace_front_active.png",
+                       backface_culling = false,
+                       animation = {
+                               type = "vertical_frames",
+                               aspect_w = 16,
+                               aspect_h = 16,
+                               length = 1.5
+                       },
+               }
+       },
+       paramtype2 = "facedir",
+       light_source = 8,
+       drop = "utility:furnace",
+       groups = {stone=2},
+       legacy_facedir_simple = true,
+       is_ground_content = false,
+       sounds = main.stoneSound(),
+       on_timer = furnace_node_timer,
+
+       --can_dig = can_dig,
 
-       on_step = function(self, dtime)
-               --set glow if cooking
-               --local glow = def and def.light_source
+       allow_metadata_inventory_put = allow_metadata_inventory_put,
+       allow_metadata_inventory_move = allow_metadata_inventory_move,
+       allow_metadata_inventory_take = allow_metadata_inventory_take,
+       on_destruct = function(pos)
+               destroy_furnace(pos)
        end,
 })
 
-
 minetest.register_craft({
        output = "utility:furnace",
        recipe = {
                {"main:cobble", "main:cobble", "main:cobble"},
-               {"main:cobble", "", "main:cobble"},
+               {"main:cobble", "",            "main:cobble"},
                {"main:cobble", "main:cobble", "main:cobble"},
-       },
+       }
 })