6 local function active_formspec(fuel_percent
, item_percent
)
7 return "size[9,8.75]"..
8 "background[-0.19,-0.25;9.41,9.49;crafting_inventory_furnace.png]"..
9 mcl_vars
.inventory_header
..
10 "list[current_player;main;0,4.5;9,3;9]"..
11 "list[current_player;main;0,7.74;9,1;]"..
12 "list[current_name;src;2.75,0.5;1,1;]"..
13 "list[current_name;fuel;2.75,2.5;1,1;]"..
14 "list[current_name;dst;5.75,1.5;1,1;]"..
15 "image[2.75,1.5;1,1;default_furnace_fire_bg.png^[lowpart:"..
16 (100-fuel_percent
)..":default_furnace_fire_fg.png]"..
17 "image[4.1,1.5;1.5,1;gui_furnace_arrow_bg.png^[lowpart:"..
18 (item_percent
)..":gui_furnace_arrow_fg.png^[transformR270]"..
19 "image_button[8,0;1,1;craftguide_book.png;craftguide;]"..
20 "tooltip[craftguide;Recipe book]"..
22 "listring[current_name;dst]"..
23 "listring[current_player;main]"..
24 "listring[current_name;src]"..
25 "listring[current_player;main]"..
26 "listring[current_name;fuel]"..
27 "listring[current_player;main]"
30 local inactive_formspec
= "size[9,8.75]"..
31 "background[-0.19,-0.25;9.41,9.49;crafting_inventory_furnace.png]"..
32 mcl_vars
.inventory_header
..
33 "list[current_player;main;0,4.5;9,3;9]"..
34 "list[current_player;main;0,7.74;9,1;]"..
35 "list[current_name;src;2.75,0.5;1,1;]"..
36 "list[current_name;fuel;2.75,2.5;1,1;]"..
37 "list[current_name;dst;5.75,1.5;1,1;]"..
38 "image[2.75,1.5;1,1;default_furnace_fire_bg.png]"..
39 "image[4.1,1.5;1.5,1;gui_furnace_arrow_bg.png^[transformR270]"..
40 "image_button[8,0;1,1;craftguide_book.png;craftguide;]"..
41 "tooltip[craftguide;Recipe book]"..
43 "listring[current_name;dst]"..
44 "listring[current_player;main]"..
45 "listring[current_name;src]"..
46 "listring[current_player;main]"..
47 "listring[current_name;fuel]"..
48 "listring[current_player;main]"
50 local receive_fields
= function(pos
, formname
, fields
, sender
)
51 if fields
.craftguide
then
52 mcl_craftguide
.show_craftguide(sender
)
53 elseif fields
.doc
and minetest
.get_modpath("doc") then
54 doc
.show_entry(sender
:get_player_name(), "nodes", "mcl_furnaces:furnace", true)
59 -- Node callback functions that are the same for active and inactive furnace
62 local function allow_metadata_inventory_put(pos
, listname
, index
, stack
, player
)
63 if minetest
.is_protected(pos
, player
:get_player_name()) then
66 local meta
= minetest
.get_meta(pos
)
67 local inv
= meta
:get_inventory()
68 if listname
== "fuel" then
69 -- Special case: empty bucket (not a fuel, but used for sponge drying)
70 if stack
:get_name() == "mcl_buckets:bucket_empty" then
71 if inv
:get_stack(listname
, index
):get_count() == 0 then
78 -- Test stack with size 1 because we burn one fuel at a time
79 local teststack
= ItemStack(stack
)
80 teststack
:set_count(1)
81 local output
, decremented_input
= minetest
.get_craft_result({method
="fuel", width
=1, items
={teststack
}})
82 if output
.time
~= 0 then
83 -- Only allow to place 1 item if fuel get replaced by recipe.
84 -- This is the case for lava buckets.
85 local replace_item
= decremented_input
.items
[1]
86 if replace_item
:is_empty() then
87 -- For most fuels, just allow to place everything
88 return stack
:get_count()
90 if inv
:get_stack(listname
, index
):get_count() == 0 then
99 elseif listname
== "src" then
100 return stack
:get_count()
101 elseif listname
== "dst" then
106 local function allow_metadata_inventory_move(pos
, from_list
, from_index
, to_list
, to_index
, count
, player
)
107 local meta
= minetest
.get_meta(pos
)
108 local inv
= meta
:get_inventory()
109 local stack
= inv
:get_stack(from_list
, from_index
)
110 return allow_metadata_inventory_put(pos
, to_list
, to_index
, stack
, player
)
113 local function allow_metadata_inventory_take(pos
, listname
, index
, stack
, player
)
114 if minetest
.is_protected(pos
, player
:get_player_name()) then
117 return stack
:get_count()
120 local function on_metadata_inventory_take(pos
, listname
, index
, stack
, player
)
121 -- Award smelting achievements
122 if listname
== "dst" then
123 if stack
:get_name() == "mcl_core:iron_ingot" then
124 awards
.unlock(player
:get_player_name(), "mcl:acquireIron")
125 elseif stack
:get_name() == "mcl_fishing:fish_cooked" then
126 awards
.unlock(player
:get_player_name(), "mcl:cookFish")
131 local function swap_node(pos
, name
)
132 local node
= minetest
.get_node(pos
)
133 if node
.name
== name
then
137 minetest
.swap_node(pos
, node
)
140 local function furnace_node_timer(pos
, elapsed
)
142 -- Inizialize metadata
144 local meta
= minetest
.get_meta(pos
)
145 local fuel_time
= meta
:get_float("fuel_time") or 0
146 local src_time
= meta
:get_float("src_time") or 0
147 local src_item
= meta
:get_string("src_item") or ""
148 local fuel_totaltime
= meta
:get_float("fuel_totaltime") or 0
150 local inv
= meta
:get_inventory()
151 local srclist
, fuellist
153 local cookable
, cooked
160 srclist
= inv
:get_list("src")
161 fuellist
= inv
:get_list("fuel")
167 -- Check if we have cookable content
169 cooked
, aftercooked
= minetest
.get_craft_result({method
= "cooking", width
= 1, items
= srclist
})
170 cookable
= cooked
.time
~= 0
172 -- Check if src item has been changed
173 if srclist
[1]:get_name() ~= src_item
then
174 -- Reset cooking progress in this case
176 src_item
= srclist
[1]:get_name()
179 -- Check if we have enough fuel to burn
180 elseif fuel_time
< fuel_totaltime
then
181 -- The furnace is currently active and has enough fuel
182 fuel_time
= fuel_time
+ elapsed
183 -- If there is a cookable item then check if it is ready yet
185 -- Successful cooking requires space in dst slot and time
186 if inv
:room_for_item("dst", cooked
.item
) then
187 src_time
= src_time
+ elapsed
189 -- Place result in dst list if done
190 if src_time
>= cooked
.time
then
191 inv
:add_item("dst", cooked
.item
)
192 inv
:set_stack("src", 1, aftercooked
.items
[1])
194 -- Unique recipe: Pour water into empty bucket after cooking wet sponge successfully
195 if inv
:get_stack("fuel", 1):get_name() == "mcl_buckets:bucket_empty" then
196 if srclist
[1]:get_name() == "mcl_sponges:sponge_wet" then
197 inv
:set_stack("fuel", 1, "mcl_buckets:bucket_water")
198 -- Also for river water
199 elseif srclist
[1]:get_name() == "mcl_sponges:sponge_wet_river_water" then
200 inv
:set_stack("fuel", 1, "mcl_buckets:bucket_river_water")
207 elseif src_time
~= 0 then
208 -- If output slot is occupied, stop cooking
214 -- Furnace ran out of fuel
216 -- We need to get new fuel
218 fuel
, afterfuel
= minetest
.get_craft_result({method
= "fuel", width
= 1, items
= fuellist
})
220 if fuel
.time
== 0 then
221 -- No valid fuel in fuel list
225 -- Take fuel from fuel list
226 inv
:set_stack("fuel", 1, afterfuel
.items
[1])
228 fuel_totaltime
= fuel
.time
+ (fuel_time
- fuel_totaltime
)
229 src_time
= src_time
+ elapsed
232 -- We don't need to get new fuel since there is no cookable item
242 if fuel
and fuel_totaltime
> fuel
.time
then
243 fuel_totaltime
= fuel
.time
245 if srclist
[1]:is_empty() then
250 -- Update formspec and node
252 local formspec
= inactive_formspec
254 local item_percent
= 0
256 item_percent
= math
.floor(src_time
/ cooked
.time
* 100)
261 if fuel_totaltime
~= 0 then
262 local fuel_percent
= math
.floor(fuel_time
/ fuel_totaltime
* 100)
263 formspec
= active_formspec(fuel_percent
, item_percent
)
264 swap_node(pos
, "mcl_furnaces:furnace_active")
265 -- make sure timer restarts automatically
268 swap_node(pos
, "mcl_furnaces:furnace")
269 -- stop timer on the inactive furnace
270 minetest
.get_node_timer(pos
):stop()
276 meta
:set_float("fuel_totaltime", fuel_totaltime
)
277 meta
:set_float("fuel_time", fuel_time
)
278 meta
:set_float("src_time", src_time
)
279 meta
:set_string("src_item", srclist
[1]:get_name())
280 meta
:set_string("formspec", formspec
)
286 if minetest
.get_modpath("screwdriver") then
287 on_rotate
= screwdriver
.rotate_simple
290 minetest
.register_node("mcl_furnaces:furnace", {
291 description
= "Furnace",
292 _doc_items_longdesc
= "Furnaces cook or smelt several items, using a furnace fuel, into something else.",
293 _doc_items_usagehelp
= "Right-click the furnace to view it. Place a furnace fuel in the lower slot and the source material in the upper slot. The furnace will slowly use its fuel to smelt the item. The result will be placed into the output slot at the right side.",
294 _doc_items_hidden
= false,
296 "default_furnace_top.png", "default_furnace_bottom.png",
297 "default_furnace_side.png", "default_furnace_side.png",
298 "default_furnace_side.png", "default_furnace_front.png"
300 paramtype2
= "facedir",
301 groups
= {pickaxey
=1, container
=4, deco_block
=1, material_stone
=1},
302 is_ground_content
= false,
303 sounds
= mcl_sounds
.node_sound_stone_defaults(),
305 on_timer
= furnace_node_timer
,
306 after_dig_node
= function(pos
, oldnode
, oldmetadata
, digger
)
307 local meta
= minetest
.get_meta(pos
)
309 meta
:from_table(oldmetadata
)
310 local inv
= meta
:get_inventory()
311 for _
, listname
in ipairs({"src", "dst", "fuel"}) do
312 local stack
= inv
:get_stack(listname
, 1)
313 if not stack
:is_empty() then
314 local p
= {x
=pos
.x
+math
.random(0, 10)/10-0.5, y
=pos
.y
, z
=pos
.z
+math
.random(0, 10)/10-0.5}
315 minetest
.add_item(p
, stack
)
318 meta
:from_table(meta2
:to_table())
321 on_construct
= function(pos
)
322 local meta
= minetest
.get_meta(pos
)
323 meta
:set_string("formspec", inactive_formspec
)
324 local inv
= meta
:get_inventory()
325 inv
:set_size('src', 1)
326 inv
:set_size('fuel', 1)
327 inv
:set_size('dst', 1)
330 on_metadata_inventory_move
= function(pos
)
331 minetest
.get_node_timer(pos
):start(1.0)
333 on_metadata_inventory_put
= function(pos
)
334 -- start timer function, it will sort out whether furnace can burn or not.
335 minetest
.get_node_timer(pos
):start(1.0)
338 allow_metadata_inventory_put
= allow_metadata_inventory_put
,
339 allow_metadata_inventory_move
= allow_metadata_inventory_move
,
340 allow_metadata_inventory_take
= allow_metadata_inventory_take
,
341 on_metadata_inventory_take
= on_metadata_inventory_take
,
342 on_receive_fields
= receive_fields
,
343 _mcl_blast_resistance
= 17.5,
345 on_rotate
= on_rotate
,
348 minetest
.register_node("mcl_furnaces:furnace_active", {
349 description
= "Burning Furnace",
350 _doc_items_create_entry
= false,
352 "default_furnace_top.png", "default_furnace_bottom.png",
353 "default_furnace_side.png", "default_furnace_side.png",
354 "default_furnace_side.png", "default_furnace_front_active.png",
356 paramtype2
= "facedir",
359 drop
= "mcl_furnaces:furnace",
360 groups
= {pickaxey
=1, container
=4, deco_block
=1, not_in_creative_inventory
=1, material_stone
=1},
361 is_ground_content
= false,
362 sounds
= mcl_sounds
.node_sound_stone_defaults(),
363 on_timer
= furnace_node_timer
,
365 after_dig_node
= function(pos
, oldnode
, oldmetadata
, digger
)
366 local meta
= minetest
.get_meta(pos
)
368 meta
:from_table(oldmetadata
)
369 local inv
= meta
:get_inventory()
370 for _
, listname
in ipairs({"src", "dst", "fuel"}) do
371 local stack
= inv
:get_stack(listname
, 1)
372 if not stack
:is_empty() then
373 local p
= {x
=pos
.x
+math
.random(0, 10)/10-0.5, y
=pos
.y
, z
=pos
.z
+math
.random(0, 10)/10-0.5}
374 minetest
.add_item(p
, stack
)
377 meta
:from_table(meta2
:to_table())
381 allow_metadata_inventory_put
= allow_metadata_inventory_put
,
382 allow_metadata_inventory_move
= allow_metadata_inventory_move
,
383 allow_metadata_inventory_take
= allow_metadata_inventory_take
,
384 on_metadata_inventory_take
= on_metadata_inventory_take
,
385 on_receive_fields
= receive_fields
,
386 _mcl_blast_resistance
= 17.5,
388 on_rotate
= on_rotate
,
391 minetest
.register_craft({
392 output
= "mcl_furnaces:furnace",
394 { "mcl_core:cobble", "mcl_core:cobble", "mcl_core:cobble" },
395 { "mcl_core:cobble", "", "mcl_core:cobble" },
396 { "mcl_core:cobble", "mcl_core:cobble", "mcl_core:cobble" },
400 -- Add entry alias for the Help
401 if minetest
.get_modpath("doc") then
402 doc
.add_entry_alias("nodes", "mcl_furnaces:furnace", "nodes", "mcl_furnaces:furnace_active")