item_entity.lua 5.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189
  1. -- Minetest: builtin/item_entity.lua
  2. function core.spawn_item(pos, item)
  3. -- Take item in any format
  4. local stack = ItemStack(item)
  5. local obj = core.add_entity(pos, "__builtin:item")
  6. obj:get_luaentity():set_item(stack:to_string())
  7. return obj
  8. end
  9. -- If item_entity_ttl is not set, enity will have default life time
  10. -- Setting it to -1 disables the feature
  11. local time_to_live = tonumber(core.setting_get("item_entity_ttl"))
  12. if not time_to_live then
  13. time_to_live = 900
  14. end
  15. core.register_entity(":__builtin:item", {
  16. initial_properties = {
  17. hp_max = 1,
  18. physical = true,
  19. collide_with_objects = false,
  20. collisionbox = {-0.24, -0.24, -0.24, 0.24, 0.24, 0.24},
  21. visual = "wielditem",
  22. visual_size = {x = 0.3, y = 0.3},
  23. textures = {""},
  24. spritediv = {x = 1, y = 1},
  25. initial_sprite_basepos = {x = 0, y = 0},
  26. is_visible = false,
  27. },
  28. itemstring = '',
  29. physical_state = true,
  30. age = 0,
  31. set_item = function(self, itemstring)
  32. self.itemstring = itemstring
  33. local stack = ItemStack(itemstring)
  34. local count = stack:get_count()
  35. local max_count = stack:get_stack_max()
  36. if count > max_count then
  37. count = max_count
  38. self.itemstring = stack:get_name().." "..max_count
  39. end
  40. local s = 0.15 + 0.15 * (count / max_count)
  41. local c = 0.8 * s
  42. local itemtable = stack:to_table()
  43. local itemname = nil
  44. if itemtable then
  45. itemname = stack:to_table().name
  46. end
  47. local item_texture = nil
  48. local item_type = ""
  49. if core.registered_items[itemname] then
  50. item_texture = core.registered_items[itemname].inventory_image
  51. item_type = core.registered_items[itemname].type
  52. end
  53. prop = {
  54. is_visible = true,
  55. visual = "wielditem",
  56. textures = {itemname},
  57. visual_size = {x = s, y = s},
  58. collisionbox = {-c, -c, -c, c, c, c},
  59. automatic_rotate = math.pi * 0.2,
  60. }
  61. self.object:set_properties(prop)
  62. end,
  63. get_staticdata = function(self)
  64. return core.serialize({
  65. itemstring = self.itemstring,
  66. always_collect = self.always_collect,
  67. age = self.age
  68. })
  69. end,
  70. on_activate = function(self, staticdata, dtime_s)
  71. if string.sub(staticdata, 1, string.len("return")) == "return" then
  72. local data = core.deserialize(staticdata)
  73. if data and type(data) == "table" then
  74. self.itemstring = data.itemstring
  75. self.always_collect = data.always_collect
  76. if data.age then
  77. self.age = data.age + dtime_s
  78. else
  79. self.age = dtime_s
  80. end
  81. end
  82. else
  83. self.itemstring = staticdata
  84. end
  85. self.object:set_armor_groups({immortal = 1})
  86. self.object:setvelocity({x = 0, y = 2, z = 0})
  87. self.object:setacceleration({x = 0, y = -10, z = 0})
  88. self:set_item(self.itemstring)
  89. end,
  90. on_step = function(self, dtime)
  91. self.age = self.age + dtime
  92. if time_to_live > 0 and self.age > time_to_live then
  93. self.itemstring = ''
  94. self.object:remove()
  95. return
  96. end
  97. local p = self.object:getpos()
  98. p.y = p.y - 0.3
  99. local nn = core.get_node(p).name
  100. -- If node is not registered or node is walkably solid and resting on nodebox
  101. local v = self.object:getvelocity()
  102. if not core.registered_nodes[nn] or core.registered_nodes[nn].walkable and v.y == 0 then
  103. if self.physical_state then
  104. local own_stack = ItemStack(self.object:get_luaentity().itemstring)
  105. for _,object in ipairs(core.get_objects_inside_radius(p, 0.8)) do
  106. local obj = object:get_luaentity()
  107. if obj and obj.name == "__builtin:item" and obj.physical_state == false then
  108. local stack = ItemStack(obj.itemstring)
  109. if own_stack:get_name() == stack:get_name() and stack:get_free_space() > 0 then
  110. local overflow = false
  111. local count = stack:get_count() + own_stack:get_count()
  112. local max_count = stack:get_stack_max()
  113. if count>max_count then
  114. overflow = true
  115. count = count - max_count
  116. else
  117. self.itemstring = ''
  118. end
  119. local pos=object:getpos()
  120. pos.y = pos.y + (count - stack:get_count()) / max_count * 0.15
  121. object:moveto(pos, false)
  122. local s, c
  123. local max_count = stack:get_stack_max()
  124. local name = stack:get_name()
  125. if not overflow then
  126. obj.itemstring = name.." "..count
  127. s = 0.15 + 0.15 * (count / max_count)
  128. c = 0.8 * s
  129. object:set_properties({
  130. visual_size = {x = s, y = s},
  131. collisionbox = {-c, -c, -c, c, c, c}
  132. })
  133. self.object:remove()
  134. return
  135. else
  136. s = 0.3
  137. c = 0.24
  138. object:set_properties({
  139. visual_size = {x = s, y = s},
  140. collisionbox = {-c, -c, -c, c, c, c}
  141. })
  142. obj.itemstring = name.." "..max_count
  143. s = 0.15 + 0.15 * (count / max_count)
  144. c = 0.8 * s
  145. self.object:set_properties({
  146. visual_size = {x = s, y = s},
  147. collisionbox = {-c, -c, -c, c, c, c}
  148. })
  149. self.itemstring = name.." "..count
  150. end
  151. end
  152. end
  153. end
  154. self.object:setvelocity({x = 0, y = 0, z = 0})
  155. self.object:setacceleration({x = 0, y = 0, z = 0})
  156. self.physical_state = false
  157. self.object:set_properties({physical = false})
  158. end
  159. else
  160. if not self.physical_state then
  161. self.object:setvelocity({x = 0, y = 0, z = 0})
  162. self.object:setacceleration({x = 0, y = -10, z = 0})
  163. self.physical_state = true
  164. self.object:set_properties({physical = true})
  165. end
  166. end
  167. end,
  168. on_punch = function(self, hitter)
  169. if self.itemstring ~= '' then
  170. local left = hitter:get_inventory():add_item("main", self.itemstring)
  171. if not left:is_empty() then
  172. self.itemstring = left:to_string()
  173. return
  174. end
  175. end
  176. self.itemstring = ''
  177. self.object:remove()
  178. end,
  179. })