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)
73 obj:get_luaentity().collection_timer = 2
78 for _,object in ipairs(minetest.get_objects_inside_radius(vector.new(pos.x,pos.y+cook_height,pos.z), 0.1)) do
79 if not object:is_player() and object:get_luaentity() and object:get_luaentity().name == "utility:cook" then
80 local pos = object:getpos()
81 local item = object:get_luaentity().itemstring
82 if item ~= "utility:nothing" then
83 local obj = minetest.add_item(pos,item)
84 obj:get_luaentity().collection_timer = 2
89 for _,object in ipairs(minetest.get_objects_inside_radius(vector.new(pos.x,pos.y+output_height,pos.z), 0.1)) do
90 if not object:is_player() and object:get_luaentity() and object:get_luaentity().name == "utility:output" then
91 local pos = object:getpos()
92 local item = object:get_luaentity().itemstring
93 if item ~= "utility:nothing" then
94 local obj = minetest.add_item(pos,item)
95 obj:get_luaentity().collection_timer = 2
102 minetest.register_node("utility:furnace", {
103 description = "Furnace",
105 "furnace_top.png", "furnace_bottom.png",
106 "furnace_side.png", "furnace_side.png",
107 "furnace_side.png", "furnace_front.png"
109 paramtype2 = "facedir",
111 legacy_facedir_simple = true,
112 is_ground_content = false,
113 sounds = main.stoneSound(),
114 on_construct = function(pos)
117 on_destruct = function(pos)
122 minetest.register_craft({
123 output = "utility:furnace",
125 {"main:stone", "main:stone", "main:stone"},
126 {"main:stone", "", "main:stone"},
127 {"main:stone", "main:stone", "main:stone"},
131 --------------------------------------------------------------------------------------------------
134 minetest.get_craft_result({method = "cooking", width = 1, items = srclist}) --check if cookable
136 minetest.get_craft_result({method = "fuel", width = 1, items = fuellist}) --check if fuel
138 space in between = 0.55
144 minetest.register_entity("utility:fuel", {
145 initial_properties = {
148 collide_with_objects = false,
149 collisionbox = {-0.3, -0.3, -0.3, 0.3, 0.3, 0.3},
150 visual = "wielditem",
151 visual_size = {x = 0.6, y = 0.6},
153 spritediv = {x = 1, y = 1},
154 initial_sprite_basepos = {x = 0, y = 0},
165 set_item = function(self, item)
166 local stack = ItemStack(item or self.itemstring)
167 self.itemstring = stack:to_string()
168 --if self.itemstring == "" then
169 -- item not yet known
173 local count = stack:get_count()
176 -- Backwards compatibility: old clients use the texture
177 -- to get the type of the item
178 local itemname = stack:is_known() and stack:get_name() or "unknown"
180 local max_count = stack:get_stack_max()
182 local coll_height = size * 0.75
183 local def = minetest.registered_nodes[itemname]
184 --local glow = def and def.light_source
186 self.object:set_properties({
188 visual = "wielditem",
189 textures = {itemname},
190 visual_size = {x = size, y = size},
191 --collisionbox = {-size, -coll_height, -size,
192 -- size, coll_height, size},
193 selectionbox = {-size, -size, -size, size, size, size},
194 automatic_rotate = math.pi * 0.5 * 0.2 / size,
195 wield_item = self.itemstring,
200 get_staticdata = function(self)
201 return minetest.serialize({
202 itemstring = self.itemstring,
207 on_activate = function(self, staticdata, dtime_s)
208 if string.sub(staticdata, 1, string.len("return")) == "return" then
209 local data = minetest.deserialize(staticdata)
210 if data and type(data) == "table" then
211 self.itemstring = data.itemstring
212 self.count = data.count
215 self.itemstring = staticdata
217 self.object:set_armor_groups({immortal = 1})
218 self.object:set_velocity({x = 0, y = 0, z = 0})
219 self.object:set_acceleration({x = 0, y = 0, z = 0})
223 on_rightclick = function(self, clicker)
225 if not clicker or not clicker:is_player() then
229 local stack = clicker:get_wielded_item()
231 local item = stack:get_name()
232 local count = stack:get_count()
233 if stack:get_name() == "utility:nothing" then
237 --shoot out existing item
238 if self.itemstring ~= item.." "..count and self.itemstring ~= "utility:nothing" then
239 local pos = self.object:getpos()
240 local pos2 = clicker:getpos()
241 pos2.y = pos2.y + 1.25
242 local obj = minetest.add_item(pos,self.itemstring)
243 local dir = vector.subtract(pos2,pos)
244 vector.multiply(dir,5)
247 obj:setvelocity(vector.new(dir.x,dir.y+3.5,dir.z))
248 obj:get_luaentity().collection_timer = 2
250 print("ERROR FURNACE RELEASED NON ITEM")
254 if (item == "" or item == "hand:player") then
255 self.set_item(self,"utility:nothing")
256 self.object:set_nametag_attributes({
263 self.set_item(self, item.." "..count)
265 self.object:set_nametag_attributes({
267 text = minetest.registered_items[item].description.." "..count,
270 stack = stack:clear()
271 clicker:set_wielded_item("")
274 on_punch = function(self, puncher, time_from_last_punch, tool_capabilities, dir)
275 if not puncher or not puncher:is_player() then
279 if self.itemstring == "utility:nothing" then
283 local pos = self.object:getpos()
284 local pos2 = puncher:getpos()
285 pos2.y = pos2.y + 1.25
287 local obj = minetest.add_item(pos,self.itemstring)
288 local dir = vector.subtract(pos2,pos)
289 vector.multiply(dir,5)
291 self.set_item(self,"utility:nothing")
292 self.object:set_nametag_attributes({
298 obj:setvelocity(vector.new(dir.x,dir.y+3.5,dir.z))
299 obj:get_luaentity().collection_timer = 2
301 print("ERROR FURNACE RELEASED NON ITEM")
305 check_cook = function(self)
306 local pos = self.object:getpos()
307 --check the cook timer
308 for _,object in ipairs(minetest.get_objects_inside_radius(vector.new(pos.x,pos.y+0.55,pos.z), 0.1)) do
309 if not object:is_player() and object:get_luaentity() and object:get_luaentity().name == "utility:cook" then
310 local item = object:get_luaentity().itemstring
311 return(minetest.get_craft_result({method = "cooking", width = 1, items = {ItemStack(item)}}).time)
316 cook_item = function(self)
317 local pos = self.object:getpos()
318 for _,object in ipairs(minetest.get_objects_inside_radius(vector.new(pos.x,pos.y+0.55,pos.z), 0.1)) do
319 if not object:is_player() and object:get_luaentity() and object:get_luaentity().name == "utility:cook" then
320 local item = ItemStack(object:get_luaentity().itemstring)
324 local count = object:get_luaentity().count
325 local output = minetest.get_craft_result({method = "cooking", width = 1, items = {ItemStack(item)}}).item
326 local outputitem = output:get_name()
327 local outputcount = output:get_count()
330 local itemname = item:get_name()
334 object:get_luaentity().count = count
336 local pos = self.object:getpos()
339 for _,object2 in ipairs(minetest.get_objects_inside_radius(vector.new(pos.x,pos.y+1.10,pos.z), 0.1)) do
340 if not object2:is_player() and object2:get_luaentity() and object2:get_luaentity().name == "utility:output" then
341 local goal_item = ItemStack(object2:get_luaentity().itemstring)
342 local goal_item_name = goal_item:get_name()
343 local goal_item_count = goal_item:get_count()
345 --cancel out if player took item
346 if outputitem == "" then
350 --add item to output or throw existing item out if not matched
351 if goal_item_name ~= outputitem and goal_item_name ~= "utility:nothing" then
352 local pos2 = object2:get_pos()
353 local obj = minetest.add_item(pos2,object2:get_luaentity().itemstring)
354 local dir = vector.new(math.random(-3,3),math.random(3,6),math.random(-3,3))
355 --dir = vector.multiply(dir,2)
358 obj:setvelocity(vector.new(dir.x,dir.y,dir.z))
359 obj:get_luaentity().collection_timer = 2
361 print("ERROR FURNACE RELEASED NON ITEM")
363 object2:get_luaentity().count = 0
366 object2:get_luaentity().count = object2:get_luaentity().count + outputcount
367 object2:get_luaentity().set_item(object2:get_luaentity(), outputitem.." "..object2:get_luaentity().count)
368 object2:set_nametag_attributes({
370 text = outputitem.." "..object2:get_luaentity().count,
376 --update count and nametag
377 if object:get_luaentity().count == 0 then
378 object:get_luaentity().set_item(object:get_luaentity(), "utility:nothing")
379 object:set_nametag_attributes({
384 object:get_luaentity().set_item(object:get_luaentity(), itemname.." "..count)
385 object:set_nametag_attributes({
387 text = itemname.." "..count,
394 spawn_particles = function(self,time)
395 --print("time:"..time)
396 local pos = self.object:getpos()
397 minetest.add_particlespawner({
398 amount = math.floor(10*time),
400 minpos = vector.new(pos.x-0.3,pos.y-0.3,pos.z-0.3),
401 maxpos = vector.new(pos.x+0.3,pos.y+0.3,pos.z+0.3),
402 minvel = {x=0, y=0.2, z=0},
403 maxvel = {x=0, y=0.5, z=0},
404 minacc = {x=0, y=0, z=0},
405 maxacc = {x=0, y=0, z=0},
410 collisiondetection = false,
412 texture = "flame.png",
416 minetest.add_particlespawner({
417 amount = math.floor(10*time),
419 minpos = vector.new(pos.x-0.3,pos.y+0.3,pos.z-0.3),
420 maxpos = vector.new(pos.x+0.3,pos.y+0.6,pos.z+0.3),
421 minvel = {x=0, y=0.2, z=0},
422 maxvel = {x=0, y=0.7, z=0},
423 minacc = {x=0, y=0, z=0},
424 maxacc = {x=0, y=0, z=0},
429 collisiondetection = false,
431 texture = "smoke.png",
437 --check if item is in the input then cook if so
438 on_step = function(self, dtime)
439 if self.cooking == true then
440 self.cooking_timer = self.cooking_timer - dtime
441 if self.cooking_timer < 0 then
442 self.cooking_timer = 0
448 --check to start cooking countdown
449 if self.cooking == false then
450 local stack = ItemStack(self.itemstring)
451 local fuel = minetest.get_craft_result({method = "fuel", width = 1, items = {stack}}).time
453 local cookie = self.check_cook(self)
455 --print("starting timer")
456 self.spawn_particles(self,fuel)
457 self.cooking_timer = cookie
459 --set up the fuel timer
460 if self.fuel_timer == 0 then
461 self.fuel_timer = fuel
468 if self.fuel_timer >= 0 then
469 self.fuel_timer = self.fuel_timer - dtime
470 --print(self.fuel_timer)
471 elseif self.fuel_timer < 0 then
472 if ItemStack(self.itemstring):get_name() == "utility:nothing" then
475 if self.cooking == false then
478 self.count = self.count - 1
480 local count = self.count
481 local itemname = ItemStack(self.itemstring):get_name()
483 if self.count == 0 then
484 self.set_item(self, "utility:nothing")
485 self.object:set_nametag_attributes({
490 self.set_item(self, itemname.." "..count)
491 self.object:set_nametag_attributes({
493 text = itemname.." "..count,
497 if self.count == 0 then
502 if self.cooking == true then
503 --print("resetting timer")
504 local time = minetest.get_craft_result({method = "fuel", width = 1, items = {ItemStack(self.itemstring)}}).time
505 self.fuel_timer = time
511 ----------------------------------------------------------------------------
513 minetest.register_entity("utility:cook", {
514 initial_properties = {
517 collide_with_objects = false,
518 collisionbox = {-0.3, -0.3, -0.3, 0.3, 0.3, 0.3},
519 visual = "wielditem",
520 visual_size = {x = 0.6, y = 0.6},
522 spritediv = {x = 1, y = 1},
523 initial_sprite_basepos = {x = 0, y = 0},
531 set_item = function(self, item)
532 local stack = ItemStack(item or self.itemstring)
533 self.itemstring = stack:to_string()
534 --if self.itemstring == "" then
535 -- item not yet known
539 local count = stack:get_count()
540 if stack:get_name() == "utility:nothing" then
545 -- Backwards compatibility: old clients use the texture
546 -- to get the type of the item
547 local itemname = stack:is_known() and stack:get_name() or "unknown"
549 local max_count = stack:get_stack_max()
551 local coll_height = size * 0.75
552 local def = minetest.registered_nodes[itemname]
553 --local glow = def and def.light_source
555 self.object:set_properties({
557 visual = "wielditem",
558 textures = {itemname},
559 visual_size = {x = size, y = size},
560 --collisionbox = {-size, -coll_height, -size,
561 -- size, coll_height, size},
562 selectionbox = {-size, -size, -size, size, size, size},
563 automatic_rotate = math.pi * 0.5 * 0.2 / size,
564 wield_item = self.itemstring,
569 get_staticdata = function(self)
570 return minetest.serialize({
571 itemstring = self.itemstring,
576 on_activate = function(self, staticdata, dtime_s)
577 if string.sub(staticdata, 1, string.len("return")) == "return" then
578 local data = minetest.deserialize(staticdata)
579 if data and type(data) == "table" then
580 self.itemstring = data.itemstring
581 self.count = data.count
584 self.itemstring = staticdata
586 self.object:set_armor_groups({immortal = 1})
587 self.object:set_velocity({x = 0, y = 0, z = 0})
588 self.object:set_acceleration({x = 0, y = 0, z = 0})
592 on_rightclick = function(self, clicker)
594 if not clicker or not clicker:is_player() then
598 local stack = clicker:get_wielded_item()
600 local item = stack:get_name()
601 local count = stack:get_count()
603 --shoot out existing item
604 if self.itemstring ~= item.." "..count and self.itemstring ~= "utility:nothing" then
605 local pos = self.object:getpos()
606 local pos2 = clicker:getpos()
607 pos2.y = pos2.y + 1.25
608 local obj = minetest.add_item(pos,self.itemstring)
609 local dir = vector.subtract(pos2,pos)
610 vector.multiply(dir,5)
613 obj:setvelocity(vector.new(dir.x,dir.y+3.5,dir.z))
614 obj:get_luaentity().collection_timer = 2
616 print("ERROR FURNACE RELEASED NON ITEM")
620 if (item == "" or item == "hand:player") then
621 self.set_item(self,"utility:nothing")
622 self.object:set_nametag_attributes({
629 self.set_item(self, item.." "..count)
631 self.object:set_nametag_attributes({
633 text = minetest.registered_items[item].description.." "..count,
636 stack = stack:clear()
637 clicker:set_wielded_item("")
640 on_punch = function(self, puncher, time_from_last_punch, tool_capabilities, dir)
641 if not puncher or not puncher:is_player() then
645 if self.itemstring == "utility:nothing" then
649 local pos = self.object:getpos()
650 local pos2 = puncher:getpos()
651 pos2.y = pos2.y + 1.25
653 local obj = minetest.add_item(pos,self.itemstring)
654 local dir = vector.subtract(pos2,pos)
655 vector.multiply(dir,5)
657 self.set_item(self,"utility:nothing")
658 self.object:set_nametag_attributes({
664 obj:setvelocity(vector.new(dir.x,dir.y+3.5,dir.z))
665 obj:get_luaentity().collection_timer = 2
667 print("ERROR FURNACE RELEASED NON ITEM")
672 on_step = function(self, dtime)
673 --set glow if cooking
674 --local glow = def and def.light_source
677 ----------------------------------------------------------------------------
679 minetest.register_entity("utility:output", {
680 initial_properties = {
683 collide_with_objects = false,
684 collisionbox = {-0.3, -0.3, -0.3, 0.3, 0.3, 0.3},
685 visual = "wielditem",
686 visual_size = {x = 0.6, y = 0.6},
688 spritediv = {x = 1, y = 1},
689 initial_sprite_basepos = {x = 0, y = 0},
697 set_item = function(self, item)
698 local stack = ItemStack(item or self.itemstring)
699 self.itemstring = stack:to_string()
700 --if self.itemstring == "" then
701 -- item not yet known
705 local count = stack:get_count()
706 if stack:get_name() == "utility:nothing" then
711 -- Backwards compatibility: old clients use the texture
712 -- to get the type of the item
713 local itemname = stack:is_known() and stack:get_name() or "unknown"
715 local max_count = stack:get_stack_max()
717 local coll_height = size * 0.75
718 local def = minetest.registered_nodes[itemname]
719 --local glow = def and def.light_source
721 self.object:set_properties({
723 visual = "wielditem",
724 textures = {itemname},
725 visual_size = {x = size, y = size},
726 --collisionbox = {-size, -coll_height, -size,
727 -- size, coll_height, size},
728 selectionbox = {-size, -size, -size, size, size, size},
729 automatic_rotate = math.pi * 0.5 * 0.2 / size,
730 wield_item = self.itemstring,
735 get_staticdata = function(self)
736 return minetest.serialize({
737 itemstring = self.itemstring,
742 on_activate = function(self, staticdata, dtime_s)
743 if string.sub(staticdata, 1, string.len("return")) == "return" then
744 local data = minetest.deserialize(staticdata)
745 if data and type(data) == "table" then
746 self.itemstring = data.itemstring
747 self.count = data.count
750 self.itemstring = staticdata
752 self.object:set_armor_groups({immortal = 1})
753 self.object:set_velocity({x = 0, y = 0, z = 0})
754 self.object:set_acceleration({x = 0, y = 0, z = 0})
758 on_punch = function(self, puncher, time_from_last_punch, tool_capabilities, dir)
759 if not puncher or not puncher:is_player() then
763 if self.itemstring == "utility:nothing" then
769 local pos = self.object:getpos()
770 local pos2 = puncher:getpos()
771 pos2.y = pos2.y + 1.25
773 local obj = minetest.add_item(pos,self.itemstring)
774 local dir = vector.subtract(pos2,pos)
775 vector.multiply(dir,5)
777 self.set_item(self,"utility:nothing")
778 self.object:set_nametag_attributes({
784 obj:setvelocity(vector.new(dir.x,dir.y+3.5,dir.z))
785 obj:get_luaentity().collection_timer = 2
787 print("ERROR FURNACE RELEASED NON ITEM")
792 on_step = function(self, dtime)
793 --set glow if cooking
794 --local glow = def and def.light_source
799 minetest.register_craft({
800 output = "utility:furnace",
802 {"main:cobble", "main:cobble", "main:cobble"},
803 {"main:cobble", "", "main:cobble"},
804 {"main:cobble", "main:cobble", "main:cobble"},