init.lua 9.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354
  1. -- support for i18n
  2. local S = minetest.get_translator(minetest.get_current_modname())
  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:set_yaw(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.set_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 = S("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 = S("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", S("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. end,
  167. can_dig = function(pos, player)
  168. local meta = minetest.get_meta(pos)
  169. local inv = meta:get_inventory()
  170. for _, element in pairs(elements) do
  171. if not inv:is_empty("armor_"..element) then
  172. return false
  173. end
  174. end
  175. return true
  176. end,
  177. after_place_node = function(pos, placer)
  178. minetest.add_entity(pos, "3d_armor_stand:armor_entity")
  179. add_hidden_node(pos, placer)
  180. end,
  181. allow_metadata_inventory_put = function(pos, listname, index, stack)
  182. local def = stack:get_definition() or {}
  183. local groups = def.groups or {}
  184. if groups[listname] then
  185. return 1
  186. end
  187. return 0
  188. end,
  189. allow_metadata_inventory_move = function(pos)
  190. return 0
  191. end,
  192. on_metadata_inventory_put = function(pos)
  193. update_entity(pos)
  194. end,
  195. on_metadata_inventory_take = function(pos)
  196. update_entity(pos)
  197. end,
  198. after_destruct = function(pos)
  199. update_entity(pos)
  200. remove_hidden_node(pos)
  201. end,
  202. on_blast = function(pos)
  203. drop_armor(pos)
  204. armor.drop_armor(pos, "3d_armor_stand:armor_stand")
  205. minetest.remove_node(pos)
  206. end,
  207. })
  208. minetest.register_node("3d_armor_stand:locked_armor_stand", {
  209. description = S("Locked Armor stand"),
  210. drawtype = "mesh",
  211. mesh = "3d_armor_stand.obj",
  212. tiles = {"3d_armor_stand_locked.png"},
  213. paramtype = "light",
  214. paramtype2 = "facedir",
  215. walkable = false,
  216. selection_box = {
  217. type = "fixed",
  218. fixed = {
  219. {-0.25, -0.4375, -0.25, 0.25, 1.4, 0.25},
  220. {-0.5, -0.5, -0.5, 0.5, -0.4375, 0.5},
  221. },
  222. },
  223. groups = {choppy=2, oddly_breakable_by_hand=2},
  224. sounds = default.node_sound_wood_defaults(),
  225. on_construct = function(pos)
  226. local meta = minetest.get_meta(pos)
  227. meta:set_string("formspec", armor_stand_formspec)
  228. meta:set_string("infotext", S("Armor Stand"))
  229. meta:set_string("owner", "")
  230. local inv = meta:get_inventory()
  231. for _, element in pairs(elements) do
  232. inv:set_size("armor_"..element, 1)
  233. end
  234. end,
  235. can_dig = function(pos, player)
  236. local meta = minetest.get_meta(pos)
  237. local inv = meta:get_inventory()
  238. for _, element in pairs(elements) do
  239. if not inv:is_empty("armor_"..element) then
  240. return false
  241. end
  242. end
  243. return true
  244. end,
  245. after_place_node = function(pos, placer)
  246. minetest.add_entity(pos, "3d_armor_stand:armor_entity")
  247. local meta = minetest.get_meta(pos)
  248. meta:set_string("owner", placer:get_player_name() or "")
  249. meta:set_string("infotext", S("Armor Stand (owned by @1)", meta:get_string("owner")))
  250. add_hidden_node(pos, placer)
  251. end,
  252. allow_metadata_inventory_put = function(pos, listname, index, stack, player)
  253. local meta = minetest.get_meta(pos)
  254. if not has_locked_armor_stand_privilege(meta, player) then
  255. return 0
  256. end
  257. local def = stack:get_definition() or {}
  258. local groups = def.groups or {}
  259. if groups[listname] then
  260. return 1
  261. end
  262. return 0
  263. end,
  264. allow_metadata_inventory_take = function(pos, listname, index, stack, player)
  265. local meta = minetest.get_meta(pos)
  266. if not has_locked_armor_stand_privilege(meta, player) then
  267. return 0
  268. end
  269. return stack:get_count()
  270. end,
  271. allow_metadata_inventory_move = function(pos)
  272. return 0
  273. end,
  274. on_metadata_inventory_put = function(pos)
  275. update_entity(pos)
  276. end,
  277. on_metadata_inventory_take = function(pos)
  278. update_entity(pos)
  279. end,
  280. after_destruct = function(pos)
  281. update_entity(pos)
  282. remove_hidden_node(pos)
  283. end,
  284. on_blast = function(pos)
  285. -- Not affected by TNT
  286. end,
  287. })
  288. minetest.register_entity("3d_armor_stand:armor_entity", {
  289. physical = true,
  290. visual = "mesh",
  291. mesh = "3d_armor_entity.obj",
  292. visual_size = {x=1, y=1},
  293. collisionbox = {0,0,0,0,0,0},
  294. textures = {"3d_armor_trans.png"},
  295. pos = nil,
  296. timer = 0,
  297. on_activate = function(self)
  298. local pos = self.object:get_pos()
  299. if pos then
  300. self.pos = vector.round(pos)
  301. update_entity(pos)
  302. end
  303. end,
  304. on_blast = function(self, damage)
  305. local drops = {}
  306. local node = minetest.get_node(self.pos)
  307. if node.name == "3d_armor_stand:armor_stand" then
  308. drop_armor(self.pos)
  309. self.object:remove()
  310. end
  311. return false, false, drops
  312. end,
  313. })
  314. minetest.register_abm({
  315. nodenames = {"3d_armor_stand:locked_armor_stand", "3d_armor_stand:armor_stand"},
  316. interval = 15,
  317. chance = 1,
  318. action = function(pos, node, active_object_count, active_object_count_wider)
  319. local num
  320. num = #minetest.get_objects_inside_radius(pos, 0.5)
  321. if num > 0 then return end
  322. update_entity(pos)
  323. end
  324. })
  325. minetest.register_craft({
  326. output = "3d_armor_stand:armor_stand",
  327. recipe = {
  328. {"", "group:fence", ""},
  329. {"", "group:fence", ""},
  330. {"default:steel_ingot", "default:steel_ingot", "default:steel_ingot"},
  331. }
  332. })
  333. minetest.register_craft({
  334. output = "3d_armor_stand:locked_armor_stand",
  335. recipe = {
  336. {"3d_armor_stand:armor_stand", "default:steel_ingot"},
  337. }
  338. })