init.lua 6.4 KB

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