init.lua 9.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376
  1. local armor_stand_formspec = "size[8,7]" ..
  2. default.gui_bg ..
  3. default.gui_bg_img ..
  4. default.gui_slots ..
  5. default.get_hotbar_bg(0,3) ..
  6. "list[current_name;armor_head;3,0.5;1,1;]" ..
  7. "list[current_name;armor_torso;4,0.5;1,1;]" ..
  8. "list[current_name;armor_legs;3,1.5;1,1;]" ..
  9. "list[current_name;armor_feet;4,1.5;1,1;]" ..
  10. "image[3,0.5;1,1;3d_armor_stand_head.png]" ..
  11. "image[4,0.5;1,1;3d_armor_stand_torso.png]" ..
  12. "image[3,1.5;1,1;3d_armor_stand_legs.png]" ..
  13. "image[4,1.5;1,1;3d_armor_stand_feet.png]" ..
  14. "list[current_player;main;0,3;8,1;]" ..
  15. "list[current_player;main;0,4.25;8,3;8]"
  16. local elements = {"head", "torso", "legs", "feet"}
  17. local function drop_armor(pos)
  18. local meta = minetest.get_meta(pos)
  19. local inv = meta:get_inventory()
  20. for _, element in pairs(elements) do
  21. local stack = inv:get_stack("armor_"..element, 1)
  22. if stack and stack:get_count() > 0 then
  23. armor.drop_armor(pos, stack)
  24. inv:set_stack("armor_"..element, 1, nil)
  25. end
  26. end
  27. end
  28. local function get_stand_object(pos)
  29. local object = nil
  30. local objects = minetest.get_objects_inside_radius(pos, 0.5) or {}
  31. for _, obj in pairs(objects) do
  32. local ent = obj:get_luaentity()
  33. if ent then
  34. if ent.name == "3d_armor_stand:armor_entity" then
  35. -- Remove duplicates
  36. if object then
  37. obj:remove()
  38. else
  39. object = obj
  40. end
  41. end
  42. end
  43. end
  44. return object
  45. end
  46. local function update_entity(pos)
  47. local node = minetest.get_node(pos)
  48. local object = get_stand_object(pos)
  49. if object then
  50. if not string.find(node.name, "3d_armor_stand:") then
  51. object:remove()
  52. return
  53. end
  54. else
  55. object = minetest.add_entity(pos, "3d_armor_stand:armor_entity")
  56. end
  57. if object then
  58. local texture = "3d_armor_trans.png"
  59. local textures = {}
  60. local meta = minetest.get_meta(pos)
  61. local inv = meta:get_inventory()
  62. local yaw = 0
  63. if inv then
  64. for _, element in pairs(elements) do
  65. local stack = inv:get_stack("armor_"..element, 1)
  66. if stack:get_count() == 1 then
  67. local item = stack:get_name() or ""
  68. local def = stack:get_definition() or {}
  69. local groups = def.groups or {}
  70. if groups["armor_"..element] then
  71. if def.texture then
  72. table.insert(textures, def.texture)
  73. else
  74. table.insert(textures, item:gsub("%:", "_")..".png")
  75. end
  76. end
  77. end
  78. end
  79. end
  80. if #textures > 0 then
  81. texture = table.concat(textures, "^")
  82. end
  83. if node.param2 then
  84. local rot = node.param2 % 4
  85. if rot == 1 then
  86. yaw = 3 * math.pi / 2
  87. elseif rot == 2 then
  88. yaw = math.pi
  89. elseif rot == 3 then
  90. yaw = math.pi / 2
  91. end
  92. end
  93. object:setyaw(yaw)
  94. object:set_properties({textures={texture}})
  95. end
  96. end
  97. local function has_locked_armor_stand_privilege(meta, player)
  98. local name = ""
  99. if player then
  100. if minetest.check_player_privs(player, "protection_bypass") then
  101. return true
  102. end
  103. name = player:get_player_name()
  104. end
  105. if name ~= meta:get_string("owner") then
  106. return false
  107. end
  108. return true
  109. end
  110. local function add_hidden_node(pos, player)
  111. local p = {x=pos.x, y=pos.y + 1, z=pos.z}
  112. local name = player:get_player_name()
  113. local node = minetest.get_node(p)
  114. if node.name == "air" and not minetest.is_protected(pos, name) then
  115. minetest.add_node(p, {name="3d_armor_stand:top"})
  116. end
  117. end
  118. local function remove_hidden_node(pos)
  119. local p = {x=pos.x, y=pos.y + 1, z=pos.z}
  120. local node = minetest.get_node(p)
  121. if node.name == "3d_armor_stand:top" then
  122. minetest.remove_node(p)
  123. end
  124. end
  125. minetest.register_node("3d_armor_stand:top", {
  126. description = "Armor Stand Top",
  127. paramtype = "light",
  128. drawtype = "plantlike",
  129. sunlight_propagates = true,
  130. walkable = true,
  131. pointable = false,
  132. diggable = false,
  133. buildable_to = false,
  134. drop = "",
  135. groups = {not_in_creative_inventory = 1},
  136. on_blast = function() end,
  137. tiles = {"3d_armor_trans.png"},
  138. })
  139. minetest.register_node("3d_armor_stand:armor_stand", {
  140. description = "Armor Stand",
  141. drawtype = "mesh",
  142. mesh = "3d_armor_stand.obj",
  143. tiles = {"3d_armor_stand.png"},
  144. paramtype = "light",
  145. paramtype2 = "facedir",
  146. walkable = false,
  147. selection_box = {
  148. type = "fixed",
  149. fixed = {
  150. {-0.25, -0.4375, -0.25, 0.25, 1.4, 0.25},
  151. {-0.5, -0.5, -0.5, 0.5, -0.4375, 0.5},
  152. },
  153. },
  154. groups = {choppy=2, oddly_breakable_by_hand=2},
  155. sounds = default.node_sound_wood_defaults(),
  156. on_construct = function(pos)
  157. local meta = minetest.get_meta(pos)
  158. meta:set_string("formspec", armor_stand_formspec)
  159. meta:set_string("infotext", "Armor Stand")
  160. local inv = meta:get_inventory()
  161. for _, element in pairs(elements) do
  162. inv:set_size("armor_"..element, 1)
  163. end
  164. local timer = minetest.get_node_timer(pos)
  165. timer:start(60*60) -- 1 hour.
  166. end,
  167. on_timer = function(pos, elapsed)
  168. update_entity(pos)
  169. return true -- Restart timer with same timeout.
  170. end,
  171. can_dig = function(pos, player)
  172. local meta = minetest.get_meta(pos)
  173. local inv = meta:get_inventory()
  174. for _, element in pairs(elements) do
  175. if not inv:is_empty("armor_"..element) then
  176. return false
  177. end
  178. end
  179. return true
  180. end,
  181. after_place_node = function(pos, placer)
  182. minetest.add_entity(pos, "3d_armor_stand:armor_entity")
  183. add_hidden_node(pos, placer)
  184. end,
  185. allow_metadata_inventory_put = function(pos, listname, index, stack)
  186. local def = stack:get_definition() or {}
  187. local groups = def.groups or {}
  188. if groups[listname] then
  189. return 1
  190. end
  191. return 0
  192. end,
  193. allow_metadata_inventory_move = function(pos)
  194. return 0
  195. end,
  196. on_metadata_inventory_put = function(pos)
  197. update_entity(pos)
  198. local timer = minetest.get_node_timer(pos)
  199. if not timer:is_started() then
  200. timer:start(60*60)
  201. end
  202. end,
  203. on_metadata_inventory_take = function(pos)
  204. update_entity(pos)
  205. local timer = minetest.get_node_timer(pos)
  206. if not timer:is_started() then
  207. timer:start(60*60)
  208. end
  209. end,
  210. after_destruct = function(pos)
  211. update_entity(pos)
  212. remove_hidden_node(pos)
  213. end,
  214. on_blast = function(pos)
  215. drop_armor(pos)
  216. armor.drop_armor(pos, "3d_armor_stand:armor_stand")
  217. minetest.remove_node(pos)
  218. end,
  219. })
  220. minetest.register_node("3d_armor_stand:locked_armor_stand", {
  221. description = "Locked Armor Stand",
  222. drawtype = "mesh",
  223. mesh = "3d_armor_stand.obj",
  224. tiles = {"3d_armor_stand_locked.png"},
  225. paramtype = "light",
  226. paramtype2 = "facedir",
  227. walkable = false,
  228. selection_box = {
  229. type = "fixed",
  230. fixed = {
  231. {-0.25, -0.4375, -0.25, 0.25, 1.4, 0.25},
  232. {-0.5, -0.5, -0.5, 0.5, -0.4375, 0.5},
  233. },
  234. },
  235. groups = {choppy=2, oddly_breakable_by_hand=2},
  236. sounds = default.node_sound_wood_defaults(),
  237. on_construct = function(pos)
  238. local meta = minetest.get_meta(pos)
  239. meta:set_string("formspec", armor_stand_formspec)
  240. meta:set_string("infotext", "Armor Stand")
  241. meta:set_string("owner", "")
  242. local inv = meta:get_inventory()
  243. for _, element in pairs(elements) do
  244. inv:set_size("armor_"..element, 1)
  245. end
  246. local timer = minetest.get_node_timer(pos)
  247. timer:start(60*60) -- 1 hour.
  248. end,
  249. on_timer = function(pos, elapsed)
  250. update_entity(pos)
  251. return true -- Restart timer with same timeout.
  252. end,
  253. can_dig = function(pos, player)
  254. local meta = minetest.get_meta(pos)
  255. local inv = meta:get_inventory()
  256. for _, element in pairs(elements) do
  257. if not inv:is_empty("armor_"..element) then
  258. return false
  259. end
  260. end
  261. return true
  262. end,
  263. after_place_node = function(pos, placer)
  264. minetest.add_entity(pos, "3d_armor_stand:armor_entity")
  265. local meta = minetest.get_meta(pos)
  266. meta:set_string("owner", placer:get_player_name() or "")
  267. meta:set_string("infotext", "Armor Stand (Owned by <" .. rename.gpn(meta:get_string("owner")) .. ">!)")
  268. add_hidden_node(pos, placer)
  269. end,
  270. _on_rename_check = function(pos)
  271. local meta = minetest.get_meta(pos)
  272. meta:set_string("infotext", "Armor Stand (Owned by <" .. rename.gpn(meta:get_string("owner")) .. ">!)")
  273. end,
  274. allow_metadata_inventory_put = function(pos, listname, index, stack, player)
  275. local meta = minetest.get_meta(pos)
  276. if not has_locked_armor_stand_privilege(meta, player) then
  277. return 0
  278. end
  279. local def = stack:get_definition() or {}
  280. local groups = def.groups or {}
  281. if groups[listname] then
  282. return 1
  283. end
  284. return 0
  285. end,
  286. allow_metadata_inventory_take = function(pos, listname, index, stack, player)
  287. local meta = minetest.get_meta(pos)
  288. if not has_locked_armor_stand_privilege(meta, player) then
  289. return 0
  290. end
  291. return stack:get_count()
  292. end,
  293. allow_metadata_inventory_move = function(pos)
  294. return 0
  295. end,
  296. on_metadata_inventory_put = function(pos)
  297. update_entity(pos)
  298. local timer = minetest.get_node_timer(pos)
  299. if not timer:is_started() then
  300. timer:start(60*60)
  301. end
  302. end,
  303. on_metadata_inventory_take = function(pos)
  304. update_entity(pos)
  305. local timer = minetest.get_node_timer(pos)
  306. if not timer:is_started() then
  307. timer:start(60*60)
  308. end
  309. end,
  310. after_destruct = function(pos)
  311. update_entity(pos)
  312. remove_hidden_node(pos)
  313. end,
  314. on_blast = function(pos)
  315. -- Not affected by TNT
  316. end,
  317. })
  318. minetest.register_entity("3d_armor_stand:armor_entity", {
  319. physical = true,
  320. visual = "mesh",
  321. mesh = "3d_armor_entity.obj",
  322. visual_size = {x=1, y=1},
  323. collisionbox = {0,0,0,0,0,0},
  324. textures = {"3d_armor_trans.png"},
  325. pos = nil,
  326. timer = 0,
  327. on_activate = function(self)
  328. local pos = self.object:get_pos()
  329. if pos then
  330. self.pos = vector.round(pos)
  331. update_entity(pos)
  332. end
  333. end,
  334. on_blast = function(self, damage)
  335. local drops = {}
  336. local node = minetest.get_node(self.pos)
  337. if node.name == "3d_armor_stand:armor_stand" then
  338. drop_armor(self.pos)
  339. self.object:remove()
  340. end
  341. return false, false, drops
  342. end,
  343. })
  344. minetest.register_craft({
  345. output = "3d_armor_stand:armor_stand",
  346. recipe = {
  347. {"", "default:fence_pine_wood", ""},
  348. {"", "default:fence_pine_wood", ""},
  349. {"default:steel_ingot", "default:steel_ingot", "default:steel_ingot"},
  350. }
  351. })
  352. minetest.register_craft({
  353. output = "3d_armor_stand:locked_armor_stand",
  354. recipe = {
  355. {"3d_armor_stand:armor_stand", "default:padlock"},
  356. }
  357. })