init.lua 9.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358
  1. -- default/furnace.lua
  2. public_furnace = {}
  3. -- support for MT game translation.
  4. local S = default.get_translator
  5. --
  6. -- Formspecs
  7. --
  8. function public_furnace.get_furnace_active_formspec(fuel_percent, item_percent)
  9. return "size[8,8.5]"..
  10. "list[context;src;2.75,0.5;1,1;]"..
  11. "list[context;fuel;2.75,2.5;1,1;]"..
  12. "image[2.75,1.5;1,1;default_furnace_fire_bg.png^[lowpart:"..
  13. (fuel_percent)..":default_furnace_fire_fg.png]"..
  14. "image[3.75,1.5;1,1;gui_furnace_arrow_bg.png^[lowpart:"..
  15. (item_percent)..":gui_furnace_arrow_fg.png^[transformR270]"..
  16. "list[context;dst;4.75,0.96;2,2;]"..
  17. "list[current_player;main;0,4.25;8,1;]"..
  18. "list[current_player;main;0,5.5;8,3;8]"..
  19. "listring[context;dst]"..
  20. "listring[current_player;main]"..
  21. "listring[context;src]"..
  22. "listring[current_player;main]"..
  23. "listring[context;fuel]"..
  24. "listring[current_player;main]"..
  25. default.get_hotbar_bg(0, 4.25)
  26. end
  27. function public_furnace.get_furnace_inactive_formspec()
  28. return "size[8,8.5]"..
  29. "list[context;src;2.75,0.5;1,1;]"..
  30. "list[context;fuel;2.75,2.5;1,1;]"..
  31. "image[2.75,1.5;1,1;default_furnace_fire_bg.png]"..
  32. "image[3.75,1.5;1,1;gui_furnace_arrow_bg.png^[transformR270]"..
  33. "list[context;dst;4.75,0.96;2,2;]"..
  34. "list[current_player;main;0,4.25;8,1;]"..
  35. "list[current_player;main;0,5.5;8,3;8]"..
  36. "listring[context;dst]"..
  37. "listring[current_player;main]"..
  38. "listring[context;src]"..
  39. "listring[current_player;main]"..
  40. "listring[context;fuel]"..
  41. "listring[current_player;main]"..
  42. default.get_hotbar_bg(0, 4.25)
  43. end
  44. --
  45. -- Node callback functions that are the same for active and inactive furnace
  46. --
  47. local function can_dig(pos, player)
  48. local meta = minetest.get_meta(pos);
  49. local inv = meta:get_inventory()
  50. return inv:is_empty("fuel") and inv:is_empty("dst") and inv:is_empty("src")
  51. end
  52. local function allow_metadata_inventory_put(pos, listname, index, stack, player)
  53. local meta = minetest.get_meta(pos)
  54. local inv = meta:get_inventory()
  55. if listname == "fuel" then
  56. if minetest.get_craft_result({method="fuel", width=1, items={stack}}).time ~= 0 then
  57. if inv:is_empty("src") then
  58. meta:set_string("infotext", S("Furnace is empty"))
  59. end
  60. return stack:get_count()
  61. else
  62. return 0
  63. end
  64. elseif listname == "src" then
  65. return stack:get_count()
  66. elseif listname == "dst" then
  67. return 0
  68. end
  69. end
  70. local function allow_metadata_inventory_move(pos, from_list, from_index, to_list, to_index, count, player)
  71. local meta = minetest.get_meta(pos)
  72. local inv = meta:get_inventory()
  73. local stack = inv:get_stack(from_list, from_index)
  74. return allow_metadata_inventory_put(pos, to_list, to_index, stack, player)
  75. end
  76. local function allow_metadata_inventory_take(pos, listname, index, stack, player)
  77. return stack:get_count()
  78. end
  79. local function swap_node(pos, name)
  80. local node = minetest.get_node(pos)
  81. if node.name == name then
  82. return
  83. end
  84. node.name = name
  85. minetest.swap_node(pos, node)
  86. end
  87. local function furnace_node_timer(pos, elapsed)
  88. --
  89. -- Initialize metadata
  90. --
  91. local meta = minetest.get_meta(pos)
  92. local fuel_time = meta:get_float("fuel_time") or 0
  93. local src_time = meta:get_float("src_time") or 0
  94. local fuel_totaltime = meta:get_float("fuel_totaltime") or 0
  95. local inv = meta:get_inventory()
  96. local srclist, fuellist
  97. local dst_full = false
  98. local cookable, cooked
  99. local fuel
  100. local update = true
  101. while elapsed > 0 and update do
  102. update = false
  103. srclist = inv:get_list("src")
  104. fuellist = inv:get_list("fuel")
  105. --
  106. -- Cooking
  107. --
  108. -- Check if we have cookable content
  109. local aftercooked
  110. cooked, aftercooked = minetest.get_craft_result({method = "cooking", width = 1, items = srclist})
  111. cookable = cooked.time ~= 0
  112. local el = math.min(elapsed, fuel_totaltime - fuel_time)
  113. if cookable then -- fuel lasts long enough, adjust el to cooking duration
  114. el = math.min(el, cooked.time - src_time)
  115. end
  116. -- Check if we have enough fuel to burn
  117. if fuel_time < fuel_totaltime then
  118. -- The furnace is currently active and has enough fuel
  119. fuel_time = fuel_time + el
  120. -- If there is a cookable item then check if it is ready yet
  121. if cookable then
  122. src_time = src_time + el
  123. if src_time >= cooked.time then
  124. -- Place result in dst list if possible
  125. if inv:room_for_item("dst", cooked.item) then
  126. inv:add_item("dst", cooked.item)
  127. inv:set_stack("src", 1, aftercooked.items[1])
  128. src_time = src_time - cooked.time
  129. update = true
  130. else
  131. dst_full = true
  132. end
  133. else
  134. -- Item could not be cooked: probably missing fuel
  135. update = true
  136. end
  137. end
  138. else
  139. -- Furnace ran out of fuel
  140. if cookable then
  141. -- We need to get new fuel
  142. local afterfuel
  143. fuel, afterfuel = minetest.get_craft_result({method = "fuel", width = 1, items = fuellist})
  144. if fuel.time == 0 then
  145. -- No valid fuel in fuel list
  146. fuel_totaltime = 0
  147. src_time = 0
  148. else
  149. -- Take fuel from fuel list
  150. inv:set_stack("fuel", 1, afterfuel.items[1])
  151. -- Put replacements in dst list or drop them on the furnace.
  152. local replacements = fuel.replacements
  153. if replacements[1] then
  154. local leftover = inv:add_item("dst", replacements[1])
  155. if not leftover:is_empty() then
  156. local above = vector.new(pos.x, pos.y + 1, pos.z)
  157. local drop_pos = minetest.find_node_near(above, 1, {"air"}) or above
  158. minetest.item_drop(replacements[1], nil, drop_pos)
  159. end
  160. end
  161. update = true
  162. fuel_totaltime = fuel.time + (fuel_totaltime - fuel_time)
  163. end
  164. else
  165. -- We don't need to get new fuel since there is no cookable item
  166. fuel_totaltime = 0
  167. src_time = 0
  168. end
  169. fuel_time = 0
  170. end
  171. elapsed = elapsed - el
  172. end
  173. if fuel and fuel_totaltime > fuel.time then
  174. fuel_totaltime = fuel.time
  175. end
  176. if srclist and srclist[1]:is_empty() then
  177. src_time = 0
  178. end
  179. --
  180. -- Update formspec, infotext and node
  181. --
  182. local formspec
  183. local item_state
  184. local item_percent = 0
  185. if cookable then
  186. item_percent = math.floor(src_time / cooked.time * 100)
  187. if dst_full then
  188. item_state = S("100% (output full)")
  189. else
  190. item_state = S("@1%", item_percent)
  191. end
  192. else
  193. if srclist and not srclist[1]:is_empty() then
  194. item_state = S("Not cookable")
  195. else
  196. item_state = S("Empty")
  197. end
  198. end
  199. local fuel_state = S("Empty")
  200. local active = false
  201. local result = false
  202. if fuel_totaltime ~= 0 then
  203. active = true
  204. local fuel_percent = 100 - math.floor(fuel_time / fuel_totaltime * 100)
  205. fuel_state = S("@1%", fuel_percent)
  206. formspec = public_furnace.get_furnace_active_formspec(fuel_percent, item_percent)
  207. swap_node(pos, "public_furnace:public_furnace_active")
  208. -- make sure timer restarts automatically
  209. result = true
  210. else
  211. if fuellist and not fuellist[1]:is_empty() then
  212. fuel_state = S("@1%", 0)
  213. end
  214. formspec = public_furnace.get_furnace_inactive_formspec()
  215. swap_node(pos, "public_furnace:public_furnace")
  216. -- stop timer on the inactive furnace
  217. minetest.get_node_timer(pos):stop()
  218. end
  219. local infotext
  220. if active then
  221. infotext = S("Furnace active")
  222. else
  223. infotext = S("Furnace inactive")
  224. end
  225. infotext = infotext .. "\n" .. S("(Item: @1; Fuel: @2)", item_state, fuel_state)
  226. --
  227. -- Set meta values
  228. --
  229. meta:set_float("fuel_totaltime", fuel_totaltime)
  230. meta:set_float("fuel_time", fuel_time)
  231. meta:set_float("src_time", src_time)
  232. meta:set_string("formspec", formspec)
  233. meta:set_string("infotext", infotext)
  234. return result
  235. end
  236. --
  237. -- Node definitions
  238. --
  239. minetest.register_node("public_furnace:public_furnace", {
  240. description = S("Public Furnace"),
  241. tiles = {
  242. "default_furnace_top.png", "default_furnace_bottom.png",
  243. "default_furnace_side.png", "default_furnace_side.png",
  244. "default_furnace_side.png", "default_furnace_front.png"
  245. },
  246. paramtype2 = "facedir",
  247. groups = {cracky=2},
  248. legacy_facedir_simple = true,
  249. is_ground_content = false,
  250. sounds = default.node_sound_stone_defaults(),
  251. can_dig = can_dig,
  252. on_timer = furnace_node_timer,
  253. on_construct = function(pos)
  254. local meta = minetest.get_meta(pos)
  255. local inv = meta:get_inventory()
  256. inv:set_size('src', 1)
  257. inv:set_size('fuel', 1)
  258. inv:set_size('dst', 4)
  259. furnace_node_timer(pos, 0)
  260. end,
  261. on_metadata_inventory_move = function(pos)
  262. minetest.get_node_timer(pos):start(1.0)
  263. end,
  264. on_metadata_inventory_put = function(pos)
  265. -- start timer function, it will sort out whether furnace can burn or not.
  266. minetest.get_node_timer(pos):start(1.0)
  267. end,
  268. on_blast = function(pos)
  269. local drops = {}
  270. default.get_inventory_drops(pos, "src", drops)
  271. default.get_inventory_drops(pos, "fuel", drops)
  272. default.get_inventory_drops(pos, "dst", drops)
  273. drops[#drops+1] = "public_furnace:public_furnace"
  274. minetest.remove_node(pos)
  275. return drops
  276. end,
  277. allow_metadata_inventory_put = allow_metadata_inventory_put,
  278. allow_metadata_inventory_move = allow_metadata_inventory_move,
  279. allow_metadata_inventory_take = allow_metadata_inventory_take,
  280. })
  281. minetest.register_node("public_furnace:public_furnace_active", {
  282. description = S("Furnace"),
  283. tiles = {
  284. "default_furnace_top.png", "default_furnace_bottom.png",
  285. "default_furnace_side.png", "default_furnace_side.png",
  286. "default_furnace_side.png",
  287. {
  288. image = "default_furnace_front_active.png",
  289. backface_culling = false,
  290. animation = {
  291. type = "vertical_frames",
  292. aspect_w = 16,
  293. aspect_h = 16,
  294. length = 1.5
  295. },
  296. }
  297. },
  298. paramtype2 = "facedir",
  299. light_source = 8,
  300. drop = "public_furnace:public_furnace",
  301. groups = {cracky=2, not_in_creative_inventory=1},
  302. legacy_facedir_simple = true,
  303. is_ground_content = false,
  304. sounds = default.node_sound_stone_defaults(),
  305. on_timer = furnace_node_timer,
  306. can_dig = can_dig,
  307. allow_metadata_inventory_put = allow_metadata_inventory_put,
  308. allow_metadata_inventory_move = allow_metadata_inventory_move,
  309. allow_metadata_inventory_take = allow_metadata_inventory_take,
  310. })
  311. minetest.register_craft({
  312. output = "public_furnace:public_furnace",
  313. type = "shapeless",
  314. recipe = {"default:furnace"}
  315. })