From 7b63e066977fc870c5c08dc6581522d2fb0eed5b Mon Sep 17 00:00:00 2001 From: MeseCraft Date: Fri, 25 Dec 2020 02:31:51 +0000 Subject: [PATCH] Upload files to '' protector & playerfactions resolution - fixed function call name check - fixed nil check on function - fixed missing variable for owner. --- admin.lua | 239 ++++++++++++++ depends.txt | 5 + description.txt | 1 + hud.lua | 67 ++++ init.lua | 798 +++++++++++++++++++++++++++++++++++++++++++++++ intllib.lua | 45 +++ license.txt | 21 ++ lucky_block.lua | 18 ++ pvp.lua | 72 +++++ settingtypes.txt | 32 ++ 10 files changed, 1298 insertions(+) create mode 100644 admin.lua create mode 100644 depends.txt create mode 100644 description.txt create mode 100644 hud.lua create mode 100644 init.lua create mode 100644 intllib.lua create mode 100644 license.txt create mode 100644 lucky_block.lua create mode 100644 pvp.lua create mode 100644 settingtypes.txt diff --git a/admin.lua b/admin.lua new file mode 100644 index 0000000..ad1afce --- /dev/null +++ b/admin.lua @@ -0,0 +1,239 @@ + +local S = protector.intllib +local removal_names = "" +local replace_names = "" + +minetest.register_chatcommand("protector_remove", { + params = S(""), + description = S("Remove Protectors around players (separate names with spaces)"), + privs = {server = true}, + func = function(name, param) + + if not param or param == "" then + + minetest.chat_send_player(name, + S("Protector Names to remove: @1", + removal_names)) + + return + end + + if param == "-" then + + minetest.chat_send_player(name, + S("Name List Reset")) + + removal_names = "" + + return + end + + removal_names = param + end, +}) + + +minetest.register_chatcommand("protector_replace", { + params = S(" "), + description = S("Replace Protector Owner with name provided"), + privs = {server = true}, + func = function(name, param) + + -- reset list to empty + if param == "-" then + + minetest.chat_send_player(name, S("Name List Reset")) + + replace_names = "" + + return + end + + -- show name info + if param == "" + and replace_names ~= "" then + + local names = replace_names:split(" ") + + minetest.chat_send_player(name, + S("Replacing Protector name @1 with @2", + names[1] or "", names[2] or "")) + + return + end + + replace_names = param + end, +}) + + +minetest.register_abm({ + nodenames = {"protector:protect", "protector:protect2", "protector:protect_hidden"}, + interval = 8, + chance = 1, + catch_up = false, + action = function(pos, node) + + if removal_names == "" + and replace_names == "" then + return + end + + local meta = minetest.get_meta(pos) + + if not meta then return end + + local owner = meta:get_string("owner") + + if removal_names ~= "" then + + local names = removal_names:split(" ") + + for _, n in pairs(names) do + if n == owner then + minetest.set_node(pos, {name = "air"}) + end + end + end + + if replace_names ~= "" then + + local names = replace_names:split(" ") + + if names[1] and names[2] and owner == names[1] then + meta:set_string("owner", names[2]) + meta:set_string("infotext", S("Protection (owned by @1)", names[2])) + end + end + end +}) + +-- get protection radius +local r = tonumber(minetest.settings:get("protector_radius")) or 5 + +-- show protection areas of nearby protectors owned by you (thanks agaran) +minetest.register_chatcommand("protector_show_area", { + params = "", + description = S("Show protected areas of your nearby protectors"), + privs = {}, + func = function(name, param) + + local player = minetest.get_player_by_name(name) + local pos = player:get_pos() + + -- find the protector nodes + local pos = minetest.find_nodes_in_area( + {x = pos.x - r, y = pos.y - r, z = pos.z - r}, + {x = pos.x + r, y = pos.y + r, z = pos.z + r}, + {"protector:protect", "protector:protect2", "protector:protect_hidden"}) + + local meta, owner + + -- show a maximum of 5 protected areas only + for n = 1, math.min(#pos, 5) do + + meta = minetest.get_meta(pos[n]) + owner = meta:get_string("owner") or "" + + if owner == name + or minetest.check_player_privs(name, {protection_bypass = true}) then + minetest.add_entity(pos[n], "protector:display") + end + end + end +}) + + +-- ability to hide protection blocks (borrowed from doors mod :) +minetest.register_node("protector:protect_hidden", { + description = "Hidden Protector", + drawtype = "airlike", + paramtype = "light", + paramtype2 = "facedir", + sunlight_propagates = true, + -- has to be walkable for falling nodes to stop falling + walkable = true, + pointable = false, + diggable = false, + buildable_to = false, + floodable = false, + drop = "", + groups = {not_in_creative_inventory = 1, unbreakable = 1}, + on_blast = function() end, + -- 1px block inside door hinge near node top + collision_box = { + type = "fixed", + fixed = {-15/32, 13/32, -15/32, -13/32, 1/2, -13/32}, + }, +}) + + +minetest.register_chatcommand("protector_show", { + params = "", + description = S("Show your nearby protection blocks"), + privs = {interact = true}, + + func = function(name, param) + + local player = minetest.get_player_by_name(name) + + if not player then + return false, "Player not found" + end + + local pos = player:get_pos() + + local a = minetest.find_nodes_in_area( + {x = pos.x - r, y = pos.y - r, z = pos.z - r}, + {x = pos.x + r, y = pos.y + r, z = pos.z + r}, + {"protector:protect_hidden"}) + + local meta, owner + + for _, row in pairs(a) do + + meta = minetest.get_meta(row) + owner = meta:get_string("owner") or "" + + if owner == name + or minetest.check_player_privs(name, {protection_bypass = true}) then + minetest.swap_node(row, {name = "protector:protect"}) + end + end + end +}) + +minetest.register_chatcommand("protector_hide", { + params = "", + description = S("Hide your nearby protection blocks"), + privs = {interact = true}, + + func = function(name, param) + + local player = minetest.get_player_by_name(name) + + if not player then + return false, "Player not found" + end + + local pos = player:get_pos() + + local a = minetest.find_nodes_in_area( + {x = pos.x - r, y = pos.y - r, z = pos.z - r}, + {x = pos.x + r, y = pos.y + r, z = pos.z + r}, + {"protector:protect", "protector:protect2"}) + + local meta, owner + + for _, row in pairs(a) do + + meta = minetest.get_meta(row) + owner = meta:get_string("owner") or "" + + if owner == name + or minetest.check_player_privs(name, {protection_bypass = true}) then + minetest.swap_node(row, {name = "protector:protect_hidden"}) + end + end + end +}) diff --git a/depends.txt b/depends.txt new file mode 100644 index 0000000..5b09c28 --- /dev/null +++ b/depends.txt @@ -0,0 +1,5 @@ +default? +intllib? +lucky_block? +mesecons_mvps? +playerfactions? diff --git a/description.txt b/description.txt new file mode 100644 index 0000000..587fee8 --- /dev/null +++ b/description.txt @@ -0,0 +1 @@ +Lets players craft special blocks to protect their builds or disable PVP in areas. \ No newline at end of file diff --git a/hud.lua b/hud.lua new file mode 100644 index 0000000..e33901e --- /dev/null +++ b/hud.lua @@ -0,0 +1,67 @@ + +local S = protector.intllib +local radius = (tonumber(minetest.setting_get("protector_radius")) or 5) + +-- radius limiter (minetest cannot handle node volume of more than 4096000) +if radius > 22 then radius = 22 end + +local hud = {} +local hud_timer = 0 +local hud_interval = (tonumber(minetest.setting_get("protector_hud_interval")) or 5) + +if hud_interval > 0 then +minetest.register_globalstep(function(dtime) + + -- every 5 seconds + hud_timer = hud_timer + dtime + if hud_timer < hud_interval then + return + end + hud_timer = 0 + + for _, player in pairs(minetest.get_connected_players()) do + + local name = player:get_player_name() + local pos = vector.round(player:get_pos()) + local hud_text = "" + + local protectors = minetest.find_nodes_in_area( + {x = pos.x - radius , y = pos.y - radius , z = pos.z - radius}, + {x = pos.x + radius , y = pos.y + radius , z = pos.z + radius}, + {"protector:protect","protector:protect2", "protector:protect_hidden"}) + + if #protectors > 0 then + local npos = protectors[1] + local meta = minetest.get_meta(npos) + local nodeowner = meta:get_string("owner") + + hud_text = S("Owner: @1", nodeowner) + end + + if not hud[name] then + + hud[name] = {} + + hud[name].id = player:hud_add({ + hud_elem_type = "text", + name = "Protector Area", + number = 0xFFFF22, + position = {x = 0, y = 0.95}, + offset = {x = 8, y = -8}, + text = hud_text, + scale = {x = 200, y = 60}, + alignment = {x = 1, y = -1}, + }) + + return + else + player:hud_change(hud[name].id, "text", hud_text) + end + end +end) + +minetest.register_on_leaveplayer(function(player) + hud[player:get_player_name()] = nil +end) + +end diff --git a/init.lua b/init.lua new file mode 100644 index 0000000..d1a05c2 --- /dev/null +++ b/init.lua @@ -0,0 +1,798 @@ + +-- default support (for use with MineClone2 and other [games] +default = default or { + node_sound_stone_defaults = function(table) end, + node_sound_wood_defaults = function(table) end, + gui_bg = "", + gui_bg_img = "", + gui_slots = "", +} + +-- Load support for intllib. +local MP = minetest.get_modpath(minetest.get_current_modname()) +local F = minetest.formspec_escape +local S = minetest.get_translator and minetest.get_translator("protector") or + dofile(MP .. "/intllib.lua") + +-- Load support for factions +local factions_available = minetest.global_exists("factions") + +protector = { + mod = "redo", + modpath = MP, + intllib = S +} + +local protector_max_share_count = 12 +-- get minetest.conf settings +local protector_radius = tonumber(minetest.settings:get("protector_radius")) or 5 +local protector_flip = minetest.settings:get_bool("protector_flip") or false +local protector_hurt = tonumber(minetest.settings:get("protector_hurt")) or 0 +local protector_spawn = tonumber(minetest.settings:get("protector_spawn") + or minetest.settings:get("protector_pvp_spawn")) or 0 +local protector_show = tonumber(minetest.settings:get("protector_show_interval")) or 5 +local protector_recipe = minetest.settings:get_bool("protector_recipe") ~= false +local protector_msg = minetest.settings:get_bool("protector_msg") ~= false + +-- radius limiter (minetest cannot handle node volume of more than 4096000) +if protector_radius > 22 then protector_radius = 22 end + + +-- get static spawn position +local statspawn = minetest.string_to_pos(minetest.settings:get("static_spawnpoint")) + or {x = 0, y = 2, z = 0} + + +-- return list of members as a table +local get_member_list = function(meta) + + return meta:get_string("members"):split(" ") +end + + +-- write member list table in protector meta as string +local set_member_list = function(meta, list) + + meta:set_string("members", table.concat(list, " ")) +end + + +-- check for owner name +local is_owner = function(meta, name) + + return name == meta:get_string("owner") +end + + +-- check for member name +local is_member = function (meta, name) + + if factions_available + and meta:get_int("faction_members") == 1 then + + if factions.version == nil then + + -- backward compatibility + if factions.get_player_faction(name) ~= nil + and factions.get_player_faction(meta:get_string("owner")) == + factions.get_player_faction(name) then + return true + end + else + -- is member if player and owner share at least one faction + local owner_factions = factions.get_player_factions(name) + local owner = meta:get_string("owner") + for _, f in ipairs(owner_factions) do + + if factions.player_is_in_faction(f, owner) then + return true + end + end + end + end + + for _, n in pairs(get_member_list(meta)) do + + if n == name then + return true + end + end + + return false +end + + +-- add player name to table as member +local add_member = function(meta, name) + + -- Constant (20) defined by player.h + if name:len() > 25 then + return + end + + -- does name already exist? + if is_owner(meta, name) + or is_member(meta, name) then + return + end + + local list = get_member_list(meta) + + if #list >= protector_max_share_count then + return + end + + table.insert(list, name) + + set_member_list(meta, list) +end + + +-- remove player name from table +local del_member = function(meta, name) + + local list = get_member_list(meta) + + for i, n in pairs(list) do + + if n == name then + table.remove(list, i) + break + end + end + + set_member_list(meta, list) +end + + +-- protector interface +local protector_formspec = function(meta) + + local formspec = "size[8,7]" + .. default.gui_bg + .. default.gui_bg_img + .. default.gui_slots + .. "label[2.5,0;" .. F(S("-- Protector interface --")) .. "]" + .. "label[0,1;" .. F(S("PUNCH node to show protected area")) .. "]" + .. "label[0,2;" .. F(S("Members:")) .. "]" + .. "button_exit[2.5,6.2;3,0.5;close_me;" .. F(S("Close")) .. "]" + .. "field_close_on_enter[protector_add_member;false]" + + local members = get_member_list(meta) + local npp = protector_max_share_count -- max users added to protector list + local i = 0 + local checkbox_faction = false + + -- Display the checkbox only if the owner is member of at least 1 faction + if factions_available then + + if factions.version == nil then + + -- backward compatibility + if factions.get_player_faction(meta:get_string("owner")) then + checkbox_faction = true + end + else + if factions.get_player_factions(meta:get_string("owner")) ~= nil then + if next(factions.get_player_factions(meta:get_string("owner"))) then + checkbox_faction = true + end + end + end + end + if checkbox_faction then + + formspec = formspec .. "checkbox[0,5;faction_members;" + .. F(S("Allow faction access")) + .. ";" .. (meta:get_int("faction_members") == 1 and + "true" or "false") .. "]" + + if npp > 8 then + npp = 8 + end + end + + for n = 1, #members do + + if i < npp then + + -- show username + formspec = formspec .. "button[" .. (i % 4 * 2) + .. "," .. math.floor(i / 4 + 3) + .. ";1.5,.5;protector_member;" .. F(members[n]) .. "]" + + -- username remove button + .. "button[" .. (i % 4 * 2 + 1.25) .. "," + .. math.floor(i / 4 + 3) + .. ";.75,.5;protector_del_member_" .. F(members[n]) .. ";X]" + end + + i = i + 1 + end + + if i < npp then + + -- user name entry field + formspec = formspec .. "field[" .. (i % 4 * 2 + 1 / 3) .. "," + .. (math.floor(i / 4 + 3) + 1 / 3) + .. ";1.433,.5;protector_add_member;;]" + + -- username add button + .."button[" .. (i % 4 * 2 + 1.25) .. "," + .. math.floor(i / 4 + 3) .. ";.75,.5;protector_submit;+]" + + end + + return formspec +end + + +-- check if pos is inside a protected spawn area +local inside_spawn = function(pos, radius) + + if protector_spawn <= 0 then + return false + end + + if pos.x < statspawn.x + radius + and pos.x > statspawn.x - radius + and pos.y < statspawn.y + radius + and pos.y > statspawn.y - radius + and pos.z < statspawn.z + radius + and pos.z > statspawn.z - radius then + + return true + end + + return false +end + + +-- show protection message if enabled +local show_msg = function(player, msg) + + -- if messages disabled or no player name provided + if protector_msg == false or not player or player == "" then + return + end + + minetest.chat_send_player(player, msg) +end + + +-- Infolevel: +-- 0 for no info +-- 1 for "This area is owned by !" if you can't dig +-- 2 for "This area is owned by . +-- 3 for checking protector overlaps + +protector.can_dig = function(r, pos, digger, onlyowner, infolevel) + + if not digger or not pos then + return false + end + + -- protector_bypass privileged users can override protection + if infolevel == 1 + and minetest.check_player_privs(digger, {protection_bypass = true}) then + return true + end + + -- infolevel 3 is only used to bypass priv check, change to 1 now + if infolevel == 3 then infolevel = 1 end + + -- is spawn area protected ? + if inside_spawn(pos, protector_spawn) then + + show_msg(digger, + S("Spawn @1 has been protected up to a @2 block radius.", + minetest.pos_to_string(statspawn), protector_spawn)) + + return false + end + + -- find the protector nodes + local pos = minetest.find_nodes_in_area( + {x = pos.x - r, y = pos.y - r, z = pos.z - r}, + {x = pos.x + r, y = pos.y + r, z = pos.z + r}, + {"protector:protect", "protector:protect2", "protector:protect_hidden"}) + + local meta, owner, members + + for n = 1, #pos do + + meta = minetest.get_meta(pos[n]) + owner = meta:get_string("owner") or "" + members = meta:get_string("members") or "" + + -- node change and digger isn't owner + if infolevel == 1 and owner ~= digger then + + -- and you aren't on the member list + if onlyowner or not is_member(meta, digger) then + + show_msg(digger, + S("This area is owned by @1", owner) .. "!") + + return false + end + end + + -- when using protector as tool, show protector information + if infolevel == 2 then + + minetest.chat_send_player(digger, + S("This area is owned by @1", owner) .. ".") + + minetest.chat_send_player(digger, + S("Protection located at: @1", minetest.pos_to_string(pos[n]))) + + if members ~= "" then + + minetest.chat_send_player(digger, S("Members: @1.", members)) + end + + return false + end + + end + + -- show when you can build on unprotected area + if infolevel == 2 then + + if #pos < 1 then + + minetest.chat_send_player(digger, S("This area is not protected.")) + end + + minetest.chat_send_player(digger, S("You can build here.")) + end + + return true +end + + +local old_is_protected = minetest.is_protected + +-- check for protected area, return true if protected and digger isn't on list +function minetest.is_protected(pos, digger) + + digger = digger or "" -- nil check + + -- is area protected against digger? + if not protector.can_dig(protector_radius, pos, digger, false, 1) then + + local player = minetest.get_player_by_name(digger) + + if player and player:is_player() then + + -- hurt player if protection violated + if protector_hurt > 0 and player:get_hp() > 0 then + + -- This delay fixes item duplication bug (thanks luk3yx) + minetest.after(0.1, function() + player:set_hp(player:get_hp() - protector_hurt) + end) + end + + -- flip player when protection violated + if protector_flip then + + -- yaw + 180° + local yaw = player:get_look_horizontal() + math.pi + + if yaw > 2 * math.pi then + yaw = yaw - 2 * math.pi + end + + player:set_look_horizontal(yaw) + + -- invert pitch + player:set_look_vertical(-player:get_look_vertical()) + + -- if digging below player, move up to avoid falling through hole + local pla_pos = player:get_pos() + + if pos.y < pla_pos.y then + + player:set_pos({ + x = pla_pos.x, + y = pla_pos.y + 0.8, + z = pla_pos.z + }) + end + end + end + + return true + end + + -- otherwise can dig or place + return old_is_protected(pos, digger) +end + + +-- make sure protection block doesn't overlap another protector's area +local check_overlap = function(itemstack, placer, pointed_thing) + + if pointed_thing.type ~= "node" then + return itemstack + end + + local pos = pointed_thing.above + local name = placer:get_player_name() + + -- make sure protector doesn't overlap onto protected spawn area + if inside_spawn(pos, protector_spawn + protector_radius) then + + minetest.chat_send_player(name, + S("Spawn @1 has been protected up to a @2 block radius.", + minetest.pos_to_string(statspawn), protector_spawn)) + + return itemstack + end + + -- make sure protector doesn't overlap any other player's area + if not protector.can_dig(protector_radius * 2, pos, name, true, 3) then + + minetest.chat_send_player(name, + S("Overlaps into above players protected area")) + + return itemstack + end + + return minetest.item_place(itemstack, placer, pointed_thing) + +end + + +-- temporary pos store +local player_pos = {} + +-- protection node +minetest.register_node("protector:protect", { + description = S("Protection Block") .. " (" .. S("USE for area check") .. ")", + drawtype = "nodebox", + tiles = { + "default_stone.png^protector_overlay.png", + "default_stone.png^protector_overlay.png", + "default_stone.png^protector_overlay.png^protector_logo.png" + }, + sounds = default.node_sound_stone_defaults(), + groups = {dig_immediate = 2, unbreakable = 1}, + is_ground_content = false, + paramtype = "light", + light_source = 4, + + node_box = { + type = "fixed", + fixed = { + {-0.5 ,-0.5, -0.5, 0.5, 0.5, 0.5}, + } + }, + + on_place = check_overlap, + + after_place_node = function(pos, placer) + + local meta = minetest.get_meta(pos) + + meta:set_string("owner", placer:get_player_name() or "") + meta:set_string("members", "") + meta:set_string("infotext", + S("Protection (owned by @1)", meta:get_string("owner"))) + end, + + on_use = function(itemstack, user, pointed_thing) + + if pointed_thing.type ~= "node" then + return + end + + protector.can_dig(protector_radius, pointed_thing.under, + user:get_player_name(), false, 2) + end, + + on_rightclick = function(pos, node, clicker, itemstack) + + local meta = minetest.get_meta(pos) + local name = clicker:get_player_name() + + if meta + and protector.can_dig(1, pos, name, true, 1) then + + player_pos[name] = pos + + minetest.show_formspec(name, "protector:node", protector_formspec(meta)) + end + end, + + on_punch = function(pos, node, puncher) + + if minetest.is_protected(pos, puncher:get_player_name()) then + return + end + + minetest.add_entity(pos, "protector:display") + end, + + can_dig = function(pos, player) + + return player and protector.can_dig(1, pos, player:get_player_name(), true, 1) + end, + + on_blast = function() end, + + after_destruct = function(pos, oldnode) + local objects = minetest.get_objects_inside_radius(pos, 0.5) + for _, v in ipairs(objects) do + v:remove() + end + end, +}) + +-- default recipe and alternative for MineClone2 +if protector_recipe then + if minetest.registered_items["default:stone"] then + minetest.register_craft({ + output = "protector:protect", + recipe = { + {"default:stone", "default:stone", "default:stone"}, + {"default:stone", "default:gold_ingot", "default:stone"}, + {"default:stone", "default:stone", "default:stone"}, + } + }) + else + minetest.register_craft({ + output = "protector:protect", + recipe = { + {"mcl_core:stone", "mcl_core:stone", "mcl_core:stone"}, + {"mcl_core:stone", "mcl_core:gold_ingot", "mcl_core:stone"}, + {"mcl_core:stone", "mcl_core:stone", "mcl_core:stone"}, + } + }) + end +end + +-- protection logo +minetest.register_node("protector:protect2", { + description = S("Protection Logo") .. " (" .. S("USE for area check") .. ")", + tiles = {"protector_logo.png"}, + wield_image = "protector_logo.png", + inventory_image = "protector_logo.png", + sounds = default.node_sound_stone_defaults(), + groups = {dig_immediate = 2, unbreakable = 1}, + paramtype = "light", + paramtype2 = "wallmounted", + legacy_wallmounted = true, + light_source = 4, + drawtype = "nodebox", + sunlight_propagates = true, + walkable = true, + node_box = { + type = "wallmounted", + wall_top = {-0.375, 0.4375, -0.5, 0.375, 0.5, 0.5}, + wall_bottom = {-0.375, -0.5, -0.5, 0.375, -0.4375, 0.5}, + wall_side = {-0.5, -0.5, -0.375, -0.4375, 0.5, 0.375}, + }, + selection_box = {type = "wallmounted"}, + + on_place = check_overlap, + + after_place_node = function(pos, placer) + + local meta = minetest.get_meta(pos) + + meta:set_string("owner", placer:get_player_name() or "") + meta:set_string("members", "") + meta:set_string("infotext", + S("Protection (owned by @1)", meta:get_string("owner"))) + end, + + on_use = function(itemstack, user, pointed_thing) + + if pointed_thing.type ~= "node" then + return + end + + protector.can_dig(protector_radius, pointed_thing.under, + user:get_player_name(), false, 2) + end, + + on_rightclick = function(pos, node, clicker, itemstack) + + local meta = minetest.get_meta(pos) + local name = clicker:get_player_name() + + if meta + and protector.can_dig(1, pos, name, true, 1) then + + player_pos[name] = pos + + minetest.show_formspec(name, "protector:node", protector_formspec(meta)) + end + end, + + on_punch = function(pos, node, puncher) + + if minetest.is_protected(pos, puncher:get_player_name()) then + return + end + + minetest.add_entity(pos, "protector:display") + end, + + can_dig = function(pos, player) + + return player and protector.can_dig(1, pos, player:get_player_name(), true, 1) + end, + + on_blast = function() end, + + after_destruct = function(pos, oldnode) + local objects = minetest.get_objects_inside_radius(pos, 0.5) + for _, v in ipairs(objects) do + v:remove() + end + end, +}) + +-- recipes to switch between protectors +minetest.register_craft({ + type = "shapeless", + output = "protector:protect", + recipe = {"protector:protect2"} +}) + +minetest.register_craft({ + type = "shapeless", + output = "protector:protect2", + recipe = {"protector:protect"} +}) + + +-- check formspec buttons or when name entered +minetest.register_on_player_receive_fields(function(player, formname, fields) + + if formname ~= "protector:node" then + return + end + + local name = player:get_player_name() + local pos = player_pos[name] + + if not name or not pos then + return + end + + local add_member_input = fields.protector_add_member + + -- reset formspec until close button pressed + if (fields.close_me or fields.quit) + and (not add_member_input or add_member_input == "") then + player_pos[name] = nil + return + end + + -- only owner can add names + if not protector.can_dig(1, pos, player:get_player_name(), true, 1) then + return + end + + -- are we adding member to a protection node ? (csm protection) + local nod = minetest.get_node(pos).name + + if nod ~= "protector:protect" + and nod ~= "protector:protect2" then + player_pos[name] = nil + return + end + + local meta = minetest.get_meta(pos) + + if not meta then + return + end + + -- add faction members + if factions_available then + meta:set_int("faction_members", fields.faction_members == "true" and 1 or 0) + end + + -- add member [+] + if add_member_input then + + for _, i in pairs(add_member_input:split(" ")) do + add_member(meta, i) + end + end + + -- remove member [x] + for field, value in pairs(fields) do + + if string.sub(field, 0, + string.len("protector_del_member_")) == "protector_del_member_" then + + del_member(meta, + string.sub(field,string.len("protector_del_member_") + 1)) + end + end + + minetest.show_formspec(name, formname, protector_formspec(meta)) +end) + + +-- display entity shown when protector node is punched +minetest.register_entity("protector:display", { + physical = false, + collisionbox = {0, 0, 0, 0, 0, 0}, + visual = "wielditem", + -- wielditem seems to be scaled to 1.5 times original node size + visual_size = {x = 0.67, y = 0.67}, + textures = {"protector:display_node"}, + timer = 0, + glow = 10, + + on_step = function(self, dtime) + + self.timer = self.timer + dtime + + -- remove after set number of seconds + if self.timer > protector_show then + self.object:remove() + end + end, +}) + + +-- Display-zone node, Do NOT place the display as a node, +-- it is made to be used as an entity (see above) + +local x = protector_radius +minetest.register_node("protector:display_node", { + tiles = {"protector_display.png"}, + use_texture_alpha = true, + walkable = false, + drawtype = "nodebox", + node_box = { + type = "fixed", + fixed = { + -- sides + {-(x+.55), -(x+.55), -(x+.55), -(x+.45), (x+.55), (x+.55)}, + {-(x+.55), -(x+.55), (x+.45), (x+.55), (x+.55), (x+.55)}, + {(x+.45), -(x+.55), -(x+.55), (x+.55), (x+.55), (x+.55)}, + {-(x+.55), -(x+.55), -(x+.55), (x+.55), (x+.55), -(x+.45)}, + -- top + {-(x+.55), (x+.45), -(x+.55), (x+.55), (x+.55), (x+.55)}, + -- bottom + {-(x+.55), -(x+.55), -(x+.55), (x+.55), -(x+.45), (x+.55)}, + -- middle (surround protector) + {-.55,-.55,-.55, .55,.55,.55}, + }, + }, + selection_box = { + type = "regular", + }, + paramtype = "light", + groups = {dig_immediate = 3, not_in_creative_inventory = 1}, + drop = "", +}) + + +dofile(MP .. "/doors_chest.lua") +dofile(MP .. "/pvp.lua") +dofile(MP .. "/admin.lua") +dofile(MP .. "/tool.lua") +dofile(MP .. "/hud.lua") +dofile(MP .. "/lucky_block.lua") + + +-- stop mesecon pistons from pushing protectors +if minetest.get_modpath("mesecons_mvps") then + mesecon.register_mvps_stopper("protector:protect") + mesecon.register_mvps_stopper("protector:protect2") + mesecon.register_mvps_stopper("protector:chest") +end + + +print (S("[MOD] Protector Redo loaded")) diff --git a/intllib.lua b/intllib.lua new file mode 100644 index 0000000..6669d72 --- /dev/null +++ b/intllib.lua @@ -0,0 +1,45 @@ + +-- Fallback functions for when `intllib` is not installed. +-- Code released under Unlicense . + +-- Get the latest version of this file at: +-- https://raw.githubusercontent.com/minetest-mods/intllib/master/lib/intllib.lua + +local function format(str, ...) + local args = { ... } + local function repl(escape, open, num, close) + if escape == "" then + local replacement = tostring(args[tonumber(num)]) + if open == "" then + replacement = replacement..close + end + return replacement + else + return "@"..open..num..close + end + end + return (str:gsub("(@?)@(%(?)(%d+)(%)?)", repl)) +end + +local gettext, ngettext +if minetest.get_modpath("intllib") then + if intllib.make_gettext_pair then + -- New method using gettext. + gettext, ngettext = intllib.make_gettext_pair() + else + -- Old method using text files. + gettext = intllib.Getter() + end +end + +-- Fill in missing functions. + +gettext = gettext or function(msgid, ...) + return format(msgid, ...) +end + +ngettext = ngettext or function(msgid, msgid_plural, n, ...) + return format(n==1 and msgid or msgid_plural, ...) +end + +return gettext, ngettext diff --git a/license.txt b/license.txt new file mode 100644 index 0000000..fec6f6a --- /dev/null +++ b/license.txt @@ -0,0 +1,21 @@ +The MIT License (MIT) + +Copyright (c) 2016 TenPlus1 + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. diff --git a/lucky_block.lua b/lucky_block.lua new file mode 100644 index 0000000..59c52c1 --- /dev/null +++ b/lucky_block.lua @@ -0,0 +1,18 @@ + +-- add lucky blocks + +if minetest.get_modpath("lucky_block") then + + lucky_block:add_blocks({ + {"dro", {"protector:protect"}, 3}, + {"dro", {"protector:protect2"}, 3}, + {"dro", {"protector:door_wood"}, 1}, + {"dro", {"protector:door_steel"}, 1}, + {"exp", 5, true}, + {"dro", {"protector:trapdoor"}, 1}, + {"dro", {"protector:trapdoor_steel"}, 1}, + {"dro", {"protector:tool"}, 1}, + {"dro", {"protector:chest"}, 1}, + {"exp"}, + }) +end diff --git a/pvp.lua b/pvp.lua new file mode 100644 index 0000000..0efb62a --- /dev/null +++ b/pvp.lua @@ -0,0 +1,72 @@ + +local S = protector.intllib + +-- get static spawn position +local statspawn = minetest.string_to_pos(minetest.settings:get("static_spawnpoint")) + or {x = 0, y = 2, z = 0} + +-- is spawn protected +local protector_spawn = tonumber(minetest.settings:get("protector_spawn") + or minetest.settings:get("protector_pvp_spawn")) or 0 + +-- is night-only pvp enabled +local protector_night_pvp = minetest.settings:get_bool("protector_night_pvp") + +-- disables PVP in your own protected areas +if minetest.settings:get_bool("enable_pvp") +and minetest.settings:get_bool("protector_pvp") then + + if minetest.register_on_punchplayer then + + minetest.register_on_punchplayer(function(player, hitter, + time_from_last_punch, tool_capabilities, dir, damage) + + if not player + or not hitter then + print(S("[Protector] on_punchplayer called with nil objects")) + end + + if not hitter:is_player() then + return false + end + + -- no pvp at spawn area + local pos = player:get_pos() + + if pos.x < statspawn.x + protector_spawn + and pos.x > statspawn.x - protector_spawn + and pos.y < statspawn.y + protector_spawn + and pos.y > statspawn.y - protector_spawn + and pos.z < statspawn.z + protector_spawn + and pos.z > statspawn.z - protector_spawn then + return true + end + + -- do we enable pvp at night time only ? + if protector_night_pvp then + + -- get time of day + local tod = minetest.get_timeofday() or 0 + + if tod > 0.2 and tod < 0.8 then + -- + else + return false + end + end + + -- is player being punched inside a protected area ? + if minetest.is_protected(pos, hitter:get_player_name()) then + return true + end + + return false + + end) + else + print(S("[Protector] pvp_protect not active, update your version of Minetest")) + + end +else + print(S("[Protector] pvp_protect is disabled")) +end diff --git a/settingtypes.txt b/settingtypes.txt new file mode 100644 index 0000000..7fe8446 --- /dev/null +++ b/settingtypes.txt @@ -0,0 +1,32 @@ +# Size of protected area around protection node limiting player interaction +protector_radius (Protector Radius [max 22]) int 5 + +# Flips player around when accessing protected area to stop lag griefing +protector_flip (Protector Flip) bool false + +# Hurts player by amount entered when accessing protected area, 0 to disable +protector_hurt (Protector Hurt) int 0 + +# Sets a protected area around spawn by node radius given +protector_spawn (Protector Spawn) int 0 + +# Enables PVP inside of protected areas +protector_pvp (Protector PVP) bool false + +# When true will allow PVP inside protected spawn area +protector_pvp_spawn (Protector PVP Spawn) int 0 + +# When true will allow PVP inside all protected areas at night time only +protector_night_pvp (Protector Night PVP) bool false + +# Interval in seconds that protection field is shown +protector_show_interval (Protector Show Interval) int 5 + +# Interval in seconds that HUD ownership text is updated, 0 to disable +protector_hud_interval (Protector HUD Interval) int 5 + +# Enables craft recipe for protection block +protector_recipe (Enable Protector recipe) bool true + +# Enables protection messages in player chat +protector_msg (Enable Protector Messages) bool true