5 function furnace.get_hotbar_bg(x,y)
8 out = out .."image["..x+i..","..y..";1,1;gui_furnace_arrow_bg.png]"
13 function furnace.get_inventory_drops(pos, inventory, drops)
14 local inv = minetest.get_meta(pos):get_inventory()
16 for i = 1, inv:get_size(inventory) do
17 local stack = inv:get_stack(inventory, i)
18 if stack:get_count() > 0 then
19 drops[n+1] = stack:to_table()
25 function furnace.get_furnace_active_formspec(fuel_percent, item_percent)
26 return "size[8,8.5]"..
27 "list[context;src;2.75,0.5;1,1;]"..
28 "list[context;fuel;2.75,2.5;1,1;]"..
29 "image[2.75,1.5;1,1;default_furnace_fire_bg.png^[lowpart:"..
30 (fuel_percent)..":default_furnace_fire_fg.png]"..
31 "image[3.75,1.5;1,1;gui_furnace_arrow_bg.png^[lowpart:"..
32 (item_percent)..":gui_furnace_arrow_fg.png^[transformR270]"..
33 "list[context;dst;4.75,0.96;2,2;]"..
34 "list[current_player;main;0,4.25;8,1;]"..
35 "list[current_player;main;0,5.5;8,3;8]"..
36 "listring[context;dst]"..
37 "listring[current_player;main]"..
38 "listring[context;src]"..
39 "listring[current_player;main]"..
40 "listring[context;fuel]"..
41 "listring[current_player;main]"..
42 furnace.get_hotbar_bg(0, 4.25)
45 function furnace.get_furnace_inactive_formspec()
46 return "size[8,8.5]"..
47 "list[context;src;2.75,0.5;1,1;]"..
48 "list[context;fuel;2.75,2.5;1,1;]"..
49 "image[2.75,1.5;1,1;default_furnace_fire_bg.png]"..
50 "image[3.75,1.5;1,1;gui_furnace_arrow_bg.png^[transformR270]"..
51 "list[context;dst;4.75,0.96;2,2;]"..
52 "list[current_player;main;0,4.25;8,1;]"..
53 "list[current_player;main;0,5.5;8,3;8]"..
54 "listring[context;dst]"..
55 "listring[current_player;main]"..
56 "listring[context;src]"..
57 "listring[current_player;main]"..
58 "listring[context;fuel]"..
59 "listring[current_player;main]"..
60 furnace.get_hotbar_bg(0, 4.25)
64 -- Node callback functions that are the same for active and inactive furnace
67 local function can_dig(pos, player)
68 local meta = minetest.get_meta(pos);
69 local inv = meta:get_inventory()
70 return inv:is_empty("fuel") and inv:is_empty("dst") and inv:is_empty("src")
73 local function allow_metadata_inventory_put(pos, listname, index, stack, player)
74 if minetest.is_protected(pos, player:get_player_name()) then
77 local meta = minetest.get_meta(pos)
78 local inv = meta:get_inventory()
79 if listname == "fuel" then
80 if minetest.get_craft_result({method="fuel", width=1, items={stack}}).time ~= 0 then
81 if inv:is_empty("src") then
82 --meta:set_string("infotext", "Furnace is empty")
84 return stack:get_count()
88 elseif listname == "src" then
89 return stack:get_count()
90 elseif listname == "dst" then
95 local function allow_metadata_inventory_move(pos, from_list, from_index, to_list, to_index, count, player)
96 local meta = minetest.get_meta(pos)
97 local inv = meta:get_inventory()
98 local stack = inv:get_stack(from_list, from_index)
99 return allow_metadata_inventory_put(pos, to_list, to_index, stack, player)
102 local function allow_metadata_inventory_take(pos, listname, index, stack, player)
103 if minetest.is_protected(pos, player:get_player_name()) then
106 return stack:get_count()
109 local function swap_node(pos, name)
110 local node = minetest.get_node(pos)
111 if node.name == name then
115 minetest.swap_node(pos, node)
118 local function furnace_node_timer(pos, elapsed)
120 -- Initialize metadata
122 local meta = minetest.get_meta(pos)
123 local fuel_time = meta:get_float("fuel_time") or 0
124 local src_time = meta:get_float("src_time") or 0
125 local fuel_totaltime = meta:get_float("fuel_totaltime") or 0
127 local inv = meta:get_inventory()
128 local srclist, fuellist
129 local dst_full = false
131 local cookable, cooked
135 while elapsed > 0 and update do
138 srclist = inv:get_list("src")
139 fuellist = inv:get_list("fuel")
145 -- Check if we have cookable content
147 cooked, aftercooked = minetest.get_craft_result({method = "cooking", width = 1, items = srclist})
148 cookable = cooked.time ~= 0
150 local el = math.min(elapsed, fuel_totaltime - fuel_time)
151 if cookable then -- fuel lasts long enough, adjust el to cooking duration
152 el = math.min(el, cooked.time - src_time)
155 -- Check if we have enough fuel to burn
156 if fuel_time < fuel_totaltime then
157 -- The furnace is currently active and has enough fuel
158 fuel_time = fuel_time + el
159 -- If there is a cookable item then check if it is ready yet
161 src_time = src_time + el
162 if src_time >= cooked.time then
163 -- Place result in dst list if possible
164 if inv:room_for_item("dst", cooked.item) then
165 inv:add_item("dst", cooked.item)
166 inv:set_stack("src", 1, aftercooked.items[1])
167 src_time = src_time - cooked.time
173 -- Item could not be cooked: probably missing fuel
178 -- Furnace ran out of fuel
180 -- We need to get new fuel
182 fuel, afterfuel = minetest.get_craft_result({method = "fuel", width = 1, items = fuellist})
184 if fuel.time == 0 then
185 -- No valid fuel in fuel list
189 -- Take fuel from fuel list
190 inv:set_stack("fuel", 1, afterfuel.items[1])
191 -- Put replacements in dst list or drop them on the furnace.
192 local replacements = fuel.replacements
193 if replacements[1] then
194 local leftover = inv:add_item("dst", replacements[1])
195 if not leftover:is_empty() then
196 local above = vector.new(pos.x, pos.y + 1, pos.z)
197 local drop_pos = minetest.find_node_near(above, 1, {"air"}) or above
198 minetest.item_drop(replacements[1], nil, drop_pos)
202 fuel_totaltime = fuel.time + (fuel_totaltime - fuel_time)
205 -- We don't need to get new fuel since there is no cookable item
212 elapsed = elapsed - el
215 if fuel and fuel_totaltime > fuel.time then
216 fuel_totaltime = fuel.time
218 if srclist and srclist[1]:is_empty() then
223 -- Update formspec, infotext and node
227 local item_percent = 0
229 item_percent = math.floor(src_time / cooked.time * 100)
231 item_state = "100% (output full)"
233 item_state = "@1%", item_percent
236 if srclist and not srclist[1]:is_empty() then
237 item_state = "Not cookable"
243 local fuel_state = "Empty"
247 if fuel_totaltime ~= 0 then
249 local fuel_percent = 100 - math.floor(fuel_time / fuel_totaltime * 100)
250 fuel_state = "@1%", fuel_percent
251 formspec = furnace.get_furnace_active_formspec(fuel_percent, item_percent)
252 swap_node(pos, "utility:furnace_active")
253 -- make sure timer restarts automatically
256 if fuellist and not fuellist[1]:is_empty() then
257 fuel_state = "@1%", 0
259 formspec = furnace.get_furnace_inactive_formspec()
260 swap_node(pos, "utility:furnace")
261 -- stop timer on the inactive furnace
262 minetest.get_node_timer(pos):stop()
268 infotext = "Furnace active"
270 infotext = "Furnace inactive"
272 infotext = infotext .. "\n" .. "(Item: @1; Fuel: @2)", item_state, fuel_state
277 meta:set_float("fuel_totaltime", fuel_totaltime)
278 meta:set_float("fuel_time", fuel_time)
279 meta:set_float("src_time", src_time)
280 meta:set_string("formspec", formspec)
281 --meta:set_string("infotext", infotext)
290 minetest.register_node("utility:furnace", {
291 description = "Furnace",
293 "furnace_top.png", "furnace_bottom.png",
294 "furnace_side.png", "furnace_side.png",
295 "furnace_side.png", "furnace_front.png"
297 paramtype2 = "facedir",
299 legacy_facedir_simple = true,
300 is_ground_content = false,
301 sounds = main.stoneSound(),
305 on_timer = furnace_node_timer,
307 on_construct = function(pos)
308 local meta = minetest.get_meta(pos)
309 local inv = meta:get_inventory()
310 inv:set_size('src', 1)
311 inv:set_size('fuel', 1)
312 inv:set_size('dst', 4)
313 furnace_node_timer(pos, 0)
316 on_metadata_inventory_move = function(pos)
317 minetest.get_node_timer(pos):start(1.0)
319 on_metadata_inventory_put = function(pos)
320 -- start timer function, it will sort out whether furnace can burn or not.
321 minetest.get_node_timer(pos):start(1.0)
323 on_blast = function(pos)
325 furnace.get_inventory_drops(pos, "src", drops)
326 furnace.get_inventory_drops(pos, "fuel", drops)
327 furnace.get_inventory_drops(pos, "dst", drops)
328 drops[#drops+1] = "default:furnace"
329 minetest.remove_node(pos)
333 allow_metadata_inventory_put = allow_metadata_inventory_put,
334 allow_metadata_inventory_move = allow_metadata_inventory_move,
335 allow_metadata_inventory_take = allow_metadata_inventory_take,
338 minetest.register_node("utility:furnace_active", {
339 description = "Furnace",
341 "furnace_top.png", "furnace_bottom.png",
342 "furnace_side.png", "furnace_side.png",
345 image = "furnace_front_active.png",
346 backface_culling = false,
348 type = "vertical_frames",
355 paramtype2 = "facedir",
357 drop = "default:furnace",
358 groups = {stone=2, not_in_creative_inventory=1},
359 legacy_facedir_simple = true,
360 is_ground_content = false,
361 sounds = main.stoneSound(),
362 on_timer = furnace_node_timer,
366 allow_metadata_inventory_put = allow_metadata_inventory_put,
367 allow_metadata_inventory_move = allow_metadata_inventory_move,
368 allow_metadata_inventory_take = allow_metadata_inventory_take,
371 minetest.register_craft({
372 output = "utility:furnace",
374 {"main:stone", "main:stone", "main:stone"},
375 {"main:stone", "", "main:stone"},
376 {"main:stone", "main:stone", "main:stone"},