kiln_node_callbacks.lua 8.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361
  1. local coal = minetest.registered_aliases["coal"]
  2. local COAL_HEAT = 10
  3. local KILN_TIMER_LENGTH = 0.2
  4. local update_infotext =
  5. dofile(minetest.get_modpath("kilns") .. "/infotext.lua")
  6. --the act of smelting
  7. ------------------------------------------------------------------------
  8. --consumes coal and increases heat if heat is <= 0,
  9. --returns new heat, fuel is passed as a reference so it's not returned
  10. local function refuel_if_necessary(heat, fuel)
  11. if heat <= 0 and not fuel:is_empty()
  12. then
  13. heat = COAL_HEAT
  14. fuel:take_item()
  15. end
  16. return heat
  17. end
  18. --looks up a smelting recipe for an input itemstack and returns
  19. --the result or false if there is no recipe for the item stack.
  20. local function get_smelt_result(input_stack)
  21. local input = {method = "cooking", items = {input_stack}}
  22. local result = minetest.get_craft_result(input)
  23. if not result.item:is_empty()
  24. then
  25. return result
  26. else
  27. return false
  28. end
  29. end
  30. local chimney_particle_prototype =
  31. {
  32. amount = 20 * KILN_TIMER_LENGTH,
  33. time = KILN_TIMER_LENGTH,
  34. minvel = {x = -0.2, y = 0.2, z = -0.2},
  35. maxvel = {x = 0.2, y = 1, z = 0.2},
  36. minexptime = 3,
  37. maxexptime = 5,
  38. minsize = 1,
  39. maxsize = 3,
  40. }
  41. local function spawn_chimney_particles(pos)
  42. pos.y = pos.y + 0.5
  43. local smokedef_white = {}
  44. local smokedef_black = {}
  45. for k, v in pairs(chimney_particle_prototype)
  46. do
  47. smokedef_white[k] = v
  48. smokedef_black[k] = v
  49. end
  50. smokedef_white.minpos = pos
  51. smokedef_white.maxpos = pos
  52. smokedef_black.minpos = pos
  53. smokedef_black.maxpos = pos
  54. smokedef_white.texture = "smoke_puff_white.png"
  55. smokedef_black.texture = "smoke_puff_black.png"
  56. minetest.add_particlespawner(smokedef_white)
  57. minetest.add_particlespawner(smokedef_black)
  58. end
  59. local smoke_puff_particle_prototype =
  60. {
  61. amount = 30,
  62. time = 0.05,
  63. minvel = {x = -1, y = 0.2, z = -1},
  64. maxvel = {x = 1, y = 0.5, z = 1},
  65. minexptime = 0.3,
  66. maxexptime = 1,
  67. minsize = 1,
  68. maxsize = 3,
  69. }
  70. local function spawn_smoke_puff_particles(pos)
  71. pos.y = pos.y + 0.5
  72. local smokedef_white = {}
  73. local smokedef_black = {}
  74. for k, v in pairs(smoke_puff_particle_prototype)
  75. do
  76. smokedef_white[k] = v
  77. smokedef_black[k] = v
  78. end
  79. smokedef_white.minpos = pos
  80. smokedef_white.maxpos = pos
  81. smokedef_black.minpos = pos
  82. smokedef_black.maxpos = pos
  83. smokedef_white.texture = "smoke_puff_white.png"
  84. smokedef_black.texture = "smoke_puff_black.png"
  85. minetest.add_particlespawner(smokedef_white)
  86. minetest.add_particlespawner(smokedef_black)
  87. end
  88. local function on_timer(pos, elapsed)
  89. local meta = minetest.get_meta(pos)
  90. local inv = meta:get_inventory()
  91. local heat = meta:get_float("heat") - elapsed
  92. local progress = meta:get_float("progress") - elapsed
  93. --the smelting result possibly won't fit if the recipe is changed
  94. --inbetween sessions but I don't care enough to fix it.
  95. local fuel = inv:get_stack("fuel", 1)
  96. local input = inv:get_stack("in", 1)
  97. local output = inv:get_stack("out", 1)
  98. --should smelt
  99. if not input:is_empty()
  100. then
  101. heat = refuel_if_necessary(heat, fuel)
  102. if heat > 0
  103. then
  104. progress = progress + 2 * elapsed
  105. local recipe = get_smelt_result(input)
  106. if recipe and progress >= recipe.time --done one item
  107. then
  108. spawn_smoke_puff_particles(pos)
  109. progress = 0
  110. local rest = output:add_item(recipe.item)
  111. local consume = input:take_item()
  112. --if output stack is full, undo smelting
  113. if not rest:is_empty()
  114. then
  115. input:add_item(consume)
  116. end
  117. end
  118. end
  119. end
  120. --write back possibly changed values
  121. local fuel = inv:set_stack("fuel", 1, fuel)
  122. local input = inv:set_stack("in", 1, input)
  123. local output = inv:set_stack("out", 1, output)
  124. meta:set_float("heat", heat)
  125. meta:set_float("progress", progress)
  126. local continue = heat > 0 or progress > 0
  127. update_infotext(meta, continue)
  128. if not continue
  129. then
  130. local node = minetest.get_node(pos)
  131. local n =
  132. {
  133. name = "kilns:kiln_off",
  134. param1 = node.param1,
  135. param2 = node.param2
  136. }
  137. minetest.swap_node(pos, n)
  138. else
  139. spawn_chimney_particles(pos)
  140. end
  141. return continue
  142. end
  143. --player interaction with kiln inventory
  144. ------------------------------------------------------------------------
  145. --returning items from the kiln's inventory
  146. -----------------------------------------------------
  147. local function kiln_get_return_stack(kiln_inv)
  148. local priority_order = {"out", "in", "fuel",}
  149. for i, list in ipairs(priority_order)
  150. do
  151. local itemstack = kiln_inv:get_stack(list, 1)
  152. if not itemstack:is_empty()
  153. then
  154. return itemstack, list
  155. end
  156. end
  157. end
  158. local function kiln_item_return_wholestack(kiln_inv, player_inv)
  159. local stack, retlist = kiln_get_return_stack(kiln_inv)
  160. if not stack
  161. then
  162. --Empty
  163. return
  164. end
  165. local overflow = player_inv:add_item("main", stack)
  166. kiln_inv:set_stack(retlist, 1, overflow)
  167. end
  168. local function kiln_item_return_single(kiln_inv, player_inv)
  169. local stack, retlist = kiln_get_return_stack(kiln_inv)
  170. if not stack
  171. then
  172. --Empty
  173. return
  174. end
  175. local overflow = player_inv:add_item("main", stack:take_item(1))
  176. stack:add_item(overflow)
  177. kiln_inv:set_stack(retlist, 1, stack)
  178. end
  179. --punch to return
  180. local function on_punch(pos, node, puncher, pointed_thing)
  181. if not puncher
  182. then
  183. return true
  184. end
  185. local meta = minetest.get_meta(pos)
  186. local inv = meta:get_inventory()
  187. local wholestack = puncher:get_player_control().aux1
  188. local puncherinv = puncher:get_inventory()
  189. if wholestack
  190. then
  191. kiln_item_return_wholestack(inv, puncherinv)
  192. else
  193. kiln_item_return_single(inv, puncherinv)
  194. end
  195. update_infotext(meta, false)
  196. return true
  197. end
  198. --add items to the kiln inventory
  199. -----------------------------------------------------
  200. local function start_timer_if_needed(pos, inv)
  201. local timer = minetest.get_node_timer(pos)
  202. if timer:is_started()
  203. then
  204. --already smelting
  205. return
  206. end
  207. local input = inv:get_stack("in", 1)
  208. if input:is_empty()
  209. then
  210. return
  211. end
  212. local fuel = inv:get_stack("fuel", 1)
  213. if fuel:is_empty()
  214. then
  215. return
  216. end
  217. --we now know that input and fuel are not empty and that the kiln
  218. --is not burning already, so we can start smelting
  219. timer:start(KILN_TIMER_LENGTH)
  220. return true
  221. end
  222. local function can_put(to_put, input_stack, output_stack)
  223. local smelt_result = get_smelt_result(to_put)
  224. if not smelt_result
  225. then
  226. return false
  227. end
  228. return (input_stack:is_empty() or
  229. to_put:get_name() == input_stack:get_name()) and
  230. (output_stack:is_empty() or
  231. smelt_result.item:get_name() == output_stack:get_name())
  232. end
  233. local function kiln_item_add(kiln_inv, itemstack, amount)
  234. local rest
  235. if itemstack:get_name() == coal
  236. then
  237. local coalstack = kiln_inv:get_stack("fuel", 1)
  238. rest = coalstack:add_item(itemstack:take_item(amount))
  239. kiln_inv:set_stack("fuel", 1, coalstack)
  240. else
  241. local to_smelt = kiln_inv:get_stack("in", 1)
  242. local smelted = kiln_inv:get_stack("out", 1)
  243. if can_put(itemstack, to_smelt, smelted)
  244. then
  245. rest = to_smelt:add_item(itemstack:take_item(amount))
  246. kiln_inv:set_stack("in", 1, to_smelt)
  247. end
  248. end
  249. itemstack:add_item(ItemStack(rest))
  250. end
  251. local function kiln_item_add_single(kiln_inv, itemstack)
  252. kiln_item_add(kiln_inv, itemstack, 1)
  253. end
  254. local function kiln_item_add_wholestack(kiln_inv, itemstack)
  255. local stack_size = itemstack:get_count()
  256. kiln_item_add(kiln_inv, itemstack, stack_size)
  257. end
  258. --add stuff to the kiln with rightclick
  259. local function on_rightclick(pos, node, clicker, itemstack, pointed_thing)
  260. local meta = minetest.get_meta(pos)
  261. local inv = meta:get_inventory()
  262. local wholestack = clicker:get_player_control().aux1
  263. if wholestack
  264. then
  265. kiln_item_add_wholestack(inv, itemstack)
  266. else
  267. kiln_item_add_single(inv, itemstack)
  268. end
  269. local switch_to_burning = start_timer_if_needed(pos, inv)
  270. if switch_to_burning
  271. then
  272. local n =
  273. {
  274. name = "kilns:kiln_on",
  275. param1 = node.param1,
  276. param2 = node.param2
  277. }
  278. minetest.swap_node(pos, n)
  279. end
  280. update_infotext(meta, false)
  281. return itemstack
  282. end
  283. --initialize metadata
  284. ------------------------------------------------------------------------
  285. local function on_construct(pos)
  286. local meta = minetest.get_meta(pos)
  287. meta:set_float("heat", 0)
  288. meta:set_float("progress", 0)
  289. meta:mark_as_private({"heat", "progress"})
  290. local inv = meta:get_inventory()
  291. inv:set_size("fuel", 1)
  292. inv:set_size("in", 1)
  293. inv:set_size("out", 1)
  294. update_infotext(meta, false)
  295. end
  296. return on_timer, on_punch, on_rightclick, on_construct