autofurnace.lua 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552
  1. local function swap_node(pos, name)
  2. local node = minetest.get_node(pos)
  3. if node.name == name then
  4. return
  5. end
  6. node.name = name
  7. minetest.swap_node(pos, node)
  8. end
  9. local function get_af_active_formspec(fuel_percent, item_percent)
  10. return "size[8,8.5]"..
  11. default.gui_bg..
  12. default.gui_bg_img..
  13. default.gui_slots..
  14. -- "list[context;src;2.75,0.5;1,1;]"..
  15. "list[context;fuel;.75,.5;2,4;]"..
  16. "image[2.75,1.5;1,1;default_furnace_fire_bg.png^[lowpart:"..
  17. (100-fuel_percent)..":default_furnace_fire_fg.png]"..
  18. "image[3.75,1.5;1,1;gui_furnace_arrow_bg.png^[lowpart:"..
  19. (item_percent)..":gui_furnace_arrow_fg.png^[transformR270]"..
  20. -- "list[context;dst;4.75,0.96;2,2;]"..
  21. "list[current_player;main;0,4.25;8,1;]"..
  22. "list[current_player;main;0,5.5;8,3;8]"..
  23. -- "listring[context;dst]"..
  24. -- "listring[current_player;main]"..
  25. -- "listring[context;src]"..
  26. -- "listring[current_player;main]"..
  27. -- "listring[context;fuel]"..
  28. -- "listring[current_player;main]"..
  29. default.get_hotbar_bg(0, 4.25)
  30. end
  31. local function grab_fuel(inv)
  32. local list = inv:get_list("fuel")
  33. for i,st in ipairs(list) do
  34. --print(st:get_name())
  35. local fuel, remains
  36. fuel, remains = minetest.get_craft_result({
  37. method = "fuel",
  38. width = 1,
  39. items = {
  40. ItemStack(st:get_name())
  41. },
  42. })
  43. if fuel.time > 0 then
  44. -- Take fuel from fuel list
  45. st:take_item()
  46. inv:set_stack("fuel", i, st)
  47. return fuel.time
  48. end
  49. end
  50. return 0 -- no fuel found
  51. end
  52. -- gets a new item to cook
  53. local function grab_raw_item(pos)
  54. local meta = minetest.get_meta(pos)
  55. local inv = meta:get_inventory()
  56. local list = inv:get_list("main")
  57. for i,st in ipairs(list) do
  58. local cooked
  59. cooked, remains = minetest.get_craft_result({method = "cooking", width = 1, items = {ItemStack(st:get_name())}})
  60. if cooked.time ~= 0 then
  61. st:take_item()
  62. inv:set_stack("main", i, st)
  63. return cooked
  64. end
  65. end
  66. return nil -- no cookable items found
  67. end
  68. -- returns false if the container overflowed
  69. local function put_item(pos, item)
  70. local meta = minetest.get_meta(pos)
  71. if meta == nil then
  72. --print("af: wasting item for lack of output")
  73. return
  74. end
  75. local inv = meta:get_inventory()
  76. if inv == nil then
  77. --print("af: wasting item for lack of output inventory")
  78. return
  79. end
  80. local rem = inv:add_item("main", item)
  81. if rem ~= nil and rem:get_count() > 0 then
  82. return false
  83. end
  84. return true
  85. end
  86. local function af_on_timer(pos, elapsed)
  87. local meta = minetest.get_meta(pos)
  88. local fuel_time = meta:get_float("fuel_time") or 0
  89. local fuel_burned = meta:get_float("fuel_burned") or 0
  90. local cook_time_remaining = meta:get_float("cook_time_remaining") or 0
  91. local cook_item = meta:get_string("cook_item") or ""
  92. local inv = meta:get_inventory()
  93. local can_cook = false
  94. local burned = elapsed
  95. local turn_off = false
  96. --print("\n\naf timer")
  97. --print("fuel_burned: " .. fuel_burned)
  98. --print("fuel_time: " .. fuel_time)
  99. -- if fuel_burned <= fuel_time or fuel_time == 0 then
  100. -- -- use fuel
  101. -- print("af fuel")
  102. if fuel_time > 0 and fuel_burned + elapsed < fuel_time then
  103. fuel_burned = fuel_burned + elapsed
  104. meta:set_float("fuel_burned", fuel_burned + elapsed)
  105. else
  106. local t = grab_fuel(inv)
  107. if t <= 0 then -- out of fuel
  108. --print("out of fuel")
  109. meta:set_float("fuel_time", 0)
  110. meta:set_float("fuel_burned", 0)
  111. burned = fuel_time - fuel_burned
  112. turn_off = true
  113. else
  114. -- roll into the next period
  115. fuel_burned = elapsed - (fuel_time - fuel_burned)
  116. fuel_time = t
  117. --print("fuel remaining: " .. (fuel_time - fuel_burned))
  118. meta:set_float("fuel_time", fuel_time)
  119. meta:set_float("fuel_burned", fuel_burned)
  120. end
  121. end
  122. -- end
  123. if cook_item == "" then
  124. local cooked = grab_raw_item({x=pos.x, y=pos.y+1, z=pos.z})
  125. if cooked ~= nil then
  126. cook_item = cooked.item:to_table()
  127. cook_time_remaining = cooked.time
  128. --print(cook_item)
  129. meta:set_string("cook_item", minetest.serialize(cook_item))
  130. meta:set_float("cook_time_remaining", cooked.time)
  131. else
  132. -- nothing to cook, carry on
  133. --print("nothing to cook")
  134. cook_item = nil
  135. meta:set_string("cook_item", "")
  136. end
  137. else
  138. --print(cook_item)
  139. cook_item = minetest.deserialize(cook_item)
  140. end
  141. if cook_item ~= nil and burned > 0 then
  142. local remain = cook_time_remaining - burned
  143. --print("remain: ".. remain);
  144. if remain > 0 then
  145. meta:set_float("cook_time_remaining", remain)
  146. else
  147. --print("finished")
  148. -- cooking is finished
  149. put_item({x=pos.x, y=pos.y - 1, z=pos.z}, cook_item.name .. " " .. (cook_item.count or 1))
  150. meta:set_string("cook_item", "")
  151. meta:set_float("cook_time_remaining", 0)
  152. end
  153. end
  154. if turn_off then
  155. swap_node(pos, "machines:autofurnace_off")
  156. return
  157. end
  158. fuel_pct = math.floor((fuel_burned * 100) / fuel_time)
  159. -- item_pct = math.floor((fuel_burned * 100) / fuel_time)
  160. meta:set_string("formspec", get_af_active_formspec(fuel_pct, 0))
  161. meta:set_string("infotext", "Fuel: " .. fuel_pct)
  162. minetest.get_node_timer(pos):start(1.0)
  163. --[[
  164. local cookable, cooked
  165. local fuel
  166. local update = true
  167. while elapsed > 0 and update do
  168. update = false
  169. --srclist = inv:get_list("src")
  170. fuellist = inv:get_list("fuel")
  171. --
  172. -- Cooking
  173. --
  174. -- Check if we have cookable content
  175. local aftercooked
  176. cooked, aftercooked = minetest.get_craft_result({method = "cooking", width = 1, items = srclist})
  177. cookable = cooked.time ~= 0
  178. local el = math.min(elapsed, fuel_totaltime - fuel_time)
  179. if cookable then -- fuel lasts long enough, adjust el to cooking duration
  180. el = math.min(el, cooked.time - src_time)
  181. end
  182. -- Check if we have enough fuel to burn
  183. if fuel_time < fuel_totaltime then
  184. -- The furnace is currently active and has enough fuel
  185. fuel_time = fuel_time + el
  186. -- If there is a cookable item then check if it is ready yet
  187. if cookable then
  188. src_time = src_time + el
  189. if src_time >= cooked.time then
  190. -- Place result in dst list if possible
  191. if inv:room_for_item("dst", cooked.item) then
  192. inv:add_item("dst", cooked.item)
  193. inv:set_stack("src", 1, aftercooked.items[1])
  194. src_time = src_time - cooked.time
  195. update = true
  196. end
  197. else
  198. -- Item could not be cooked: probably missing fuel
  199. update = true
  200. end
  201. end
  202. else
  203. -- Furnace ran out of fuel
  204. if cookable then
  205. -- We need to get new fuel
  206. local afterfuel
  207. fuel, afterfuel = minetest.get_craft_result({method = "fuel", width = 1, items = fuellist})
  208. if fuel.time == 0 then
  209. -- No valid fuel in fuel list
  210. fuel_totaltime = 0
  211. src_time = 0
  212. else
  213. -- Take fuel from fuel list
  214. inv:set_stack("fuel", 1, afterfuel.items[1])
  215. update = true
  216. fuel_totaltime = fuel.time + (fuel_totaltime - fuel_time)
  217. end
  218. else
  219. -- We don't need to get new fuel since there is no cookable item
  220. fuel_totaltime = 0
  221. src_time = 0
  222. end
  223. fuel_time = 0
  224. end
  225. elapsed = elapsed - el
  226. end
  227. if fuel and fuel_totaltime > fuel.time then
  228. fuel_totaltime = fuel.time
  229. end
  230. if srclist[1]:is_empty() then
  231. src_time = 0
  232. end
  233. --
  234. -- Update formspec, infotext and node
  235. --
  236. local formspec
  237. local item_state
  238. local item_percent = 0
  239. if cookable then
  240. item_percent = math.floor(src_time / cooked.time * 100)
  241. if item_percent > 100 then
  242. item_state = "100% (output full)"
  243. else
  244. item_state = item_percent .. "%"
  245. end
  246. else
  247. if srclist[1]:is_empty() then
  248. item_state = "Empty"
  249. else
  250. item_state = "Not cookable"
  251. end
  252. end
  253. local fuel_state = "Empty"
  254. local active = "inactive"
  255. local result = false
  256. if fuel_totaltime ~= 0 then
  257. active = "active"
  258. local fuel_percent = math.floor(fuel_time / fuel_totaltime * 100)
  259. fuel_state = fuel_percent .. "%"
  260. formspec = default.get_furnace_active_formspec(fuel_percent, item_percent)
  261. swap_node(pos, "default:furnace_active")
  262. -- make sure timer restarts automatically
  263. result = true
  264. else
  265. if not fuellist[1]:is_empty() then
  266. fuel_state = "0%"
  267. end
  268. formspec = default.get_furnace_inactive_formspec()
  269. swap_node(pos, "default:furnace")
  270. -- stop timer on the inactive furnace
  271. minetest.get_node_timer(pos):stop()
  272. end
  273. local infotext = "Furnace " .. active .. "\n(Item: " .. item_state ..
  274. "; Fuel: " .. fuel_state .. ")"
  275. --
  276. -- Set meta values
  277. --
  278. meta:set_float("fuel_totaltime", fuel_totaltime)
  279. meta:set_float("fuel_time", fuel_time)
  280. meta:set_float("src_time", src_time)
  281. return result ]]
  282. end
  283. function get_af_inactive_formspec()
  284. return "size[8,8.5]"..
  285. default.gui_bg..
  286. default.gui_bg_img..
  287. default.gui_slots..
  288. -- "list[context;src;2.75,0.5;1,1;]"..
  289. "list[context;fuel;2.75,2.5;2,2;]"..
  290. "image[2.75,1.5;1,1;default_furnace_fire_bg.png]"..
  291. -- "image[3.75,1.5;1,1;gui_furnace_arrow_bg.png^[transformR270]"..
  292. -- "list[context;dst;4.75,0.96;2,2;]"..
  293. "list[current_player;main;0,4.25;8,1;]"..
  294. "list[current_player;main;0,5.5;8,3;8]"..
  295. "listring[context;dst]"..
  296. "listring[current_player;main]"..
  297. "listring[context;src]"..
  298. "listring[current_player;main]"..
  299. "listring[context;fuel]"..
  300. "listring[current_player;main]"..
  301. default.get_hotbar_bg(0, 4.25)
  302. end
  303. minetest.register_node("machines:autofurnace", {
  304. description = "Autofurnace",
  305. tiles = {
  306. "default_bronze_block.png", "default_bronze_block.png",
  307. "default_bronze_block.png", "default_bronze_block.png",
  308. "default_bronze_block.png",
  309. {
  310. image = "default_furnace_front_active.png",
  311. backface_culling = false,
  312. animation = {
  313. type = "vertical_frames",
  314. aspect_w = 16,
  315. aspect_h = 16,
  316. length = 1.5
  317. },
  318. }
  319. },
  320. paramtype2 = "facedir",
  321. groups = {cracky=2},
  322. legacy_facedir_simple = true,
  323. is_ground_content = false,
  324. sounds = default.node_sound_stone_defaults(),
  325. stack_max = 1,
  326. can_dig = can_dig,
  327. on_timer = af_on_timer,
  328. on_construct = function(pos)
  329. local meta = minetest.get_meta(pos)
  330. meta:set_string("formspec", get_af_inactive_formspec())
  331. local inv = meta:get_inventory()
  332. inv:set_size('fuel', 4)
  333. minetest.get_node_timer(pos):start(1.0)
  334. end,
  335. on_metadata_inventory_move = function(pos)
  336. minetest.get_node_timer(pos):start(1.0)
  337. end,
  338. on_metadata_inventory_put = function(pos)
  339. -- start timer function, it will sort out whether furnace can burn or not.
  340. minetest.get_node_timer(pos):start(1.0)
  341. end,
  342. on_punch = function(pos)
  343. swap_node(pos, "machines:autofurnace_off")
  344. end,
  345. -- on_blast = function(pos)
  346. -- local drops = {}
  347. -- default.get_inventory_drops(pos, "src", drops)
  348. -- default.get_inventory_drops(pos, "fuel", drops)
  349. -- default.get_inventory_drops(pos, "dst", drops)
  350. -- drops[#drops+1] = "machines:machine"
  351. -- minetest.remove_node(pos)
  352. -- return drops
  353. -- end,
  354. allow_metadata_inventory_put = allow_metadata_inventory_put,
  355. allow_metadata_inventory_move = allow_metadata_inventory_move,
  356. allow_metadata_inventory_take = allow_metadata_inventory_take,
  357. })
  358. minetest.register_node("machines:autofurnace_off", {
  359. description = "Autofurnace (off)",
  360. tiles = {
  361. "default_bronze_block.png", "default_bronze_block.png",
  362. "default_bronze_block.png", "default_bronze_block.png",
  363. "default_bronze_block.png", "default_furnace_front.png"
  364. },
  365. paramtype2 = "facedir",
  366. groups = {cracky=2},
  367. legacy_facedir_simple = true,
  368. is_ground_content = false,
  369. sounds = default.node_sound_stone_defaults(),
  370. stack_max = 1,
  371. can_dig = can_dig,
  372. --on_timer = af_node_timer,
  373. on_construct = function(pos)
  374. local meta = minetest.get_meta(pos)
  375. meta:set_string("formspec", get_af_inactive_formspec())
  376. local inv = meta:get_inventory()
  377. inv:set_size('fuel', 4)
  378. --minetest.get_node_timer(pos):start(1.0)
  379. end,
  380. on_metadata_inventory_move = function(pos)
  381. --minetest.get_node_timer(pos):start(1.0)
  382. end,
  383. on_metadata_inventory_put = function(pos)
  384. -- start timer function, it will sort out whether furnace can burn or not.
  385. --minetest.get_node_timer(pos):start(1.0)
  386. end,
  387. on_punch = function(pos)
  388. swap_node(pos, "machines:autofurnace")
  389. minetest.get_node_timer(pos):start(1.0)
  390. end,
  391. -- on_blast = function(pos)
  392. -- local drops = {}
  393. -- default.get_inventory_drops(pos, "src", drops)
  394. -- default.get_inventory_drops(pos, "fuel", drops)
  395. -- default.get_inventory_drops(pos, "dst", drops)
  396. -- drops[#drops+1] = "machines:machine"
  397. -- minetest.remove_node(pos)
  398. -- return drops
  399. -- end,
  400. allow_metadata_inventory_put = allow_metadata_inventory_put,
  401. allow_metadata_inventory_move = allow_metadata_inventory_move,
  402. allow_metadata_inventory_take = allow_metadata_inventory_take,
  403. })
  404. minetest.register_craft({
  405. output = 'machines:autofurnace_off',
  406. recipe = {
  407. {'default:bronze_ingot', 'default:bronze_ingot', 'default:bronze_ingot'},
  408. {'default:bronze_ingot', 'default:flint', 'default:bronze_ingot'},
  409. {'default:bronze_ingot', 'default:bronze_ingot', 'default:bronze_ingot'},
  410. }
  411. })