4 spawn 3 entities - cook fuel output
10 then pass output to cooked entity
12 when player hits entity then drop item towards player
14 when cooking have fire and smoke on cooking item
19 minetest.register_craftitem("utility:nothing", {
20 description = "Nothing",
21 inventory_image = "wood.png",
26 local fuel_height = 0.75
27 local cook_height = 1.3
28 local output_height = 1.85
31 function furnace.get_hotbar_bg(x,y)
34 out = out .."image["..x+i..","..y..";1,1;gui_furnace_arrow_bg.png]"
39 function furnace.get_inventory_drops(pos, inventory, drops)
40 local inv = minetest.get_meta(pos):get_inventory()
42 for i = 1, inv:get_size(inventory) do
43 local stack = inv:get_stack(inventory, i)
44 if stack:get_count() > 0 then
45 drops[n+1] = stack:to_table()
51 --cooked, aftercooked = minetest.get_craft_result({method = "cooking", width = 1, items = srclist})
52 --cookable = cooked.time ~= 0
57 local function furnace_setup(pos)
58 local obj = minetest.add_entity(vector.new(pos.x,pos.y+fuel_height,pos.z), "utility:fuel")
59 obj:get_luaentity().set_item(obj:get_luaentity(),"utility:nothing")
60 local obj = minetest.add_entity(vector.new(pos.x,pos.y+cook_height,pos.z), "utility:cook")
61 obj:get_luaentity().set_item(obj:get_luaentity(),"utility:nothing")
62 local obj = minetest.add_entity(vector.new(pos.x,pos.y+output_height,pos.z), "utility:output")
63 obj:get_luaentity().set_item(obj:get_luaentity(),"utility:nothing")
66 local function furnace_remove(pos)
67 for _,object in ipairs(minetest.get_objects_inside_radius(vector.new(pos.x,pos.y+fuel_height,pos.z), 0.1)) do
68 if not object:is_player() and object:get_luaentity() and object:get_luaentity().name == "utility:fuel" then
69 local pos = object:getpos()
70 local item = object:get_luaentity().itemstring
71 if item ~= "utility:nothing" then
72 local obj = minetest.add_item(pos,item)
77 for _,object in ipairs(minetest.get_objects_inside_radius(vector.new(pos.x,pos.y+cook_height,pos.z), 0.1)) do
78 if not object:is_player() and object:get_luaentity() and object:get_luaentity().name == "utility:cook" then
79 local pos = object:getpos()
80 local item = object:get_luaentity().itemstring
81 if item ~= "utility:nothing" then
82 local obj = minetest.add_item(pos,item)
87 for _,object in ipairs(minetest.get_objects_inside_radius(vector.new(pos.x,pos.y+output_height,pos.z), 0.1)) do
88 if not object:is_player() and object:get_luaentity() and object:get_luaentity().name == "utility:output" then
89 local pos = object:getpos()
90 local item = object:get_luaentity().itemstring
91 if item ~= "utility:nothing" then
92 local obj = minetest.add_item(pos,item)
99 minetest.register_node("utility:furnace", {
100 description = "Furnace",
102 "furnace_top.png", "furnace_bottom.png",
103 "furnace_side.png", "furnace_side.png",
104 "furnace_side.png", "furnace_front.png"
106 paramtype2 = "facedir",
108 legacy_facedir_simple = true,
109 is_ground_content = false,
110 sounds = main.stoneSound(),
111 on_construct = function(pos)
114 on_destruct = function(pos)
119 minetest.register_craft({
120 output = "utility:furnace",
122 {"main:stone", "main:stone", "main:stone"},
123 {"main:stone", "", "main:stone"},
124 {"main:stone", "main:stone", "main:stone"},
128 --------------------------------------------------------------------------------------------------
131 minetest.get_craft_result({method = "cooking", width = 1, items = srclist}) --check if cookable
133 minetest.get_craft_result({method = "fuel", width = 1, items = fuellist}) --check if fuel
135 space in between = 0.55
141 minetest.register_entity("utility:fuel", {
142 initial_properties = {
145 collide_with_objects = false,
146 collisionbox = {-0.3, -0.3, -0.3, 0.3, 0.3, 0.3},
147 visual = "wielditem",
148 visual_size = {x = 0.6, y = 0.6},
150 spritediv = {x = 1, y = 1},
151 initial_sprite_basepos = {x = 0, y = 0},
162 set_item = function(self, item)
163 local stack = ItemStack(item or self.itemstring)
164 self.itemstring = stack:to_string()
165 --if self.itemstring == "" then
166 -- item not yet known
170 local count = stack:get_count()
173 -- Backwards compatibility: old clients use the texture
174 -- to get the type of the item
175 local itemname = stack:is_known() and stack:get_name() or "unknown"
177 local max_count = stack:get_stack_max()
179 local coll_height = size * 0.75
180 local def = minetest.registered_nodes[itemname]
181 --local glow = def and def.light_source
183 self.object:set_properties({
185 visual = "wielditem",
186 textures = {itemname},
187 visual_size = {x = size, y = size},
188 --collisionbox = {-size, -coll_height, -size,
189 -- size, coll_height, size},
190 selectionbox = {-size, -size, -size, size, size, size},
191 automatic_rotate = math.pi * 0.5 * 0.2 / size,
192 wield_item = self.itemstring,
197 get_staticdata = function(self)
198 return minetest.serialize({
199 itemstring = self.itemstring,
204 on_activate = function(self, staticdata, dtime_s)
205 if string.sub(staticdata, 1, string.len("return")) == "return" then
206 local data = minetest.deserialize(staticdata)
207 if data and type(data) == "table" then
208 self.itemstring = data.itemstring
209 self.count = data.count
212 self.itemstring = staticdata
214 self.object:set_armor_groups({immortal = 1})
215 self.object:set_velocity({x = 0, y = 0, z = 0})
216 self.object:set_acceleration({x = 0, y = 0, z = 0})
220 on_rightclick = function(self, clicker)
222 if not clicker or not clicker:is_player() then
226 local stack = clicker:get_wielded_item()
228 local item = stack:get_name()
229 local count = stack:get_count()
230 if stack:get_name() == "utility:nothing" then
234 --shoot out existing item
235 if self.itemstring ~= item.." "..count and self.itemstring ~= "utility:nothing" then
236 local pos = self.object:getpos()
237 local pos2 = clicker:getpos()
238 pos2.y = pos2.y + 1.25
239 local obj = minetest.add_item(pos,self.itemstring)
240 local dir = vector.subtract(pos2,pos)
241 vector.multiply(dir,5)
244 obj:setvelocity(vector.new(dir.x,dir.y+3.5,dir.z))
246 print("ERROR FURNACE RELEASED NON ITEM")
250 if (item == "" or item == "hand:player") then
251 self.set_item(self,"utility:nothing")
252 self.object:set_nametag_attributes({
259 self.set_item(self, item.." "..count)
261 self.object:set_nametag_attributes({
263 text = minetest.registered_items[item].description.." "..count,
266 stack = stack:clear()
267 clicker:set_wielded_item("")
270 on_punch = function(self, puncher, time_from_last_punch, tool_capabilities, dir)
271 if not puncher or not puncher:is_player() then
275 if self.itemstring == "utility:nothing" then
279 local pos = self.object:getpos()
280 local pos2 = puncher:getpos()
281 pos2.y = pos2.y + 1.25
283 local obj = minetest.add_item(pos,self.itemstring)
284 local dir = vector.subtract(pos2,pos)
285 vector.multiply(dir,5)
287 self.set_item(self,"utility:nothing")
288 self.object:set_nametag_attributes({
294 obj:setvelocity(vector.new(dir.x,dir.y+3.5,dir.z))
296 print("ERROR FURNACE RELEASED NON ITEM")
300 check_cook = function(self)
301 local pos = self.object:getpos()
302 --check the cook timer
303 for _,object in ipairs(minetest.get_objects_inside_radius(vector.new(pos.x,pos.y+0.55,pos.z), 0.1)) do
304 if not object:is_player() and object:get_luaentity() and object:get_luaentity().name == "utility:cook" then
305 local item = object:get_luaentity().itemstring
306 return(minetest.get_craft_result({method = "cooking", width = 1, items = {ItemStack(item)}}).time)
311 cook_item = function(self)
312 local pos = self.object:getpos()
313 for _,object in ipairs(minetest.get_objects_inside_radius(vector.new(pos.x,pos.y+0.55,pos.z), 0.1)) do
314 if not object:is_player() and object:get_luaentity() and object:get_luaentity().name == "utility:cook" then
315 local item = ItemStack(object:get_luaentity().itemstring)
319 local count = object:get_luaentity().count
320 local output = minetest.get_craft_result({method = "cooking", width = 1, items = {ItemStack(item)}}).item
321 local outputitem = output:get_name()
322 local outputcount = output:get_count()
325 local itemname = item:get_name()
329 object:get_luaentity().count = count
331 local pos = self.object:getpos()
334 for _,object2 in ipairs(minetest.get_objects_inside_radius(vector.new(pos.x,pos.y+1.10,pos.z), 0.1)) do
335 if not object2:is_player() and object2:get_luaentity() and object2:get_luaentity().name == "utility:output" then
336 local goal_item = ItemStack(object2:get_luaentity().itemstring)
337 local goal_item_name = goal_item:get_name()
338 local goal_item_count = goal_item:get_count()
340 --cancel out if player took item
341 if outputitem == "" then
345 --add item to output or throw existing item out if not matched
346 if goal_item_name ~= outputitem and goal_item_name ~= "utility:nothing" then
347 local pos2 = object2:get_pos()
348 local obj = minetest.add_item(pos2,object2:get_luaentity().itemstring)
349 local dir = vector.new(math.random(-3,3),math.random(3,6),math.random(-3,3))
350 --dir = vector.multiply(dir,2)
353 obj:setvelocity(vector.new(dir.x,dir.y,dir.z))
355 print("ERROR FURNACE RELEASED NON ITEM")
357 object2:get_luaentity().count = 0
360 object2:get_luaentity().count = object2:get_luaentity().count + outputcount
361 object2:get_luaentity().set_item(object2:get_luaentity(), outputitem.." "..object2:get_luaentity().count)
362 object2:set_nametag_attributes({
364 text = outputitem.." "..object2:get_luaentity().count,
370 --update count and nametag
371 if object:get_luaentity().count == 0 then
372 object:get_luaentity().set_item(object:get_luaentity(), "utility:nothing")
373 object:set_nametag_attributes({
378 object:get_luaentity().set_item(object:get_luaentity(), itemname.." "..count)
379 object:set_nametag_attributes({
381 text = itemname.." "..count,
388 spawn_particles = function(self,time)
389 --print("time:"..time)
390 local pos = self.object:getpos()
391 minetest.add_particlespawner({
392 amount = math.floor(10*time),
394 minpos = vector.new(pos.x-0.3,pos.y-0.3,pos.z-0.3),
395 maxpos = vector.new(pos.x+0.3,pos.y+0.3,pos.z+0.3),
396 minvel = {x=0, y=0.2, z=0},
397 maxvel = {x=0, y=0.5, z=0},
398 minacc = {x=0, y=0, z=0},
399 maxacc = {x=0, y=0, z=0},
404 collisiondetection = false,
406 texture = "flame.png",
410 minetest.add_particlespawner({
411 amount = math.floor(10*time),
413 minpos = vector.new(pos.x-0.3,pos.y+0.3,pos.z-0.3),
414 maxpos = vector.new(pos.x+0.3,pos.y+0.6,pos.z+0.3),
415 minvel = {x=0, y=0.2, z=0},
416 maxvel = {x=0, y=0.7, z=0},
417 minacc = {x=0, y=0, z=0},
418 maxacc = {x=0, y=0, z=0},
423 collisiondetection = false,
425 texture = "smoke.png",
431 --check if item is in the input then cook if so
432 on_step = function(self, dtime)
433 if self.cooking == true then
434 self.cooking_timer = self.cooking_timer - dtime
435 if self.cooking_timer < 0 then
436 self.cooking_timer = 0
442 --check to start cooking countdown
443 if self.cooking == false then
444 local stack = ItemStack(self.itemstring)
445 local fuel = minetest.get_craft_result({method = "fuel", width = 1, items = {stack}}).time
447 local cookie = self.check_cook(self)
449 --print("starting timer")
450 self.spawn_particles(self,fuel)
451 self.cooking_timer = cookie
453 --set up the fuel timer
454 if self.fuel_timer == 0 then
455 self.fuel_timer = fuel
462 if self.fuel_timer >= 0 then
463 self.fuel_timer = self.fuel_timer - dtime
464 --print(self.fuel_timer)
465 elseif self.fuel_timer < 0 then
466 if ItemStack(self.itemstring):get_name() == "utility:nothing" then
469 if self.cooking == false then
472 self.count = self.count - 1
474 local count = self.count
475 local itemname = ItemStack(self.itemstring):get_name()
477 if self.count == 0 then
478 self.set_item(self, "utility:nothing")
479 self.object:set_nametag_attributes({
484 self.set_item(self, itemname.." "..count)
485 self.object:set_nametag_attributes({
487 text = itemname.." "..count,
491 if self.count == 0 then
496 if self.cooking == true then
497 --print("resetting timer")
498 local time = minetest.get_craft_result({method = "fuel", width = 1, items = {ItemStack(self.itemstring)}}).time
499 self.fuel_timer = time
505 ----------------------------------------------------------------------------
507 minetest.register_entity("utility:cook", {
508 initial_properties = {
511 collide_with_objects = false,
512 collisionbox = {-0.3, -0.3, -0.3, 0.3, 0.3, 0.3},
513 visual = "wielditem",
514 visual_size = {x = 0.6, y = 0.6},
516 spritediv = {x = 1, y = 1},
517 initial_sprite_basepos = {x = 0, y = 0},
525 set_item = function(self, item)
526 local stack = ItemStack(item or self.itemstring)
527 self.itemstring = stack:to_string()
528 --if self.itemstring == "" then
529 -- item not yet known
533 local count = stack:get_count()
534 if stack:get_name() == "utility:nothing" then
539 -- Backwards compatibility: old clients use the texture
540 -- to get the type of the item
541 local itemname = stack:is_known() and stack:get_name() or "unknown"
543 local max_count = stack:get_stack_max()
545 local coll_height = size * 0.75
546 local def = minetest.registered_nodes[itemname]
547 --local glow = def and def.light_source
549 self.object:set_properties({
551 visual = "wielditem",
552 textures = {itemname},
553 visual_size = {x = size, y = size},
554 --collisionbox = {-size, -coll_height, -size,
555 -- size, coll_height, size},
556 selectionbox = {-size, -size, -size, size, size, size},
557 automatic_rotate = math.pi * 0.5 * 0.2 / size,
558 wield_item = self.itemstring,
563 get_staticdata = function(self)
564 return minetest.serialize({
565 itemstring = self.itemstring,
570 on_activate = function(self, staticdata, dtime_s)
571 if string.sub(staticdata, 1, string.len("return")) == "return" then
572 local data = minetest.deserialize(staticdata)
573 if data and type(data) == "table" then
574 self.itemstring = data.itemstring
575 self.count = data.count
578 self.itemstring = staticdata
580 self.object:set_armor_groups({immortal = 1})
581 self.object:set_velocity({x = 0, y = 0, z = 0})
582 self.object:set_acceleration({x = 0, y = 0, z = 0})
586 on_rightclick = function(self, clicker)
588 if not clicker or not clicker:is_player() then
592 local stack = clicker:get_wielded_item()
594 local item = stack:get_name()
595 local count = stack:get_count()
597 --shoot out existing item
598 if self.itemstring ~= item.." "..count and self.itemstring ~= "utility:nothing" then
599 local pos = self.object:getpos()
600 local pos2 = clicker:getpos()
601 pos2.y = pos2.y + 1.25
602 local obj = minetest.add_item(pos,self.itemstring)
603 local dir = vector.subtract(pos2,pos)
604 vector.multiply(dir,5)
607 obj:setvelocity(vector.new(dir.x,dir.y+3.5,dir.z))
609 print("ERROR FURNACE RELEASED NON ITEM")
613 if (item == "" or item == "hand:player") then
614 self.set_item(self,"utility:nothing")
615 self.object:set_nametag_attributes({
622 self.set_item(self, item.." "..count)
624 self.object:set_nametag_attributes({
626 text = minetest.registered_items[item].description.." "..count,
629 stack = stack:clear()
630 clicker:set_wielded_item("")
633 on_punch = function(self, puncher, time_from_last_punch, tool_capabilities, dir)
634 if not puncher or not puncher:is_player() then
638 if self.itemstring == "utility:nothing" then
642 local pos = self.object:getpos()
643 local pos2 = puncher:getpos()
644 pos2.y = pos2.y + 1.25
646 local obj = minetest.add_item(pos,self.itemstring)
647 local dir = vector.subtract(pos2,pos)
648 vector.multiply(dir,5)
650 self.set_item(self,"utility:nothing")
651 self.object:set_nametag_attributes({
657 obj:setvelocity(vector.new(dir.x,dir.y+3.5,dir.z))
659 print("ERROR FURNACE RELEASED NON ITEM")
664 on_step = function(self, dtime)
665 --set glow if cooking
666 --local glow = def and def.light_source
669 ----------------------------------------------------------------------------
671 minetest.register_entity("utility:output", {
672 initial_properties = {
675 collide_with_objects = false,
676 collisionbox = {-0.3, -0.3, -0.3, 0.3, 0.3, 0.3},
677 visual = "wielditem",
678 visual_size = {x = 0.6, y = 0.6},
680 spritediv = {x = 1, y = 1},
681 initial_sprite_basepos = {x = 0, y = 0},
689 set_item = function(self, item)
690 local stack = ItemStack(item or self.itemstring)
691 self.itemstring = stack:to_string()
692 --if self.itemstring == "" then
693 -- item not yet known
697 local count = stack:get_count()
698 if stack:get_name() == "utility:nothing" then
703 -- Backwards compatibility: old clients use the texture
704 -- to get the type of the item
705 local itemname = stack:is_known() and stack:get_name() or "unknown"
707 local max_count = stack:get_stack_max()
709 local coll_height = size * 0.75
710 local def = minetest.registered_nodes[itemname]
711 --local glow = def and def.light_source
713 self.object:set_properties({
715 visual = "wielditem",
716 textures = {itemname},
717 visual_size = {x = size, y = size},
718 --collisionbox = {-size, -coll_height, -size,
719 -- size, coll_height, size},
720 selectionbox = {-size, -size, -size, size, size, size},
721 automatic_rotate = math.pi * 0.5 * 0.2 / size,
722 wield_item = self.itemstring,
727 get_staticdata = function(self)
728 return minetest.serialize({
729 itemstring = self.itemstring,
734 on_activate = function(self, staticdata, dtime_s)
735 if string.sub(staticdata, 1, string.len("return")) == "return" then
736 local data = minetest.deserialize(staticdata)
737 if data and type(data) == "table" then
738 self.itemstring = data.itemstring
739 self.count = data.count
742 self.itemstring = staticdata
744 self.object:set_armor_groups({immortal = 1})
745 self.object:set_velocity({x = 0, y = 0, z = 0})
746 self.object:set_acceleration({x = 0, y = 0, z = 0})
750 on_punch = function(self, puncher, time_from_last_punch, tool_capabilities, dir)
751 if not puncher or not puncher:is_player() then
755 if self.itemstring == "utility:nothing" then
761 local pos = self.object:getpos()
762 local pos2 = puncher:getpos()
763 pos2.y = pos2.y + 1.25
765 local obj = minetest.add_item(pos,self.itemstring)
766 local dir = vector.subtract(pos2,pos)
767 vector.multiply(dir,5)
769 self.set_item(self,"utility:nothing")
770 self.object:set_nametag_attributes({
776 obj:setvelocity(vector.new(dir.x,dir.y+3.5,dir.z))
778 print("ERROR FURNACE RELEASED NON ITEM")
783 on_step = function(self, dtime)
784 --set glow if cooking
785 --local glow = def and def.light_source
790 minetest.register_craft({
791 output = "utility:furnace",
793 {"main:cobble", "main:cobble", "main:cobble"},
794 {"main:cobble", "", "main:cobble"},
795 {"main:cobble", "main:cobble", "main:cobble"},