init.lua 19 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831
  1. -- default support (for use with MineClone2 and other [games]
  2. default = default or {
  3. node_sound_stone_defaults = function(table) end,
  4. node_sound_wood_defaults = function(table) end,
  5. gui_bg = "",
  6. gui_bg_img = "",
  7. gui_slots = ""
  8. }
  9. if minetest.get_modpath("mcl_sounds") then
  10. default.node_sound_stone_defaults = mcl_sounds.node_sound_stone_defaults
  11. default.node_sound_wood_defaults = mcl_sounds.node_sound_wood_defaults
  12. default.node_sound_metal_defaults = mcl_sounds.node_sound_metal_defaults
  13. end
  14. local MP = minetest.get_modpath(minetest.get_current_modname())
  15. local F = minetest.formspec_escape
  16. -- Translation support
  17. local S = minetest.get_translator("protector")
  18. -- Load support for factions
  19. local factions_available = minetest.global_exists("factions")
  20. protector = {
  21. mod = "redo",
  22. modpath = MP,
  23. intllib = S
  24. }
  25. local protector_max_share_count = 12
  26. -- get minetest.conf settings
  27. local protector_radius = tonumber(minetest.settings:get("protector_radius")) or 5
  28. local protector_flip = minetest.settings:get_bool("protector_flip") or false
  29. local protector_hurt = tonumber(minetest.settings:get("protector_hurt")) or 0
  30. local protector_spawn = tonumber(minetest.settings:get("protector_spawn")
  31. or minetest.settings:get("protector_pvp_spawn")) or 0
  32. local protector_show = tonumber(minetest.settings:get("protector_show_interval")) or 5
  33. local protector_recipe = minetest.settings:get_bool("protector_recipe") ~= false
  34. local protector_msg = minetest.settings:get_bool("protector_msg") ~= false
  35. -- radius limiter (minetest cannot handle node volume of more than 4096000)
  36. if protector_radius > 22 then protector_radius = 22 end
  37. -- get static spawn position
  38. local statspawn = minetest.string_to_pos(minetest.settings:get("static_spawnpoint"))
  39. or {x = 0, y = 2, z = 0}
  40. -- return list of members as a table
  41. local get_member_list = function(meta)
  42. return meta:get_string("members"):split(" ")
  43. end
  44. -- write member list table in protector meta as string
  45. local set_member_list = function(meta, list)
  46. meta:set_string("members", table.concat(list, " "))
  47. end
  48. -- check for owner name
  49. local is_owner = function(meta, name)
  50. return name == meta:get_string("owner")
  51. end
  52. -- check for member name
  53. local is_member = function(meta, name)
  54. if factions_available
  55. and meta:get_int("faction_members") == 1 then
  56. if factions.version == nil then
  57. -- backward compatibility
  58. if factions.get_player_faction(name) ~= nil
  59. and factions.get_player_faction(meta:get_string("owner")) ==
  60. factions.get_player_faction(name) then
  61. return true
  62. end
  63. else
  64. -- is member if player and owner share at least one faction
  65. local owner_factions = factions.get_player_factions(name)
  66. local owner = meta:get_string("owner")
  67. if owner_factions ~= nil and owner_factions ~= false then
  68. for _, f in ipairs(owner_factions) do
  69. if factions.player_is_in_faction(f, owner) then
  70. return true
  71. end
  72. end
  73. end
  74. end
  75. end
  76. for _, n in pairs(get_member_list(meta)) do
  77. if n == name then
  78. return true
  79. end
  80. end
  81. return false
  82. end
  83. -- add player name to table as member
  84. local add_member = function(meta, name)
  85. -- Validate player name for MT compliance
  86. if name ~= string.match(name, "[%w_-]+") then
  87. return
  88. end
  89. -- Constant (20) defined by player.h
  90. if name:len() > 25 then
  91. return
  92. end
  93. -- does name already exist?
  94. if is_owner(meta, name)
  95. or is_member(meta, name) then
  96. return
  97. end
  98. local list = get_member_list(meta)
  99. if #list >= protector_max_share_count then
  100. return
  101. end
  102. table.insert(list, name)
  103. set_member_list(meta, list)
  104. end
  105. -- remove player name from table
  106. local del_member = function(meta, name)
  107. local list = get_member_list(meta)
  108. for i, n in pairs(list) do
  109. if n == name then
  110. table.remove(list, i)
  111. break
  112. end
  113. end
  114. set_member_list(meta, list)
  115. end
  116. -- protector interface
  117. local protector_formspec = function(meta)
  118. local formspec = "size[8,7]"
  119. .. default.gui_bg
  120. .. default.gui_bg_img
  121. .. "label[2.5,0;" .. F(S("-- Protector interface --")) .. "]"
  122. .. "label[0,1;" .. F(S("PUNCH node to show protected area")) .. "]"
  123. .. "label[0,2;" .. F(S("Members:")) .. "]"
  124. .. "button_exit[2.5,6.2;3,0.5;close_me;" .. F(S("Close")) .. "]"
  125. .. "field_close_on_enter[protector_add_member;false]"
  126. local members = get_member_list(meta)
  127. local npp = protector_max_share_count -- max users added to protector list
  128. local i = 0
  129. local checkbox_faction = false
  130. -- Display the checkbox only if the owner is member of at least 1 faction
  131. if factions_available then
  132. if factions.version == nil then
  133. -- backward compatibility
  134. if factions.get_player_faction(meta:get_string("owner")) then
  135. checkbox_faction = true
  136. end
  137. else
  138. local player_factions = factions.get_player_factions(meta:get_string("owner"))
  139. if player_factions ~= nil and #player_factions >= 1 then
  140. checkbox_faction = true
  141. end
  142. end
  143. end
  144. if checkbox_faction then
  145. formspec = formspec .. "checkbox[0,5;faction_members;"
  146. .. F(S("Allow faction access"))
  147. .. ";" .. (meta:get_int("faction_members") == 1 and
  148. "true" or "false") .. "]"
  149. if npp > 8 then
  150. npp = 8
  151. end
  152. end
  153. for n = 1, #members do
  154. if i < npp then
  155. -- show username
  156. formspec = formspec .. "button[" .. (i % 4 * 2)
  157. .. "," .. math.floor(i / 4 + 3)
  158. .. ";1.5,.5;protector_member;" .. F(members[n]) .. "]"
  159. -- username remove button
  160. .. "button[" .. (i % 4 * 2 + 1.25) .. ","
  161. .. math.floor(i / 4 + 3)
  162. .. ";.75,.5;protector_del_member_" .. F(members[n]) .. ";X]"
  163. end
  164. i = i + 1
  165. end
  166. if i < npp then
  167. -- user name entry field
  168. formspec = formspec .. "field[" .. (i % 4 * 2 + 1 / 3) .. ","
  169. .. (math.floor(i / 4 + 3) + 1 / 3)
  170. .. ";1.433,.5;protector_add_member;;]"
  171. -- username add button
  172. .."button[" .. (i % 4 * 2 + 1.25) .. ","
  173. .. math.floor(i / 4 + 3) .. ";.75,.5;protector_submit;+]"
  174. end
  175. return formspec
  176. end
  177. -- check if pos is inside a protected spawn area
  178. local inside_spawn = function(pos, radius)
  179. if protector_spawn <= 0 then
  180. return false
  181. end
  182. if pos.x < statspawn.x + radius
  183. and pos.x > statspawn.x - radius
  184. and pos.y < statspawn.y + radius
  185. and pos.y > statspawn.y - radius
  186. and pos.z < statspawn.z + radius
  187. and pos.z > statspawn.z - radius then
  188. return true
  189. end
  190. return false
  191. end
  192. -- show protection message if enabled
  193. local show_msg = function(player, msg)
  194. -- if messages disabled or no player name provided
  195. if protector_msg == false or not player or player == "" then
  196. return
  197. end
  198. minetest.chat_send_player(player, msg)
  199. end
  200. -- Infolevel:
  201. -- 0 for no info
  202. -- 1 for "This area is owned by <owner> !" if you can't dig
  203. -- 2 for "This area is owned by <owner>.
  204. -- 3 for checking protector overlaps
  205. protector.can_dig = function(r, pos, digger, onlyowner, infolevel)
  206. if not digger or not pos then
  207. return false
  208. end
  209. -- protector_bypass privileged users can override protection
  210. if infolevel == 1
  211. and minetest.check_player_privs(digger, {protection_bypass = true}) then
  212. return true
  213. end
  214. -- infolevel 3 is only used to bypass priv check, change to 1 now
  215. if infolevel == 3 then infolevel = 1 end
  216. -- is spawn area protected ?
  217. if inside_spawn(pos, protector_spawn) then
  218. show_msg(digger,
  219. S("Spawn @1 has been protected up to a @2 block radius.",
  220. minetest.pos_to_string(statspawn), protector_spawn))
  221. return false
  222. end
  223. -- find the protector nodes
  224. local pos = minetest.find_nodes_in_area(
  225. {x = pos.x - r, y = pos.y - r, z = pos.z - r},
  226. {x = pos.x + r, y = pos.y + r, z = pos.z + r},
  227. {"protector:protect", "protector:protect2", "protector:protect_hidden"})
  228. local meta, owner, members
  229. for n = 1, #pos do
  230. meta = minetest.get_meta(pos[n])
  231. owner = meta:get_string("owner") or ""
  232. members = meta:get_string("members") or ""
  233. -- node change and digger isn't owner
  234. if infolevel == 1 and owner ~= digger then
  235. -- and you aren't on the member list
  236. if onlyowner or not is_member(meta, digger) then
  237. show_msg(digger,
  238. S("This area is owned by @1", owner) .. "!")
  239. return false
  240. end
  241. end
  242. -- when using protector as tool, show protector information
  243. if infolevel == 2 then
  244. minetest.chat_send_player(digger,
  245. S("This area is owned by @1", owner) .. ".")
  246. minetest.chat_send_player(digger,
  247. S("Protection located at: @1", minetest.pos_to_string(pos[n])))
  248. if members ~= "" then
  249. minetest.chat_send_player(digger, S("Members: @1.", members))
  250. end
  251. return false
  252. end
  253. end
  254. -- show when you can build on unprotected area
  255. if infolevel == 2 then
  256. if #pos < 1 then
  257. minetest.chat_send_player(digger, S("This area is not protected."))
  258. end
  259. minetest.chat_send_player(digger, S("You can build here."))
  260. end
  261. return true
  262. end
  263. -- add protector hurt and flip to protection violation function
  264. minetest.register_on_protection_violation(function(pos, name)
  265. local player = minetest.get_player_by_name(name)
  266. if player and player:is_player() then
  267. -- hurt player if protection violated
  268. if protector_hurt > 0 and player:get_hp() > 0 then
  269. -- This delay fixes item duplication bug (thanks luk3yx)
  270. minetest.after(0.1, function(player)
  271. player:set_hp(player:get_hp() - protector_hurt)
  272. end, player)
  273. end
  274. -- flip player when protection violated
  275. if protector_flip then
  276. -- yaw + 180°
  277. local yaw = player:get_look_horizontal() + math.pi
  278. if yaw > 2 * math.pi then
  279. yaw = yaw - 2 * math.pi
  280. end
  281. player:set_look_horizontal(yaw)
  282. -- invert pitch
  283. player:set_look_vertical(-player:get_look_vertical())
  284. -- if digging below player, move up to avoid falling through hole
  285. local pla_pos = player:get_pos()
  286. if pos.y < pla_pos.y then
  287. player:set_pos({
  288. x = pla_pos.x,
  289. y = pla_pos.y + 0.8,
  290. z = pla_pos.z
  291. })
  292. end
  293. end
  294. end
  295. end)
  296. local old_is_protected = minetest.is_protected
  297. -- check for protected area, return true if protected and digger isn't on list
  298. function minetest.is_protected(pos, digger)
  299. digger = digger or "" -- nil check
  300. -- is area protected against digger?
  301. if not protector.can_dig(protector_radius, pos, digger, false, 1) then
  302. return true
  303. end
  304. -- otherwise can dig or place
  305. return old_is_protected(pos, digger)
  306. end
  307. -- make sure protection block doesn't overlap another protector's area
  308. local check_overlap = function(itemstack, placer, pointed_thing)
  309. if pointed_thing.type ~= "node" then
  310. return itemstack
  311. end
  312. local pos = pointed_thing.above
  313. local name = placer:get_player_name()
  314. -- make sure protector doesn't overlap onto protected spawn area
  315. if inside_spawn(pos, protector_spawn + protector_radius) then
  316. minetest.chat_send_player(name,
  317. S("Spawn @1 has been protected up to a @2 block radius.",
  318. minetest.pos_to_string(statspawn), protector_spawn))
  319. return itemstack
  320. end
  321. -- make sure protector doesn't overlap any other player's area
  322. if not protector.can_dig(protector_radius * 2, pos, name, true, 3) then
  323. minetest.chat_send_player(name,
  324. S("Overlaps into above players protected area"))
  325. return itemstack
  326. end
  327. return minetest.item_place(itemstack, placer, pointed_thing)
  328. end
  329. -- remove protector display entities
  330. local del_display = function(pos)
  331. local objects = minetest.get_objects_inside_radius(pos, 0.5)
  332. for _, v in ipairs(objects) do
  333. if v and v:get_luaentity()
  334. and v:get_luaentity().name == "protector:display" then
  335. v:remove()
  336. end
  337. end
  338. end
  339. -- temporary pos store
  340. local player_pos = {}
  341. -- protection node
  342. minetest.register_node("protector:protect", {
  343. description = S("Protection Block") .. " (" .. S("USE for area check") .. ")",
  344. drawtype = "nodebox",
  345. tiles = {
  346. "default_stone.png^protector_overlay.png",
  347. "default_stone.png^protector_overlay.png",
  348. "default_stone.png^protector_overlay.png^protector_logo.png"
  349. },
  350. sounds = default.node_sound_stone_defaults(),
  351. groups = {dig_immediate = 2, unbreakable = 1},
  352. is_ground_content = false,
  353. paramtype = "light",
  354. light_source = 4,
  355. node_box = {
  356. type = "fixed",
  357. fixed = {
  358. {-0.499 ,-0.499, -0.499, 0.499, 0.499, 0.499}
  359. }
  360. },
  361. on_place = check_overlap,
  362. after_place_node = function(pos, placer)
  363. local meta = minetest.get_meta(pos)
  364. meta:set_string("owner", placer:get_player_name() or "")
  365. meta:set_string("members", "")
  366. meta:set_string("infotext",
  367. S("Protection (owned by @1)", meta:get_string("owner")))
  368. end,
  369. on_use = function(itemstack, user, pointed_thing)
  370. if pointed_thing.type ~= "node" then
  371. return
  372. end
  373. protector.can_dig(protector_radius, pointed_thing.under,
  374. user:get_player_name(), false, 2)
  375. end,
  376. on_rightclick = function(pos, node, clicker, itemstack)
  377. local meta = minetest.get_meta(pos)
  378. local name = clicker:get_player_name()
  379. if meta
  380. and protector.can_dig(1, pos, name, true, 1) then
  381. player_pos[name] = pos
  382. minetest.show_formspec(name, "protector:node", protector_formspec(meta))
  383. end
  384. end,
  385. on_punch = function(pos, node, puncher)
  386. if minetest.is_protected(pos, puncher:get_player_name()) then
  387. return
  388. end
  389. minetest.add_entity(pos, "protector:display")
  390. end,
  391. can_dig = function(pos, player)
  392. return player and protector.can_dig(1, pos, player:get_player_name(), true, 1)
  393. end,
  394. on_blast = function() end,
  395. after_destruct = del_display
  396. })
  397. -- default recipe and alternative for MineClone2
  398. if protector_recipe then
  399. if minetest.registered_items["default:stone"] then
  400. minetest.register_craft({
  401. output = "protector:protect",
  402. recipe = {
  403. {"default:stone", "default:stone", "default:stone"},
  404. {"default:stone", "default:gold_ingot", "default:stone"},
  405. {"default:stone", "default:stone", "default:stone"}
  406. }
  407. })
  408. else
  409. minetest.register_craft({
  410. output = "protector:protect",
  411. recipe = {
  412. {"mcl_core:stone", "mcl_core:stone", "mcl_core:stone"},
  413. {"mcl_core:stone", "mcl_core:gold_ingot", "mcl_core:stone"},
  414. {"mcl_core:stone", "mcl_core:stone", "mcl_core:stone"}
  415. }
  416. })
  417. end
  418. end
  419. -- protection logo
  420. minetest.register_node("protector:protect2", {
  421. description = S("Protection Logo") .. " (" .. S("USE for area check") .. ")",
  422. tiles = {"protector_logo.png"},
  423. wield_image = "protector_logo.png",
  424. inventory_image = "protector_logo.png",
  425. sounds = default.node_sound_stone_defaults(),
  426. groups = {dig_immediate = 2, unbreakable = 1},
  427. use_texture_alpha = "clip",
  428. paramtype = "light",
  429. paramtype2 = "wallmounted",
  430. legacy_wallmounted = true,
  431. light_source = 4,
  432. drawtype = "nodebox",
  433. sunlight_propagates = true,
  434. walkable = true,
  435. node_box = {
  436. type = "wallmounted",
  437. wall_top = {-0.375, 0.4375, -0.5, 0.375, 0.5, 0.5},
  438. wall_bottom = {-0.375, -0.5, -0.5, 0.375, -0.4375, 0.5},
  439. wall_side = {-0.5, -0.5, -0.375, -0.4375, 0.5, 0.375}
  440. },
  441. selection_box = {type = "wallmounted"},
  442. on_place = check_overlap,
  443. after_place_node = function(pos, placer)
  444. local meta = minetest.get_meta(pos)
  445. meta:set_string("owner", placer:get_player_name() or "")
  446. meta:set_string("members", "")
  447. meta:set_string("infotext",
  448. S("Protection (owned by @1)", meta:get_string("owner")))
  449. end,
  450. on_use = function(itemstack, user, pointed_thing)
  451. if pointed_thing.type ~= "node" then
  452. return
  453. end
  454. protector.can_dig(protector_radius, pointed_thing.under,
  455. user:get_player_name(), false, 2)
  456. end,
  457. on_rightclick = function(pos, node, clicker, itemstack)
  458. local meta = minetest.get_meta(pos)
  459. local name = clicker:get_player_name()
  460. if meta
  461. and protector.can_dig(1, pos, name, true, 1) then
  462. player_pos[name] = pos
  463. minetest.show_formspec(name, "protector:node", protector_formspec(meta))
  464. end
  465. end,
  466. on_punch = function(pos, node, puncher)
  467. if minetest.is_protected(pos, puncher:get_player_name()) then
  468. return
  469. end
  470. minetest.add_entity(pos, "protector:display")
  471. end,
  472. can_dig = function(pos, player)
  473. return player and protector.can_dig(1, pos, player:get_player_name(), true, 1)
  474. end,
  475. on_blast = function() end,
  476. after_destruct = del_display
  477. })
  478. -- recipes to switch between protectors
  479. minetest.register_craft({
  480. output = "protector:protect",
  481. recipe = {{"protector:protect2"}}
  482. })
  483. minetest.register_craft({
  484. output = "protector:protect2",
  485. recipe = {{"protector:protect"}}
  486. })
  487. -- check formspec buttons or when name entered
  488. minetest.register_on_player_receive_fields(function(player, formname, fields)
  489. if formname ~= "protector:node" then
  490. return
  491. end
  492. local name = player:get_player_name()
  493. local pos = player_pos[name]
  494. if not name or not pos then
  495. return
  496. end
  497. local add_member_input = fields.protector_add_member
  498. -- reset formspec until close button pressed
  499. if (fields.close_me or fields.quit)
  500. and (not add_member_input or add_member_input == "") then
  501. player_pos[name] = nil
  502. return
  503. end
  504. -- only owner can add names
  505. if not protector.can_dig(1, pos, player:get_player_name(), true, 1) then
  506. return
  507. end
  508. -- are we adding member to a protection node ? (csm protection)
  509. local nod = minetest.get_node(pos).name
  510. if nod ~= "protector:protect"
  511. and nod ~= "protector:protect2" then
  512. player_pos[name] = nil
  513. return
  514. end
  515. local meta = minetest.get_meta(pos)
  516. if not meta then
  517. return
  518. end
  519. -- add faction members
  520. if factions_available and fields.faction_members ~= nil then
  521. meta:set_int("faction_members", fields.faction_members == "true" and 1 or 0)
  522. end
  523. -- add member [+]
  524. if add_member_input then
  525. for _, i in pairs(add_member_input:split(" ")) do
  526. add_member(meta, i)
  527. end
  528. end
  529. -- remove member [x]
  530. for field, value in pairs(fields) do
  531. if string.sub(field, 0,
  532. string.len("protector_del_member_")) == "protector_del_member_" then
  533. del_member(meta,
  534. string.sub(field,string.len("protector_del_member_") + 1))
  535. end
  536. end
  537. minetest.show_formspec(name, formname, protector_formspec(meta))
  538. end)
  539. -- display entity shown when protector node is punched
  540. minetest.register_entity("protector:display", {
  541. initial_properties = {
  542. physical = false,
  543. collisionbox = {0, 0, 0, 0, 0, 0},
  544. visual = "wielditem",
  545. -- wielditem seems to be scaled to 1.5 times original node size
  546. visual_size = {x = 0.67, y = 0.67},
  547. textures = {"protector:display_node"},
  548. glow = 10
  549. },
  550. timer = 0,
  551. on_step = function(self, dtime)
  552. self.timer = self.timer + dtime
  553. -- remove after set number of seconds
  554. if self.timer > protector_show then
  555. self.object:remove()
  556. end
  557. end
  558. })
  559. -- Display-zone node, Do NOT place the display as a node,
  560. -- it is made to be used as an entity (see above)
  561. local x = protector_radius
  562. minetest.register_node("protector:display_node", {
  563. tiles = {"protector_display.png"},
  564. use_texture_alpha = "clip",
  565. walkable = false,
  566. drawtype = "nodebox",
  567. node_box = {
  568. type = "fixed",
  569. fixed = {
  570. -- sides
  571. {-(x+.55), -(x+.55), -(x+.55), -(x+.45), (x+.55), (x+.55)},
  572. {-(x+.55), -(x+.55), (x+.45), (x+.55), (x+.55), (x+.55)},
  573. {(x+.45), -(x+.55), -(x+.55), (x+.55), (x+.55), (x+.55)},
  574. {-(x+.55), -(x+.55), -(x+.55), (x+.55), (x+.55), -(x+.45)},
  575. -- top
  576. {-(x+.55), (x+.45), -(x+.55), (x+.55), (x+.55), (x+.55)},
  577. -- bottom
  578. {-(x+.55), -(x+.55), -(x+.55), (x+.55), -(x+.45), (x+.55)},
  579. -- middle (surround protector)
  580. {-.55,-.55,-.55, .55,.55,.55}
  581. }
  582. },
  583. selection_box = {
  584. type = "regular",
  585. },
  586. paramtype = "light",
  587. groups = {dig_immediate = 3, not_in_creative_inventory = 1},
  588. drop = ""
  589. })
  590. dofile(MP .. "/doors_chest.lua")
  591. dofile(MP .. "/pvp.lua")
  592. dofile(MP .. "/admin.lua")
  593. dofile(MP .. "/tool.lua")
  594. dofile(MP .. "/hud.lua")
  595. if minetest.get_modpath("lucky_block") then
  596. dofile(MP .. "/lucky_block.lua")
  597. end
  598. -- stop mesecon pistons from pushing protectors
  599. if minetest.get_modpath("mesecons_mvps") then
  600. mesecon.register_mvps_stopper("protector:protect")
  601. mesecon.register_mvps_stopper("protector:protect2")
  602. mesecon.register_mvps_stopper("protector:chest")
  603. end
  604. print ("[MOD] Protector Redo loaded")