init.lua 9.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326
  1. minetest.register_privilege("delprotect","Delete other's protection")
  2. protector = {}
  3. protector.get_member_list = function(meta)
  4. local s = meta:get_string("members")
  5. local list = s:split(" ")
  6. return list
  7. end
  8. protector.set_member_list = function(meta, list)
  9. meta:set_string("members", table.concat(list, " "))
  10. end
  11. protector.is_member = function (meta, name)
  12. local list = protector.get_member_list(meta)
  13. for _, n in ipairs(list) do
  14. if n == name then
  15. return true
  16. end
  17. end
  18. return false
  19. end
  20. protector.add_member = function(meta, name)
  21. if protector.is_member(meta, name) then return end
  22. local list = protector.get_member_list(meta)
  23. table.insert(list,name)
  24. protector.set_member_list(meta,list)
  25. end
  26. protector.del_member = function(meta,name)
  27. local list = protector.get_member_list(meta)
  28. for i, n in ipairs(list) do
  29. if n == name then
  30. table.remove(list, i)
  31. break
  32. end
  33. end
  34. protector.set_member_list(meta,list)
  35. end
  36. -- Protector Interface
  37. protector.generate_formspec = function(meta)
  38. if meta:get_int("page") == nil then meta:set_int("page",0) end
  39. local formspec = "size[8,7]"
  40. .."label[0,0;-- Protector interface --]"
  41. .."label[0,1;Punch node to show protected area]"
  42. .."label[0,2;Members: (type nick, press Enter to add)]"
  43. members = protector.get_member_list(meta)
  44. local npp = 12 -- was 15, names per page, for the moment is 4*4 (-1 for the + button)
  45. local s = 0
  46. local i = 0
  47. for _, member in ipairs(members) do
  48. if s < meta:get_int("page")*15 then s = s +1 else
  49. if i < npp then
  50. formspec = formspec .. "button["..(i%4*2)..","
  51. ..math.floor(i/4+3)..";1.5,.5;protector_member;"..member.."]"
  52. formspec = formspec .. "button["..(i%4*2+1.25)..","
  53. ..math.floor(i/4+3)..";.75,.5;protector_del_member_"..member..";X]"
  54. end
  55. i = i +1
  56. end
  57. end
  58. local add_i = i
  59. if add_i < npp then
  60. formspec = formspec
  61. .."field["..(add_i%4*2+1/3)..","..(math.floor(add_i/4+3)+1/3)..";1.433,.5;protector_add_member;;]"
  62. end
  63. formspec = formspec.."button_exit[1,6.2;2,0.5;close_me;<< Back]"
  64. return formspec
  65. end
  66. -- ACTUAL PROTECTION SECTION
  67. -- r: radius to check for protects
  68. -- Infolevel:
  69. -- * 0 for no info
  70. -- * 1 for "This area is owned by <owner> !" if you can't dig
  71. -- * 2 for "This area is owned by <owner>.
  72. -- Members are: <members>.", even if you can dig
  73. protector.can_dig = function(r,pos,digger,onlyowner,infolevel)
  74. if not digger then
  75. return false
  76. end
  77. local whois = digger
  78. -- Delprotect privileged users can override protections
  79. if minetest.check_player_privs(whois, {delprotect=true}) and infolevel < 3 then
  80. return true
  81. end
  82. if infolevel == 3 then infolevel = 1 end
  83. -- Find the protector nodes
  84. local positions = minetest.find_nodes_in_area(
  85. {x=pos.x-r, y=pos.y-r, z=pos.z-r},
  86. {x=pos.x+r, y=pos.y+r, z=pos.z+r},
  87. "protector:protect")
  88. for _, pos in ipairs(positions) do
  89. local meta = minetest.env:get_meta(pos)
  90. local owner = meta:get_string("owner")
  91. if owner ~= whois then
  92. if onlyowner or not protector.is_member(meta, whois) then
  93. if infolevel == 1 then
  94. minetest.chat_send_player(whois, "This area is owned by "..owner.." !")
  95. elseif infolevel == 2 then
  96. minetest.chat_send_player(whois,"This area is owned by "..meta:get_string("owner")..".")
  97. if meta:get_string("members") ~= "" then
  98. minetest.chat_send_player(whois,"Members: "..meta:get_string("members")..".")
  99. end
  100. end
  101. return false
  102. end
  103. end
  104. end
  105. if infolevel == 2 then
  106. if #positions < 1 then
  107. minetest.chat_send_player(whois,"This area is not protected.")
  108. else
  109. local meta = minetest.env:get_meta(positions[1])
  110. minetest.chat_send_player(whois,"This area is owned by "..meta:get_string("owner")..".")
  111. if meta:get_string("members") ~= "" then
  112. minetest.chat_send_player(whois,"Members: "..meta:get_string("members")..".")
  113. end
  114. end
  115. minetest.chat_send_player(whois,"You can build here.")
  116. end
  117. return true
  118. end
  119. -- Can node be added or removed, if so return node else true (for protected)
  120. protector.old_is_protected = minetest.is_protected
  121. minetest.is_protected = function(pos, digger)
  122. if protector.can_dig(5, pos, digger, false, 1) then
  123. return protector.old_is_protected(pos, digger)
  124. else
  125. return true
  126. end
  127. end
  128. -- Make sure protection block doesn't overlap another block's area
  129. protector.old_node_place = minetest.item_place
  130. function minetest.item_place(itemstack, placer, pointed_thing)
  131. if itemstack:get_name() == "protector:protect" then
  132. local pos = pointed_thing.above
  133. local user = placer:get_player_name()
  134. if protector.can_dig(10, pos, user, true, 3) then
  135. --
  136. else
  137. minetest.chat_send_player(placer:get_player_name(),"Overlaps into another protected area")
  138. return protector.old_node_place(itemstack, placer, pos)
  139. end
  140. end
  141. return protector.old_node_place(itemstack, placer, pointed_thing)
  142. end
  143. -- END
  144. minetest.register_node("protector:protect", {
  145. description = "Protection",
  146. tiles = {"protector_top.png","protector_top.png","protector_side.png"},
  147. sounds = default.node_sound_stone_defaults(),
  148. groups = {dig_immediate=2},
  149. drawtype = "nodebox",
  150. node_box = {
  151. type="fixed",
  152. fixed = { -0.5, -0.5, -0.5, 0.5, 0.5, 0.5 },
  153. },
  154. selection_box = { type="regular" },
  155. paramtype = "light",
  156. after_place_node = function(pos, placer)
  157. local meta = minetest.env:get_meta(pos)
  158. meta:set_string("owner", placer:get_player_name() or "")
  159. meta:set_string("infotext", "Protection (owned by "..
  160. meta:get_string("owner")..")")
  161. meta:set_string("members", "")
  162. end,
  163. on_use = function(itemstack, user, pointed_thing)
  164. if pointed_thing.type ~= "node" then
  165. return
  166. end
  167. protector.can_dig(5,pointed_thing.under,user:get_player_name(),false,2)
  168. end,
  169. on_rightclick = function(pos, node, clicker, itemstack)
  170. local meta = minetest.env:get_meta(pos)
  171. if protector.can_dig(1,pos,clicker:get_player_name(),true,1) then
  172. minetest.show_formspec(clicker:get_player_name(),
  173. "protector_"..minetest.pos_to_string(pos), protector.generate_formspec(meta)
  174. )
  175. end
  176. end,
  177. on_punch = function(pos, node, puncher)
  178. if not protector.can_dig(1,pos,puncher:get_player_name(),true,1) then
  179. return
  180. end
  181. local objs = minetest.env:get_objects_inside_radius(pos,.5)
  182. minetest.env:add_entity(pos, "protector:display")
  183. minetest.env:get_node_timer(pos):start(10)
  184. end,
  185. on_timer = function(pos)
  186. local objs = minetest.env:get_objects_inside_radius(pos,.5)
  187. for _, o in pairs(objs) do
  188. if (not o:is_player()) and o:get_luaentity().name == "protector:display" then
  189. o:remove()
  190. end
  191. end
  192. end,
  193. })
  194. minetest.register_on_player_receive_fields(function(player,formname,fields)
  195. if string.sub(formname,0,string.len("protector_")) == "protector_" then
  196. local pos_s = string.sub(formname,string.len("protector_")+1)
  197. local pos = minetest.string_to_pos(pos_s)
  198. local meta = minetest.env:get_meta(pos)
  199. if meta:get_int("page") == nil then meta:set_int("page",0) end
  200. if not protector.can_dig(1,pos,player:get_player_name(),true,1) then
  201. return
  202. end
  203. if fields.protector_add_member then
  204. for _, i in ipairs(fields.protector_add_member:split(" ")) do
  205. protector.add_member(meta,i)
  206. end
  207. end
  208. for field, value in pairs(fields) do
  209. if string.sub(field,0,string.len("protector_del_member_"))=="protector_del_member_" then
  210. protector.del_member(meta, string.sub(field,string.len("protector_del_member_")+1))
  211. end
  212. end
  213. if fields.protector_page_prev then
  214. meta:set_int("page",meta:get_int("page")-1)
  215. end
  216. if fields.protector_page_next then
  217. meta:set_int("page",meta:get_int("page")+1)
  218. end
  219. if fields.close_me then
  220. meta:set_int("page",meta:get_int("page"))
  221. else minetest.show_formspec(player:get_player_name(), formname, protector.generate_formspec(meta))
  222. end
  223. end
  224. end)
  225. minetest.register_craft({
  226. output = "protector:protect 4",
  227. recipe = {
  228. {"default:stone","default:stone","default:stone"},
  229. {"default:stone","default:steel_ingot","default:stone"},
  230. {"default:stone","default:stone","default:stone"},
  231. }
  232. })
  233. minetest.register_entity("protector:display", {
  234. physical = false,
  235. collisionbox = {0,0,0,0,0,0},
  236. visual = "wielditem",
  237. visual_size = {x=1.0/1.5,y=1.0/1.5}, -- wielditem seems to be scaled to 1.5 times original node size
  238. textures = {"protector:display_node"},
  239. on_step = function(self, dtime)
  240. if minetest.get_node(self.object:getpos()).name ~= "protector:protect" then
  241. self.object:remove()
  242. return
  243. end
  244. end,
  245. })
  246. -- Display-zone node.
  247. -- Do NOT place the display as a node
  248. -- it is made to be used as an entity (see above)
  249. minetest.register_node("protector:display_node", {
  250. tiles = {"protector_display.png"},
  251. use_texture_alpha = true,
  252. walkable = false,
  253. drawtype = "nodebox",
  254. node_box = {
  255. type = "fixed",
  256. fixed = {
  257. -- sides
  258. {-5.55, -5.55, -5.55, -5.45, 5.55, 5.55},
  259. {-5.55, -5.55, 5.45, 5.55, 5.55, 5.55},
  260. {5.45, -5.55, -5.55, 5.55, 5.55, 5.55},
  261. {-5.55, -5.55, -5.55, 5.55, 5.55, -5.45},
  262. -- top
  263. {-5.55, 5.45, -5.55, 5.55, 5.55, 5.55},
  264. -- bottom
  265. {-5.55, -5.55, -5.55, 5.55, -5.45, 5.55},
  266. -- middle (surround protector)
  267. {-.55,-.55,-.55, .55,.55,.55},
  268. },
  269. },
  270. selection_box = {
  271. type = "regular",
  272. },
  273. paramtype = "light",
  274. groups = {dig_immediate=3,not_in_creative_inventory=1},
  275. drop = "",
  276. })