3 function furnace.get_furnace_active_formspec(fuel_percent, item_percent)
5 "list[context;src;2.75,0.5;1,1;]"..
6 "list[context;fuel;2.75,2.5;1,1;]"..
7 "image[2.75,1.5;1,1;default_furnace_fire_bg.png^[lowpart:"..
8 (fuel_percent)..":default_furnace_fire_fg.png]"..
9 "image[3.75,1.5;1,1;gui_furnace_arrow_bg.png^[lowpart:"..
10 (item_percent)..":gui_furnace_arrow_fg.png^[transformR270]"..
11 "list[context;dst;4.75,0.96;2,2;]"..
12 "list[current_player;main;0,4.25;8,1;]"..
13 "list[current_player;main;0,5.5;8,3;8]"..
14 "listring[context;dst]"..
15 "listring[current_player;main]"..
16 "listring[context;src]"..
17 "listring[current_player;main]"..
18 "listring[context;fuel]"..
19 "listring[current_player;main]"..
20 furnace.get_hotbar_bg(0, 4.25)
23 function furnace.get_furnace_inactive_formspec()
24 return "size[8,8.5]"..
25 "list[context;src;2.75,0.5;1,1;]"..
26 "list[context;fuel;2.75,2.5;1,1;]"..
27 "image[2.75,1.5;1,1;default_furnace_fire_bg.png]"..
28 "image[3.75,1.5;1,1;gui_furnace_arrow_bg.png^[transformR270]"..
29 "list[context;dst;4.75,0.96;2,2;]"..
30 "list[current_player;main;0,4.25;8,1;]"..
31 "list[current_player;main;0,5.5;8,3;8]"..
32 "listring[context;dst]"..
33 "listring[current_player;main]"..
34 "listring[context;src]"..
35 "listring[current_player;main]"..
36 "listring[context;fuel]"..
37 "listring[current_player;main]"..
38 furnace.get_hotbar_bg(0, 4.25)
42 -- Node callback functions that are the same for active and inactive furnace
45 local function can_dig(pos, player)
46 local meta = minetest.get_meta(pos);
47 local inv = meta:get_inventory()
48 return inv:is_empty("fuel") and inv:is_empty("dst") and inv:is_empty("src")
51 local function allow_metadata_inventory_put(pos, listname, index, stack, player)
52 if minetest.is_protected(pos, player:get_player_name()) then
55 local meta = minetest.get_meta(pos)
56 local inv = meta:get_inventory()
57 if listname == "fuel" then
58 if minetest.get_craft_result({method="fuel", width=1, items={stack}}).time ~= 0 then
59 if inv:is_empty("src") then
60 meta:set_string("infotext", "Furnace is empty")
62 return stack:get_count()
66 elseif listname == "src" then
67 return stack:get_count()
68 elseif listname == "dst" then
73 local function allow_metadata_inventory_move(pos, from_list, from_index, to_list, to_index, count, player)
74 local meta = minetest.get_meta(pos)
75 local inv = meta:get_inventory()
76 local stack = inv:get_stack(from_list, from_index)
77 return allow_metadata_inventory_put(pos, to_list, to_index, stack, player)
80 local function allow_metadata_inventory_take(pos, listname, index, stack, player)
81 if minetest.is_protected(pos, player:get_player_name()) then
84 return stack:get_count()
87 local function swap_node(pos, name)
88 local node = minetest.get_node(pos)
89 if node.name == name then
93 minetest.swap_node(pos, node)
96 local function furnace_node_timer(pos, elapsed)
98 -- Initialize metadata
100 local meta = minetest.get_meta(pos)
101 local fuel_time = meta:get_float("fuel_time") or 0
102 local src_time = meta:get_float("src_time") or 0
103 local fuel_totaltime = meta:get_float("fuel_totaltime") or 0
105 local inv = meta:get_inventory()
106 local srclist, fuellist
107 local dst_full = false
109 local cookable, cooked
113 while elapsed > 0 and update do
116 srclist = inv:get_list("src")
117 fuellist = inv:get_list("fuel")
123 -- Check if we have cookable content
125 cooked, aftercooked = minetest.get_craft_result({method = "cooking", width = 1, items = srclist})
126 cookable = cooked.time ~= 0
128 local el = math.min(elapsed, fuel_totaltime - fuel_time)
129 if cookable then -- fuel lasts long enough, adjust el to cooking duration
130 el = math.min(el, cooked.time - src_time)
133 -- Check if we have enough fuel to burn
134 if fuel_time < fuel_totaltime then
135 -- The furnace is currently active and has enough fuel
136 fuel_time = fuel_time + el
137 -- If there is a cookable item then check if it is ready yet
139 src_time = src_time + el
140 if src_time >= cooked.time then
141 -- Place result in dst list if possible
142 if inv:room_for_item("dst", cooked.item) then
143 inv:add_item("dst", cooked.item)
144 inv:set_stack("src", 1, aftercooked.items[1])
145 src_time = src_time - cooked.time
151 -- Item could not be cooked: probably missing fuel
156 -- Furnace ran out of fuel
158 -- We need to get new fuel
160 fuel, afterfuel = minetest.get_craft_result({method = "fuel", width = 1, items = fuellist})
162 if fuel.time == 0 then
163 -- No valid fuel in fuel list
167 -- Take fuel from fuel list
168 inv:set_stack("fuel", 1, afterfuel.items[1])
169 -- Put replacements in dst list or drop them on the furnace.
170 local replacements = fuel.replacements
171 if replacements[1] then
172 local leftover = inv:add_item("dst", replacements[1])
173 if not leftover:is_empty() then
174 local above = vector.new(pos.x, pos.y + 1, pos.z)
175 local drop_pos = minetest.find_node_near(above, 1, {"air"}) or above
176 minetest.item_drop(replacements[1], nil, drop_pos)
180 fuel_totaltime = fuel.time + (fuel_totaltime - fuel_time)
183 -- We don't need to get new fuel since there is no cookable item
190 elapsed = elapsed - el
193 if fuel and fuel_totaltime > fuel.time then
194 fuel_totaltime = fuel.time
196 if srclist and srclist[1]:is_empty() then
201 -- Update formspec, infotext and node
205 local item_percent = 0
207 item_percent = math.floor(src_time / cooked.time * 100)
209 item_state = ("100% (output full)")
211 item_state = (item_percent)
214 if srclist and not srclist[1]:is_empty() then
215 item_state = ("Not cookable")
217 item_state = ("Empty")
221 local fuel_state = ("Empty")
225 if fuel_totaltime ~= 0 then
227 local fuel_percent = 100 - math.floor(fuel_time / fuel_totaltime * 100)
228 fuel_state = (fuel_percent)
229 formspec = furnace.get_furnace_active_formspec(fuel_percent, item_percent)
230 swap_node(pos, "utility:furnace_active")
231 -- make sure timer restarts automatically
234 if fuellist and not fuellist[1]:is_empty() then
237 formspec = furnace.get_furnace_inactive_formspec()
238 swap_node(pos, "utility:furnace")
239 -- stop timer on the inactive furnace
240 minetest.get_node_timer(pos):stop()
246 infotext = ("Furnace active")
248 infotext = ("Furnace inactive")
250 infotext = infotext .. "\n" .. "Item:"..item_state.. "Fuel:"..fuel_state
255 meta:set_float("fuel_totaltime", fuel_totaltime)
256 meta:set_float("fuel_time", fuel_time)
257 meta:set_float("src_time", src_time)
258 meta:set_string("formspec", formspec)
259 meta:set_string("infotext", infotext)
268 minetest.register_node("utility:furnace", {
269 description = ("Furnace"),
271 "default_furnace_top.png", "default_furnace_bottom.png",
272 "default_furnace_side.png", "default_furnace_side.png",
273 "default_furnace_side.png", "default_furnace_front.png"
275 paramtype2 = "facedir",
277 legacy_facedir_simple = true,
278 is_ground_content = false,
279 sounds = main.stoneSound(),
283 on_timer = furnace_node_timer,
285 on_construct = function(pos)
286 local meta = minetest.get_meta(pos)
287 local inv = meta:get_inventory()
288 inv:set_size('src', 1)
289 inv:set_size('fuel', 1)
290 inv:set_size('dst', 4)
291 furnace_node_timer(pos, 0)
294 on_metadata_inventory_move = function(pos)
295 minetest.get_node_timer(pos):start(1.0)
297 on_metadata_inventory_put = function(pos)
298 -- start timer function, it will sort out whether furnace can burn or not.
299 minetest.get_node_timer(pos):start(1.0)
301 on_blast = function(pos)
303 furnace.get_inventory_drops(pos, "src", drops)
304 furnace.get_inventory_drops(pos, "fuel", drops)
305 furnace.get_inventory_drops(pos, "dst", drops)
306 drops[#drops+1] = "utility:furnace"
307 minetest.remove_node(pos)
311 allow_metadata_inventory_put = allow_metadata_inventory_put,
312 allow_metadata_inventory_move = allow_metadata_inventory_move,
313 allow_metadata_inventory_take = allow_metadata_inventory_take,
316 minetest.register_node("utility:furnace_active", {
317 description = ("Furnace"),
319 "default_furnace_top.png", "default_furnace_bottom.png",
320 "default_furnace_side.png", "default_furnace_side.png",
321 "default_furnace_side.png",
323 image = "default_furnace_front_active.png",
324 backface_culling = false,
326 type = "vertical_frames",
333 paramtype2 = "facedir",
335 drop = "utility:furnace",
336 groups = {cracky=2, not_in_creative_inventory=1},
337 legacy_facedir_simple = true,
338 is_ground_content = false,
339 sounds = main.stoneSound(),
340 on_timer = furnace_node_timer,
344 allow_metadata_inventory_put = allow_metadata_inventory_put,
345 allow_metadata_inventory_move = allow_metadata_inventory_move,
346 allow_metadata_inventory_take = allow_metadata_inventory_take,
349 minetest.register_craft({
350 output = "utility:furnace",
352 {"group:stone", "group:stone", "group:stone"},
353 {"group:stone", "", "group:stone"},
354 {"group:stone", "group:stone", "group:stone"},