init.lua 7.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380
  1. screwdriver = screwdriver or {}
  2. local tmp = {}
  3. local max_objs = tonumber(minetest.settings:get("max_objects_per_block")) or 49
  4. -- item entity
  5. minetest.register_entity("itemframes:item",{
  6. hp_max = 1,
  7. visual = "wielditem",
  8. visual_size = {x = 0.33, y = 0.33},
  9. collisionbox = {0, 0, 0, 0, 0, 0},
  10. physical = false,
  11. textures = {"air"},
  12. on_activate = function(self, staticdata)
  13. if not self then
  14. self.object:remove()
  15. return
  16. end
  17. if tmp.nodename ~= nil
  18. and tmp.texture ~= nil then
  19. self.nodename = tmp.nodename
  20. tmp.nodename = nil
  21. self.texture = tmp.texture
  22. tmp.texture = nil
  23. else
  24. if staticdata ~= nil
  25. and staticdata ~= "" then
  26. local data = staticdata:split(';')
  27. if data and data[1] and data[2] then
  28. self.nodename = data[1]
  29. self.texture = data[2]
  30. end
  31. end
  32. end
  33. if self.texture ~= nil then
  34. self.object:set_properties({textures = {self.texture}})
  35. end
  36. if self.nodename == "itemframes:pedestal" then
  37. self.object:set_properties({automatic_rotate = 1})
  38. end
  39. end,
  40. get_staticdata = function(self)
  41. if self.nodename ~= nil
  42. and self.texture ~= nil then
  43. return self.nodename .. ';' .. self.texture
  44. end
  45. return ""
  46. end,
  47. })
  48. -- helper table
  49. local facedir = {}
  50. facedir[0] = {x = 0, y = 0, z = 1}
  51. facedir[1] = {x = 1, y = 0, z = 0}
  52. facedir[2] = {x = 0, y = 0, z = -1}
  53. facedir[3] = {x = -1, y = 0, z = 0}
  54. -- remove entities
  55. local remove_item = function(pos, nodename)
  56. local ypos = 0
  57. if nodename == "itemframes:pedestal" then
  58. ypos = 1
  59. end
  60. local objs = minetest.get_objects_inside_radius({
  61. x = pos.x, y = pos.y + ypos, z = pos.z}, 0.5)
  62. if objs then
  63. for _, obj in pairs(objs) do
  64. if obj and obj:get_luaentity()
  65. and obj:get_luaentity().name == "itemframes:item" then
  66. obj:remove()
  67. end
  68. end
  69. end
  70. end
  71. -- update entity
  72. local update_item = function(pos, node)
  73. remove_item(pos, node.name)
  74. local meta = minetest.get_meta(pos)
  75. if not meta then return end
  76. if meta:get_string("item") ~= "" then
  77. if node.name == "itemframes:frame" then
  78. local posad = facedir[node.param2]
  79. if not posad then return end
  80. pos.x = pos.x + posad.x * 6.5 / 16
  81. pos.y = pos.y + posad.y * 6.5 / 16
  82. pos.z = pos.z + posad.z * 6.5 / 16
  83. elseif node.name == "itemframes:pedestal" then
  84. pos.y = pos.y + 12 / 16 + 0.33
  85. end
  86. tmp.nodename = node.name
  87. tmp.texture = ItemStack(meta:get_string("item")):get_name()
  88. local e = minetest.add_entity(pos,"itemframes:item")
  89. if node.name == "itemframes:frame" then
  90. --local yaw = math.pi * 2 - node.param2 * math.pi / 2
  91. local yaw = 6.28 - node.param2 * 1.57
  92. e:set_yaw(yaw)
  93. end
  94. end
  95. end
  96. -- remove entity and drop as item
  97. local drop_item = function(pos, nodename, metadata)
  98. local meta = metadata or minetest.get_meta(pos)
  99. if not meta then return end
  100. local item = meta:get_string("item")
  101. meta:set_string("item", "")
  102. if item ~= "" then
  103. remove_item(pos, nodename)
  104. if nodename == "itemframes:pedestal" then
  105. pos.y = pos.y + 1
  106. end
  107. minetest.add_item(pos, item)
  108. end
  109. end
  110. -- itemframe node and recipe
  111. minetest.register_node("itemframes:frame",{
  112. description = "Item frame",
  113. drawtype = "nodebox",
  114. node_box = {
  115. type = "fixed",
  116. fixed = {-0.5, -0.5, 7/16, 0.5, 0.5, 0.5}
  117. },
  118. selection_box = {
  119. type = "fixed",
  120. fixed = {-0.5, -0.5, 7/16, 0.5, 0.5, 0.5}
  121. },
  122. tiles = {"itemframes_frame.png"},
  123. inventory_image = "itemframes_frame.png",
  124. wield_image = "itemframes_frame.png",
  125. paramtype = "light",
  126. paramtype2 = "facedir",
  127. sunlight_propagates = true,
  128. groups = {choppy = 2, dig_immediate = 2, flammable = 2},
  129. legacy_wallmounted = true,
  130. sounds = default.node_sound_defaults(),
  131. on_rotate = screwdriver.disallow,
  132. after_place_node = function(pos, placer, itemstack)
  133. local meta = minetest.get_meta(pos)
  134. meta:set_string("infotext","Item frame (right-click to add or remove item)")
  135. end,
  136. on_rightclick = function(pos, node, clicker, itemstack)
  137. if not itemstack
  138. or minetest.is_protected(pos, clicker:get_player_name()) then
  139. return
  140. end
  141. local meta = minetest.get_meta(pos)
  142. if not meta then return end
  143. if meta:get_string("item") ~= "" then
  144. drop_item(pos, node.name, meta)
  145. else
  146. local s = itemstack:take_item()
  147. meta:set_string("item", s:to_string())
  148. update_item(pos, node)
  149. return itemstack
  150. end
  151. end,
  152. on_destruct = function(pos)
  153. drop_item(pos, "itemframes:frame")
  154. end,
  155. on_punch = function(pos, node, puncher)
  156. update_item(pos, node)
  157. end,
  158. on_blast = function(pos, intensity)
  159. drop_item(pos, "itemframes:frame")
  160. minetest.add_item(pos, {name = "itemframes:frame"})
  161. minetest.remove_node(pos)
  162. end,
  163. on_burn = function(pos)
  164. drop_item(pos, "itemframes:frame")
  165. minetest.remove_node(pos)
  166. end,
  167. })
  168. minetest.register_craft({
  169. output = "itemframes:frame",
  170. recipe = {
  171. {"default:stick", "default:stick", "default:stick"},
  172. {"default:stick", "default:paper", "default:stick"},
  173. {"default:stick", "default:stick", "default:stick"},
  174. }
  175. })
  176. -- pedestal node and recipe
  177. minetest.register_node("itemframes:pedestal",{
  178. description = "Pedestal",
  179. drawtype = "nodebox",
  180. node_box = {
  181. type = "fixed", fixed = {
  182. {-7/16, -8/16, -7/16, 7/16, -7/16, 7/16}, -- bottom plate
  183. {-6/16, -7/16, -6/16, 6/16, -6/16, 6/16}, -- bottom plate (upper)
  184. {-0.25, -6/16, -0.25, 0.25, 11/16, 0.25}, -- pillar
  185. {-7/16, 11/16, -7/16, 7/16, 12/16, 7/16}, -- top plate
  186. }
  187. },
  188. selection_box = {
  189. type = "fixed",
  190. fixed = {-7/16, -0.5, -7/16, 7/16, 12/16, 7/16}
  191. },
  192. tiles = {"itemframes_pedestal.png"},
  193. paramtype = "light",
  194. groups = {cracky = 3},
  195. sounds = default.node_sound_defaults(),
  196. on_rotate = screwdriver.disallow,
  197. after_place_node = function(pos, placer, itemstack)
  198. local meta = minetest.get_meta(pos)
  199. meta:set_string("infotext","Pedestal (right-click to add or remove item)")
  200. end,
  201. on_rightclick = function(pos, node, clicker, itemstack)
  202. if not itemstack
  203. or minetest.is_protected(pos, clicker:get_player_name()) then
  204. return
  205. end
  206. local meta = minetest.get_meta(pos)
  207. if not meta then return end
  208. if meta:get_string("item") ~= "" then
  209. drop_item(pos, node.name, meta)
  210. else
  211. local s = itemstack:take_item()
  212. meta:set_string("item", s:to_string())
  213. update_item(pos, node)
  214. return itemstack
  215. end
  216. end,
  217. on_destruct = function(pos)
  218. drop_item(pos, "itemframes:pedestal")
  219. end,
  220. on_punch = function(pos, node, puncher)
  221. update_item(pos, node)
  222. end,
  223. on_blast = function(pos, intensity)
  224. drop_item(pos, "itemframes:pedestal")
  225. minetest.add_item(pos, {name = "itemframes:pedestal"})
  226. minetest.remove_node(pos)
  227. end,
  228. })
  229. minetest.register_craft({
  230. output = "itemframes:pedestal",
  231. recipe = {
  232. {"default:stone", "default:stone", "default:stone"},
  233. {"", "default:stone", ""},
  234. {"default:stone", "default:stone", "default:stone"},
  235. }
  236. })
  237. -- automatically restore entities lost from frames/pedestals
  238. -- due to /clearobjects or similar
  239. minetest.register_abm({
  240. nodenames = {"itemframes:frame", "itemframes:pedestal"},
  241. interval = 25,
  242. chance = 1,
  243. catch_up = false,
  244. action = function(pos, node, active_object_count, active_object_count_wider)
  245. if active_object_count >= max_objs then
  246. return
  247. end
  248. local num
  249. if node.name == "itemframes:frame" then
  250. num = #minetest.get_objects_inside_radius(pos, 0.5)
  251. elseif node.name == "itemframes:pedestal" then
  252. pos.y = pos.y + 1
  253. num = #minetest.get_objects_inside_radius(pos, 0.5)
  254. pos.y = pos.y - 1
  255. end
  256. if num > 0 then
  257. return
  258. end
  259. update_item(pos, node)
  260. end
  261. })
  262. -- stop mesecon pistons from pushing itemframe and pedestals
  263. if minetest.get_modpath("mesecons_mvps") then
  264. mesecon.register_mvps_stopper("itemframes:frame")
  265. mesecon.register_mvps_stopper("itemframes:pedestal")
  266. end