init.lua 6.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227
  1. itemburn = itemburn or {}
  2. itemburn.modpath = minetest.get_modpath("itemburn")
  3. -- Use an offset for finding the node under the drop,
  4. -- to allow thin slab shielding for lava, etc.
  5. itemburn.footstep=-0.25
  6. function itemburn.get_fs()
  7. return itemburn.footstep
  8. end
  9. -- mods/default/item_entity.lua
  10. local builtin_item = minetest.registered_entities["__builtin:item"]
  11. local item = {
  12. set_item = function(self, itemstring)
  13. builtin_item.set_item(self, itemstring)
  14. local stack = ItemStack(itemstring)
  15. local itemdef = minetest.registered_items[stack:get_name()]
  16. if itemdef and itemdef.groups.flammable ~= 0 then
  17. self.flammable = itemdef.groups.flammable
  18. end
  19. end,
  20. burn_up = function(self, lava)
  21. -- disappear in a smoke puff
  22. self.itemstring = ""
  23. local p = self.object:getpos()
  24. minetest.sound_play("default_item_smoke", {
  25. pos = p,
  26. max_hear_distance = 8,
  27. })
  28. minetest.add_particlespawner({
  29. amount = 3,
  30. time = 0.1,
  31. minpos = {x = p.x - 0.1, y = p.y + 0.1, z = p.z - 0.1 },
  32. maxpos = {x = p.x + 0.1, y = p.y + 0.2, z = p.z + 0.1 },
  33. minvel = {x = 0, y = 2.5, z = 0},
  34. maxvel = {x = 0, y = 2.5, z = 0},
  35. minacc = {x = -0.15, y = -0.02, z = -0.15},
  36. maxacc = {x = 0.15, y = -0.01, z = 0.15},
  37. minexptime = 4,
  38. maxexptime = 6,
  39. minsize = 5,
  40. maxsize = 5,
  41. collisiondetection = true,
  42. texture = "default_item_smoke.png"
  43. })
  44. if lava then
  45. local node = minetest.get_node(p)
  46. lava_extras.spawn_particles(p, node)
  47. end
  48. self.object:remove()
  49. end,
  50. melt_in_lava = function(self, lpos)
  51. local p = self.object:getpos()
  52. ambiance.sound_play("default_cool_lava", p, 2.0, 16)
  53. self.itemstring = ""
  54. self.object:remove()
  55. local node = minetest.get_node(lpos)
  56. lava_extras.spawn_particles(lpos, node)
  57. end,
  58. on_step = function(self, dtime, moveresult)
  59. builtin_item.on_step(self, dtime, moveresult)
  60. local is_falling = false
  61. local vel = self.object:get_velocity()
  62. -- Fix spurious error.
  63. -- Note: documentation explains this is caused by :remove() being called
  64. -- inside the original on_step() function; see just a few lines above, where
  65. -- it gets called.
  66. if not vel then
  67. return
  68. end
  69. if vel.y < -0.1 then
  70. is_falling = true
  71. self.need_lava_check = true
  72. --minetest.chat_send_all("# Server: Falling!")
  73. end
  74. if not is_falling and self.need_lava_check then
  75. --minetest.chat_send_all("# Server: Lava check!")
  76. local pos = self.object:getpos()
  77. local node = minetest.get_node(pos)
  78. --minetest.chat_send_all("# Server: A=" .. node.name)
  79. if string.find(node.name, ":lava_") then
  80. self:melt_in_lava(vector.round(pos))
  81. return
  82. else
  83. local pb = vector.round({x=pos.x, y=pos.y+itemburn.get_fs(), z=pos.z})
  84. local node = minetest.get_node(pb)
  85. --minetest.chat_send_all("# Server: U=" .. node.name)
  86. if string.find(node.name, ":lava_") then
  87. self:melt_in_lava(pb)
  88. return
  89. end
  90. end
  91. self.need_lava_check = false
  92. end
  93. -- flammable, check for igniters
  94. self.ignite_timer = (self.ignite_timer or 0) - dtime
  95. if self.ignite_timer < 0 then
  96. self.ignite_timer = math.random(10, 100)/10
  97. local pos = self.object:getpos()
  98. local node = minetest.get_node_or_nil(pos)
  99. if not node then
  100. return
  101. end
  102. -- Immediately burn up flammable items in lava
  103. if minetest.get_item_group(node.name, "lava") > 0 then
  104. self:melt_in_lava(vector.round(pos))
  105. else
  106. -- Check if sitting on top of lava.
  107. local pb = vector.round({x=pos.x, y=pos.y+itemburn.get_fs(), z=pos.z})
  108. local nb = minetest.get_node_or_nil(pb)
  109. if nb then
  110. local l = minetest.get_item_group(nb.name, "lava")
  111. if l > 0 then
  112. self:melt_in_lava(pb)
  113. return
  114. end
  115. end
  116. -- otherwise there'll be a chance based on its igniter value
  117. local burn_chance = (self.flammable or 1) * minetest.get_item_group(node.name, "igniter")
  118. if burn_chance > 0 and math.random(0, burn_chance) ~= 0 then
  119. self:burn_up()
  120. end
  121. end
  122. end
  123. end,
  124. on_punch = function(self, hitter)
  125. local inv = hitter:get_inventory()
  126. if not inv then
  127. return
  128. end
  129. local clear = true
  130. if self.itemstring ~= "" then
  131. local stack = ItemStack(self.itemstring)
  132. local name = stack:get_name()
  133. local count = stack:get_count()
  134. local left
  135. local index
  136. local inserted = false
  137. local newstack
  138. for i=1, inv:get_size("main"), 1 do
  139. local s2 = inv:get_stack("main", i)
  140. local n2 = s2:get_name()
  141. local empty = s2:is_empty()
  142. if name == n2 or empty then
  143. if empty then
  144. local s3 = stack:take_item(math.min(stack:get_count(), stack:get_stack_max()))
  145. left = stack
  146. index = i
  147. inv:set_stack("main", i, s3)
  148. newstack = ItemStack(s3) -- A copy of the stack being added.
  149. inserted = true
  150. break
  151. elseif name == n2 and s2:get_free_space() > 0 then
  152. newstack = ItemStack(stack):take_item(math.min(s2:get_free_space(), stack:get_count())) -- A copy of the stack being added.
  153. left = s2:add_item(stack)
  154. index = i
  155. inv:set_stack("main", i, s2)
  156. inserted = true
  157. break
  158. end
  159. end
  160. end
  161. -- If something was added to the inv, we update the entity, but do not clear it.
  162. if left and not left:is_empty() then
  163. count = count - left:get_count()
  164. self:set_item(left)
  165. clear = false
  166. end
  167. -- If nothing was added to the inventory, we cannot remove the entity.
  168. if not inserted then
  169. clear = false
  170. end
  171. if inserted then
  172. minetest.log("action", hitter:get_player_name() .. " picks item-entity " ..
  173. stack:get_name() .. " " .. count .. " at " .. minetest.pos_to_string(vector.round(self.object:getpos())))
  174. -- Execute player inventory callbacks.
  175. -- Note: inventory callbacks are called when player drops item (Q) so this
  176. -- implements the reciprocal.
  177. for _, func in ipairs(core.registered_on_player_inventory_actions) do
  178. func(hitter, "put", inv, {listname="main", index=index, stack=newstack})
  179. end
  180. end
  181. end
  182. if clear then
  183. self.itemstring = ""
  184. self.object:remove()
  185. end
  186. end,
  187. }
  188. -- set defined item as new __builtin:item, with the old one as fallback table
  189. setmetatable(item, builtin_item)
  190. minetest.register_entity(":__builtin:item", item)