ADDED protector_pvp switch to disable pvp inside player's own protected areas
[protector.git] / init.lua
1 minetest.register_privilege("delprotect","Ignore player protection")
2
3 protector = {}
4 protector.mod = "redo"
5 protector.radius = (tonumber(minetest.setting_get("protector_radius")) or 5)
6 protector.pvp = minetest.setting_get("protector_pvp") or false
7
8 protector.get_member_list = function(meta)
9 return meta:get_string("members"):split(" ")
10 end
11
12 protector.set_member_list = function(meta, list)
13 meta:set_string("members", table.concat(list, " "))
14 end
15
16 protector.is_member = function (meta, name)
17 for _, n in ipairs(protector.get_member_list(meta)) do
18 if n == name then
19 return true
20 end
21 end
22 return false
23 end
24
25 protector.add_member = function(meta, name)
26 if protector.is_member(meta, name) then return end
27 local list = protector.get_member_list(meta)
28 table.insert(list, name)
29 protector.set_member_list(meta,list)
30 end
31
32 protector.del_member = function(meta, name)
33 local list = protector.get_member_list(meta)
34 for i, n in ipairs(list) do
35 if n == name then
36 table.remove(list, i)
37 break
38 end
39 end
40 protector.set_member_list(meta, list)
41 end
42
43 -- Protector Interface
44
45 protector.generate_formspec = function(meta)
46
47 local formspec = "size[8,7]"
48 ..default.gui_bg..default.gui_bg_img..default.gui_slots
49 .."label[2.5,0;-- Protector interface --]"
50 .."label[0,1;PUNCH node to show protected area or USE for area check]"
51 .."label[0,2;Members: (type player name then press Enter to add)]"
52
53 local members = protector.get_member_list(meta)
54 local npp = 12
55 local i = 0
56 for _, member in ipairs(members) do
57 if i < npp then
58 formspec = formspec .. "button[" .. (i % 4 * 2)
59 .. "," .. math.floor(i / 4 + 3)
60 .. ";1.5,.5;protector_member;" .. member .. "]"
61 .. "button[" .. (i % 4 * 2 + 1.25) .. ","
62 .. math.floor(i / 4 + 3)
63 .. ";.75,.5;protector_del_member_" .. member .. ";X]"
64 end
65 i = i + 1
66 end
67
68 if i < npp then
69 formspec = formspec .. "field[" .. (i % 4 * 2 + 1 / 3) .. ","
70 .. (math.floor(i / 4 + 3) + 1 / 3) .. ";1.433,.5;protector_add_member;;]"
71 end
72
73 formspec = formspec .. "button_exit[2.5,6.2;3,0.5;close_me;Close]"
74
75 return formspec
76 end
77
78 -- ACTUAL PROTECTION SECTION
79
80 -- Infolevel:
81 -- 0 for no info
82 -- 1 for "This area is owned by <owner> !" if you can't dig
83 -- 2 for "This area is owned by <owner>.
84 -- 3 for checking protector overlaps
85
86 protector.can_dig = function(r, pos, digger, onlyowner, infolevel)
87
88 if not digger then
89 return false
90 end
91
92 -- Delprotect privileged users can override protections
93
94 if minetest.check_player_privs(digger, {delprotect = true})
95 and infolevel == 1 then
96 return true
97 end
98
99 if infolevel == 3 then infolevel = 1 end
100
101 -- Find the protector nodes
102
103 local positions = minetest.find_nodes_in_area(
104 {x = pos.x - r, y = pos.y - r, z = pos.z - r},
105 {x = pos.x + r, y = pos.y + r, z = pos.z + r},
106 {"protector:protect", "protector:protect2"})
107
108 local meta, owner, members
109 for _, pos in ipairs(positions) do
110 meta = minetest.get_meta(pos)
111 owner = meta:get_string("owner")
112 members = meta:get_string("members")
113
114 if owner ~= digger then
115 if onlyowner or not protector.is_member(meta, digger) then
116 if infolevel == 1 then
117 minetest.chat_send_player(digger,
118 "This area is owned by " .. owner .. " !")
119 elseif infolevel == 2 then
120 minetest.chat_send_player(digger,
121 "This area is owned by " .. owner .. ".")
122 minetest.chat_send_player(digger,
123 "Protection located at: " .. minetest.pos_to_string(pos))
124 if members ~= "" then
125 minetest.chat_send_player(digger,
126 "Members: " .. members .. ".")
127 end
128 end
129 return false
130 end
131 end
132
133 if infolevel == 2 then
134 minetest.chat_send_player(digger,
135 "This area is owned by " .. owner .. ".")
136 minetest.chat_send_player(digger,
137 "Protection located at: " .. minetest.pos_to_string(positions[1]))
138 if members ~= "" then
139 minetest.chat_send_player(digger,
140 "Members: " .. members .. ".")
141 end
142 end
143
144 end
145
146 if infolevel == 2 then
147 if #positions < 1 then
148 minetest.chat_send_player(digger,
149 "This area is not protected.")
150 end
151 minetest.chat_send_player(digger, "You can build here.")
152 end
153
154 return true
155 end
156
157 -- Can node be added or removed, if so return node else true (for protected)
158
159 protector.old_is_protected = minetest.is_protected
160
161 function minetest.is_protected(pos, digger)
162
163 if not protector.can_dig(protector.radius, pos, digger, false, 1) then
164 -- hurt here
165 --player = minetest.get_player_by_name(digger)
166 --player:set_hp(player:get_hp()-2)
167 return true
168 end
169 return protector.old_is_protected(pos, digger)
170
171 end
172
173 -- Make sure protection block doesn't overlap another protector's area
174
175 protector.old_node_place = minetest.item_place
176
177 function minetest.item_place(itemstack, placer, pointed_thing)
178
179 if itemstack:get_name() == "protector:protect"
180 or itemstack:get_name() == "protector:protect2" then
181 local user = placer:get_player_name()
182 if not protector.can_dig(protector.radius * 2, pointed_thing.above, user, true, 3) then
183 minetest.chat_send_player(user,
184 "Overlaps into another protected area")
185 return protector.old_node_place(itemstack, placer, pointed_thing.above)
186 end
187 end
188
189 return protector.old_node_place(itemstack, placer, pointed_thing)
190 end
191
192 -- END
193
194 --= Protection Block
195
196 minetest.register_node("protector:protect", {
197 description = "Protection Block",
198 tiles = {
199 "moreblocks_circle_stone_bricks.png",
200 "moreblocks_circle_stone_bricks.png",
201 "moreblocks_circle_stone_bricks.png^protector_logo.png"
202 },
203 sounds = default.node_sound_stone_defaults(),
204 groups = {dig_immediate = 2, unbreakable = 1},
205 paramtype = "light",
206 light_source = 2,
207
208 after_place_node = function(pos, placer)
209 local meta = minetest.get_meta(pos)
210 meta:set_string("owner", placer:get_player_name() or "")
211 meta:set_string("infotext", "Protection (owned by " .. meta:get_string("owner") .. ")")
212 meta:set_string("members", "")
213 end,
214
215 on_use = function(itemstack, user, pointed_thing)
216 if pointed_thing.type ~= "node" then return end
217 protector.can_dig(protector.radius, pointed_thing.under, user:get_player_name(), false, 2)
218 end,
219
220 on_rightclick = function(pos, node, clicker, itemstack)
221 local meta = minetest.get_meta(pos)
222 if protector.can_dig(1, pos,clicker:get_player_name(), true, 1) then
223 minetest.show_formspec(clicker:get_player_name(),
224 "protector:node_" .. minetest.pos_to_string(pos), protector.generate_formspec(meta))
225 end
226 end,
227
228 on_punch = function(pos, node, puncher)
229 if not protector.can_dig(1, pos, puncher:get_player_name(), true, 1) then
230 return
231 end
232 minetest.add_entity(pos, "protector:display")
233 end,
234
235 can_dig = function(pos, player)
236 return protector.can_dig(1, pos, player:get_player_name(), true, 1)
237 end,
238 })
239
240 minetest.register_craft({
241 output = "protector:protect 4",
242 recipe = {
243 {"default:stone", "default:stone", "default:stone"},
244 {"default:stone", "default:steel_ingot", "default:stone"},
245 {"default:stone", "default:stone", "default:stone"},
246 }
247 })
248
249 --= Protection Logo
250
251 minetest.register_node("protector:protect2", {
252 description = "Protection Logo",
253 tiles = {"protector_logo.png"},
254 wield_image = "protector_logo.png",
255 inventory_image = "protector_logo.png",
256 sounds = default.node_sound_stone_defaults(),
257 groups = {dig_immediate = 2, unbreakable = 1},
258 paramtype = 'light',
259 paramtype2 = "wallmounted",
260 light_source = 2,
261 drawtype = "nodebox",
262 sunlight_propagates = true,
263 walkable = true,
264 node_box = {
265 type = "wallmounted",
266 wall_top = {-0.375, 0.4375, -0.5, 0.375, 0.5, 0.5},
267 wall_bottom = {-0.375, -0.5, -0.5, 0.375, -0.4375, 0.5},
268 wall_side = {-0.5, -0.5, -0.375, -0.4375, 0.5, 0.375},
269 },
270 selection_box = {type = "wallmounted"},
271
272 after_place_node = function(pos, placer)
273 local meta = minetest.get_meta(pos)
274 meta:set_string("owner", placer:get_player_name() or "")
275 meta:set_string("infotext", "Protection (owned by " .. meta:get_string("owner") .. ")")
276 meta:set_string("members", "")
277 end,
278
279 on_use = function(itemstack, user, pointed_thing)
280 if pointed_thing.type ~= "node" then return end
281 protector.can_dig(protector.radius, pointed_thing.under, user:get_player_name(), false, 2)
282 end,
283
284 on_rightclick = function(pos, node, clicker, itemstack)
285 local meta = minetest.get_meta(pos)
286 if protector.can_dig(1, pos, clicker:get_player_name(), true, 1) then
287 minetest.show_formspec(clicker:get_player_name(),
288 "protector:node_" .. minetest.pos_to_string(pos), protector.generate_formspec(meta))
289 end
290 end,
291
292 on_punch = function(pos, node, puncher)
293 if not protector.can_dig(1, pos, puncher:get_player_name(), true, 1) then
294 return
295 end
296 minetest.add_entity(pos, "protector:display")
297 end,
298
299 can_dig = function(pos, player)
300 return protector.can_dig(1, pos, player:get_player_name(), true, 1)
301 end,
302 })
303
304 minetest.register_craft({
305 output = "protector:protect2 4",
306 recipe = {
307 {"default:stone", "default:stone", "default:stone"},
308 {"default:stone", "default:copper_ingot", "default:stone"},
309 {"default:stone", "default:stone", "default:stone"},
310 }
311 })
312
313 -- If name entered or button press
314 minetest.register_on_player_receive_fields(function(player,formname,fields)
315
316 if string.sub(formname, 0, string.len("protector:node_")) == "protector:node_" then
317
318 local pos_s = string.sub(formname, string.len("protector:node_") + 1)
319 local pos = minetest.string_to_pos(pos_s)
320 local meta = minetest.get_meta(pos)
321
322 if not protector.can_dig(1, pos, player:get_player_name(), true, 1) then
323 return
324 end
325
326 if fields.protector_add_member then
327 for _, i in ipairs(fields.protector_add_member:split(" ")) do
328 protector.add_member(meta, i)
329 end
330 end
331
332 for field, value in pairs(fields) do
333 if string.sub(field, 0, string.len("protector_del_member_")) == "protector_del_member_" then
334 protector.del_member(meta, string.sub(field,string.len("protector_del_member_") + 1))
335 end
336 end
337
338 if not fields.close_me then
339 minetest.show_formspec(player:get_player_name(), formname, protector.generate_formspec(meta))
340 end
341
342 end
343
344 end)
345
346 minetest.register_entity("protector:display", {
347 physical = false,
348 collisionbox = {0, 0, 0, 0, 0, 0},
349 visual = "wielditem",
350 -- wielditem seems to be scaled to 1.5 times original node size
351 visual_size = {x = 1.0 / 1.5, y = 1.0 / 1.5},
352 textures = {"protector:display_node"},
353 on_step = function(self, dtime)
354 self.timer = (self.timer or 0) + dtime
355 if self.timer > 10 then
356 self.object:remove()
357 end
358 end,
359 })
360
361 -- Display-zone node, Do NOT place the display as a node,
362 -- it is made to be used as an entity (see above)
363 local x = protector.radius
364 minetest.register_node("protector:display_node", {
365 tiles = {"protector_display.png"},
366 use_texture_alpha = true,
367 walkable = false,
368 drawtype = "nodebox",
369 node_box = {
370 type = "fixed",
371 fixed = {
372 -- sides
373 {-(x+.55), -(x+.55), -(x+.55), -(x+.45), (x+.55), (x+.55)},
374 {-(x+.55), -(x+.55), (x+.45), (x+.55), (x+.55), (x+.55)},
375 {(x+.45), -(x+.55), -(x+.55), (x+.55), (x+.55), (x+.55)},
376 {-(x+.55), -(x+.55), -(x+.55), (x+.55), (x+.55), -(x+.45)},
377 -- top
378 {-(x+.55), (x+.45), -(x+.55), (x+.55), (x+.55), (x+.55)},
379 -- bottom
380 {-(x+.55), -(x+.55), -(x+.55), (x+.55), -(x+.45), (x+.55)},
381 -- middle (surround protector)
382 {-.55,-.55,-.55, .55,.55,.55},
383 },
384 },
385 selection_box = {
386 type = "regular",
387 },
388 paramtype = "light",
389 groups = {dig_immediate = 3, not_in_creative_inventory = 1},
390 drop = "",
391 })
392
393 -- Register Protected Doors
394
395 local function on_rightclick(pos, dir, check_name, replace, replace_dir, params)
396 pos.y = pos.y+dir
397 if not minetest.get_node(pos).name == check_name then
398 return
399 end
400 local p2 = minetest.get_node(pos).param2
401 p2 = params[p2 + 1]
402
403 minetest.swap_node(pos, {name = replace_dir, param2 = p2})
404
405 pos.y = pos.y-dir
406 minetest.swap_node(pos, {name = replace, param2 = p2})
407
408 local snd_1 = "doors_door_close"
409 local snd_2 = "doors_door_open"
410 if params[1] == 3 then
411 snd_1 = "doors_door_open"
412 snd_2 = "doors_door_close"
413 end
414
415 if minetest.get_meta(pos):get_int("right") ~= 0 then
416 minetest.sound_play(snd_1, {
417 pos = pos, gain = 0.3, max_hear_distance = 10})
418 else
419 minetest.sound_play(snd_2, {
420 pos = pos, gain = 0.3, max_hear_distance = 10})
421 end
422 end
423
424 -- Protected Wooden Door
425
426 local name = "protector:door_wood"
427
428 doors.register_door(name, {
429 description = "Protected Wooden Door",
430 inventory_image = "doors_wood.png^protector_logo.png",
431 groups = {
432 snappy = 1, choppy = 2, oddly_breakable_by_hand = 2,
433 door = 1, unbreakable = 1
434 },
435 tiles_bottom = {"doors_wood_b.png^protector_logo.png", "doors_brown.png"},
436 tiles_top = {"doors_wood_a.png", "doors_brown.png"},
437 sounds = default.node_sound_wood_defaults(),
438 sunlight = false,
439 })
440
441 minetest.override_item(name .. "_b_1", {
442 on_rightclick = function(pos, node, clicker)
443 if not minetest.is_protected(pos, clicker:get_player_name()) then
444 on_rightclick(pos, 1,
445 name .. "_t_1", name .. "_b_2", name .. "_t_2", {1, 2, 3, 0})
446 end
447 end,
448 })
449
450 minetest.override_item(name.."_t_1", {
451 on_rightclick = function(pos, node, clicker)
452 if not minetest.is_protected(pos, clicker:get_player_name()) then
453 on_rightclick(pos, -1,
454 name .. "_b_1", name .. "_t_2", name .. "_b_2", {1, 2, 3, 0})
455 end
456 end,
457 })
458
459 minetest.override_item(name.."_b_2", {
460 on_rightclick = function(pos, node, clicker)
461 if not minetest.is_protected(pos, clicker:get_player_name()) then
462 on_rightclick(pos, 1,
463 name .. "_t_2", name .. "_b_1", name .. "_t_1", {3, 0, 1, 2})
464 end
465 end,
466 })
467
468 minetest.override_item(name.."_t_2", {
469 on_rightclick = function(pos, node, clicker)
470 if not minetest.is_protected(pos, clicker:get_player_name()) then
471 on_rightclick(pos, -1,
472 name .. "_b_2", name .. "_t_1", name .. "_b_1", {3, 0, 1, 2})
473 end
474 end,
475 })
476
477 minetest.register_craft({
478 output = name,
479 recipe = {
480 {"group:wood", "group:wood"},
481 {"group:wood", "default:copper_ingot"},
482 {"group:wood", "group:wood"}
483 }
484 })
485
486 minetest.register_craft({
487 output = name,
488 recipe = {
489 {"doors:door_wood", "default:copper_ingot"}
490 }
491 })
492
493 -- Protected Steel Door
494
495 local name = "protector:door_steel"
496
497 doors.register_door(name, {
498 description = "Protected Steel Door",
499 inventory_image = "doors_steel.png^protector_logo.png",
500 groups = {
501 snappy = 1, bendy = 2, cracky = 1,
502 level = 2, door = 1, unbreakable = 1
503 },
504 tiles_bottom = {"doors_steel_b.png^protector_logo.png", "doors_grey.png"},
505 tiles_top = {"doors_steel_a.png", "doors_grey.png"},
506 sounds = default.node_sound_wood_defaults(),
507 sunlight = false,
508 })
509
510 minetest.override_item(name.."_b_1", {
511 on_rightclick = function(pos, node, clicker)
512 if not minetest.is_protected(pos, clicker:get_player_name()) then
513 on_rightclick(pos, 1,
514 name .. "_t_1", name .. "_b_2", name .. "_t_2", {1, 2, 3, 0})
515 end
516 end,
517 })
518
519 minetest.override_item(name.."_t_1", {
520 on_rightclick = function(pos, node, clicker)
521 if not minetest.is_protected(pos, clicker:get_player_name()) then
522 on_rightclick(pos, -1,
523 name .. "_b_1", name .. "_t_2", name .. "_b_2", {1, 2, 3, 0})
524 end
525 end,
526 })
527
528 minetest.override_item(name.."_b_2", {
529 on_rightclick = function(pos, node, clicker)
530 if not minetest.is_protected(pos, clicker:get_player_name()) then
531 on_rightclick(pos, 1,
532 name .. "_t_2", name .. "_b_1", name .. "_t_1", {3, 0, 1, 2})
533 end
534 end,
535 })
536
537 minetest.override_item(name.."_t_2", {
538 on_rightclick = function(pos, node, clicker)
539 if not minetest.is_protected(pos, clicker:get_player_name()) then
540 on_rightclick(pos, -1,
541 name .. "_b_2", name .. "_t_1", name .. "_b_1", {3, 0, 1, 2})
542 end
543 end,
544 })
545
546 minetest.register_craft({
547 output = name,
548 recipe = {
549 {"default:steel_ingot", "default:steel_ingot"},
550 {"default:steel_ingot", "default:copper_ingot"},
551 {"default:steel_ingot", "default:steel_ingot"}
552 }
553 })
554
555 minetest.register_craft({
556 output = name,
557 recipe = {
558 {"doors:door_steel", "default:copper_ingot"}
559 }
560 })
561
562 -- Protected Chest
563
564 minetest.register_node("protector:chest", {
565 description = "Protected Chest",
566 tiles = {
567 "default_chest_top.png", "default_chest_top.png",
568 "default_chest_side.png", "default_chest_side.png",
569 "default_chest_side.png", "default_chest_front.png^protector_logo.png"
570 },
571 paramtype2 = "facedir",
572 groups = {choppy = 2, oddly_breakable_by_hand = 2, unbreakable = 1},
573 legacy_facedir_simple = true,
574 is_ground_content = false,
575 sounds = default.node_sound_wood_defaults(),
576
577 on_construct = function(pos)
578 local meta = minetest.get_meta(pos)
579 meta:set_string("infotext", "Protected Chest")
580 meta:set_string("name", "")
581 local inv = meta:get_inventory()
582 inv:set_size("main", 8 * 4)
583 end,
584
585 can_dig = function(pos,player)
586 local meta = minetest.get_meta(pos)
587 local inv = meta:get_inventory()
588 if inv:is_empty("main") then
589 if not minetest.is_protected(pos, player:get_player_name()) then
590 return true
591 end
592 end
593 end,
594
595 on_metadata_inventory_put = function(pos, listname, index, stack, player)
596 minetest.log("action", player:get_player_name() ..
597 " moves stuff to protected chest at " .. minetest.pos_to_string(pos))
598 end,
599
600 on_metadata_inventory_take = function(pos, listname, index, stack, player)
601 minetest.log("action", player:get_player_name() ..
602 " takes stuff from protected chest at " .. minetest.pos_to_string(pos))
603 end,
604
605 on_rightclick = function(pos, node, clicker)
606 if not minetest.is_protected(pos, clicker:get_player_name()) then
607 local meta = minetest.get_meta(pos)
608 local spos = pos.x .. "," .. pos.y .. "," ..pos.z
609 local formspec = "size[8,9]"..
610 default.gui_bg..default.gui_bg_img..default.gui_slots
611 .. "list[nodemeta:".. spos .. ";main;0,0.3;8,4;]"
612 .. "button[0,4.5;2,0.25;toup;To Chest]"
613 .. "field[2.3,4.8;4,0.25;chestname;;"
614 .. meta:get_string("name") .. "]"
615 .. "button[6,4.5;2,0.25;todn;To Inventory]"
616 .. "list[current_player;main;0,5;8,1;]"
617 .. "list[current_player;main;0,6.08;8,3;8]"
618 .. default.get_hotbar_bg(0,5)
619
620 minetest.show_formspec(
621 clicker:get_player_name(),
622 "protector:chest_" .. minetest.pos_to_string(pos),
623 formspec)
624 end
625 end,
626 })
627
628 -- Protected Chest formspec buttons
629
630 minetest.register_on_player_receive_fields(function(player, formname, fields)
631
632 if string.sub(formname, 0, string.len("protector:chest_")) == "protector:chest_" then
633
634 local pos_s = string.sub(formname,string.len("protector:chest_") + 1)
635 local pos = minetest.string_to_pos(pos_s)
636 local meta = minetest.get_meta(pos)
637 local chest_inv = meta:get_inventory()
638 local player_inv = player:get_inventory()
639
640 if fields.toup then
641
642 -- copy contents of players inventory to chest
643 for i, v in ipairs (player_inv:get_list("main") or {}) do
644 if (chest_inv and chest_inv:room_for_item('main', v)) then
645 local leftover = chest_inv:add_item('main', v)
646 player_inv:remove_item("main", v)
647 if (leftover and not(leftover:is_empty())) then
648 player_inv:add_item("main", v)
649 end
650 end
651 end
652
653 elseif fields.todn then
654
655 -- copy contents of chest to players inventory
656 for i, v in ipairs (chest_inv:get_list('main') or {}) do
657 if (player_inv:room_for_item("main", v)) then
658 local leftover = player_inv:add_item("main", v)
659 chest_inv:remove_item('main', v)
660 if( leftover and not(leftover:is_empty())) then
661 chest_inv:add_item('main', v)
662 end
663 end
664 end
665
666 elseif fields.chestname then
667
668 -- change chest infotext to display name
669 if fields.chestname ~= "" then
670 meta:set_string("name", fields.chestname)
671 meta:set_string("infotext",
672 "Protected Chest (" .. fields.chestname .. ")")
673 else
674 meta:set_string("infotext", "Protected Chest")
675 end
676
677 end
678 end
679
680 end)
681
682 -- Protected Chest recipe
683
684 minetest.register_craft({
685 output = 'protector:chest',
686 recipe = {
687 {'group:wood', 'group:wood', 'group:wood'},
688 {'group:wood', 'default:copper_ingot', 'group:wood'},
689 {'group:wood', 'group:wood', 'group:wood'},
690 }
691 })
692
693 minetest.register_craft({
694 output = 'protector:chest',
695 recipe = {
696 {'default:chest', 'default:copper_ingot', ''},
697 }
698 })
699
700 -- Disable PVP in your own protected areas
701 if minetest.setting_getbool("enable_pvp") and protector.pvp == "true" then
702
703 if minetest.register_on_punchplayer then
704
705 minetest.register_on_punchplayer(
706 function(player, hitter, time_from_last_punch, tool_capabilities, dir, damage)
707
708 if not player or not hitter then
709 print("on_punchplayer called with nil objects")
710 end
711
712 if not hitter:is_player() then
713 return false
714 end
715
716 if minetest.is_protected(player:getpos(), hitter:get_player_name()) then
717 return true
718 else
719 return false
720 end
721
722 end)
723 else
724 print("PVP protection not active, update your version of Minetest")
725
726 end
727 else
728 print("PVP is disabled in world")
729 end