init.lua 9.7 KB

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