123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320 |
- protector = protector or {}
- protector.players = protector.players or {}
- protector.mod = "redo"
- protector.modpath = minetest.get_modpath("protector")
- protector.radius = 5
- protector.radius_small = 3 -- Must always be smaller than primary radius.
- protector.max_share_count = 12
- -- Localize for performance.
- local math_floor = math.floor
- local math_random = math.random
- -- Tool drop is disabled because it is too easy to exploit this using lag.
- --protector.drop = minetest.setting_getbool("protector_drop") or false
- protector.flip = minetest.settings:get_bool("protector_flip") or false
- protector.hurt = (tonumber(minetest.settings:get("protector_hurt")) or 0)
- protector.display_time = 60*2
- dofile(protector.modpath .. "/hud.lua")
- dofile(protector.modpath .. "/tool.lua")
- -- Temporary pos store.
- local player_pos = protector.players
- local get_public_time = function()
- return os.date("!%Y/%m/%d UTC")
- end
- -- Use this function ONLY when calling a Minetest API in
- -- a situation where protection interferes!
- local PROTECTION_ENABLED = true
- function protector.enable_protection(enable)
- PROTECTION_ENABLED = enable
- end
- -- Function to determine whether player may place protection in a realm.
- -- Admin can always place protection regardless of realm.
- local function realm_allows_protection(pos, pname)
- if gdac.player_is_admin(pname) then
- return true
- end
- local rn = rc.current_realm_at_pos(pos)
- if rn == "abyss" or rn == "" then
- return false
- end
- return true
- end
- -- Singular function to find relevant protector nodes in an area.
- function protector.find_protector_nodes(pos, r, mult, nodename)
- -- Arguments:
- -- `pos` = the point of interaction.
- -- `r` = the primary radius, either 1 or 5. If 1 then we're only looking for the protector itself.
- -- `mult` = how much to scale the primary radius by. 1 or 2. 2 is for checking overlaps.
- -- `nodename` = the name of the protector calling this function. May be "".
- -- The logic is complex.
- r = r * mult
- local positions, counts = 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:protect3", "protector:protect4"})
- local p1 = counts["protector:protect"] or 0
- local p2 = counts["protector:protect2"] or 0
- -- Does scanned zone contain any smaller protectors?
- local p3 = counts["protector:protect3"] or 0
- local p4 = counts["protector:protect4"] or 0
- if p1 > 0 or p2 > 0 then
- -- Determine necessary culling radius based on what we're doing.
- local r2 = protector.radius * mult
- if mult == 2 and (nodename == "protector:protect3" or nodename == "protector:protect4") then
- r2 = protector.radius + protector.radius_small
- end
- -- Remove irrelevant protectors.
- -- These are protectors that are too far away for their protection radius to matter to us.
- ::redo::
- for i = 1, #positions, 1 do
- local p = positions[i]
- local nn = minetest.get_node(p).name
- if nn == "protector:protect" or nn == "protector:protect2" then
- local minp = {x=pos.x-r2, y=pos.y-r2, z=pos.z-r2}
- local maxp = {x=pos.x+r2, y=pos.y+r2, z=pos.z+r2}
- if p.x > maxp.x or p.x < minp.x or p.y > maxp.y or p.y < minp.y or p.z > maxp.z or p.z < minp.z then
- table.remove(positions, i)
- goto redo
- end
- end
- end
- end
- if p3 > 0 or p4 > 0 then
- -- Determine necessary culling radius based on what we're doing.
- local r2 = protector.radius_small * mult
- if mult == 2 and (nodename == "protector:protect" or nodename == "protector:protect2") then
- r2 = protector.radius + protector.radius_small
- end
- -- Remove irrelevant protectors.
- -- These are protectors that are too far away for their protection radius to matter to us.
- ::redo::
- for i = 1, #positions, 1 do
- local p = positions[i]
- local nn = minetest.get_node(p).name
- if nn == "protector:protect3" or nn == "protector:protect4" then
- local minp = {x=pos.x-r2, y=pos.y-r2, z=pos.z-r2}
- local maxp = {x=pos.x+r2, y=pos.y+r2, z=pos.z+r2}
- if p.x > maxp.x or p.x < minp.x or p.y > maxp.y or p.y < minp.y or p.z > maxp.z or p.z < minp.z then
- table.remove(positions, i)
- goto redo
- end
- end
- end
- end
- -- Return only positions that matter.
- return positions
- end
- minetest.register_privilege("delprotect", {
- description = "Ignore player protection.",
- give_to_singleplayer = false,
- })
- protector.get_member_list = function(meta)
- return meta:get_string("members"):split(" ")
- end
- protector.set_member_list = function(meta, list)
- meta:set_string("members", table.concat(list, " "))
- end
- protector.is_member = function(meta, name)
- for _, n in pairs(protector.get_member_list(meta)) do
- if n == name then
- return true
- end
- end
- return false
- end
- protector.add_member = function(meta, name)
- -- Constant (20) defined by player.h
- if name:len() > 25 then
- return
- end
- name = rename.grn(name)
- if protector.is_member(meta, name) then
- return
- end
- local list = protector.get_member_list(meta)
- if #list >= protector.max_share_count then
- return
- end
- table.insert(list, name)
- protector.set_member_list(meta, list)
- end
- protector.del_member = function(meta, name)
- name = rename.grn(name)
- local list = protector.get_member_list(meta)
- for i, n in pairs(list) do
- if n == name then
- table.remove(list, i)
- break
- end
- end
- protector.set_member_list(meta, list)
- end
- -- Protector Interface
- protector.generate_formspec = function(meta)
- local formspec = "size[8,7]"
- .. default.formspec.get_form_colors()
- .. default.formspec.get_form_image()
- .. default.formspec.get_slot_colors()
- .. "label[0,0;" .. "11x11x11 Protector Interface" .. "]"
- .. "label[0,0.5;" .. "PUNCH node to show protected area or USE for area check." .. "]"
- .. "label[0,2;" .. "Members:" .. "]"
- .. "button_exit[3,6.2;2,0.5;close_me;" .. "Close" .. "]"
- .. "field_close_on_enter[protector_add_member;false]"
- local members = protector.get_member_list(meta)
- local npp = protector.max_share_count -- max users added onto protector list
- local i = 0
- 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;" .. rename.gpn(members[n]) .. "]"
- -- username remove button
- .. "button[" .. (i % 4 * 2 + 1.25) .. ","
- .. math_floor(i / 4 + 3)
- .. ";.75,.5;protector_del_member_" .. 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
- protector.get_node_owner = function(pos)
- local r = protector.radius
- local positions = protector.find_protector_nodes(pos, r, 1, "")
- for n = 1, #positions do
- local meta = minetest.get_meta(positions[n])
- local owner = meta:get_string("owner")
- return owner
- end
- end
- -- This is called by the node inspector tool to toggle display entities for buried protectors.
- protector.toggle_protector_entities_in_area = function(pname, pos)
- local r = protector.radius
- local positions = protector.find_protector_nodes(pos, r, 1, "")
- for n = 1, #positions do
- local meta = minetest.get_meta(positions[n])
- local owner = meta:get_string("owner")
- if owner == pname then -- Can only toggle display entities for owned protectors.
- local node = minetest.get_node(positions[n])
- if node.name == "protector:protect" or node.name == "protector:protect2" then
- protector.toggle_area_display(positions[n], "protector:display")
- elseif node.name == "protector:protect3" or node.name == "protector:protect4" then
- protector.toggle_area_display(positions[n], "protector:display_small")
- end
- end
- end
- end
- -- Infolevel:
- -- 0 for no info
- -- 1 for "This area is owned by <owner> !" if you can't dig
- -- 2 for "This area is owned by <owner>.
- -- 3 for checking protector overlaps
- protector.can_dig = function(r, mult, nodename, pos, digger, onlyowner, infolevel)
- if not digger or not pos then
- return false
- end
-
- -- Bedrock is always protected.
- local node = minetest.get_node(pos)
- local ndef = minetest.reg_ns_nodes[node.name] or
- minetest.registered_nodes[node.name]
- if not ndef then
- return false
- end
- if ndef.always_protected then
- return false
- end
- -- Delprotect privileged users can override protections.
- if (minetest.check_player_privs(digger, {delprotect = true}) or minetest.check_player_privs(digger, {protection_bypass = true}))
- and
- (infolevel == 1 or infolevel == 0) then
- return true
- end
- -- Prevent users from modifying the map outside of any realm.
- if not rc.is_valid_realm_pos(pos) then
- return false
- end
- if infolevel == 3 then
- infolevel = 1
- end
- -- Find the protector nodes.
- local positions = protector.find_protector_nodes(pos, r, mult, nodename)
- local meta, owner, members
- -- Anyone can dig nodes marked as override in their meta.
- -- We don't bother checking the meta unless a protector is present.
- if #positions > 0 then
- -- `protection_cancel' only applies if the node is NOT buildable_to.
- -- This ensures players cannot break protection by dropping `buildable_to' nodes, and then placing into them.
-
- -- The falling block code is responsible for ensuring that a `buildable_to'
- -- node can never be dropped into a protected zone.
- local def = minetest.reg_ns_nodes[node.name] or
- minetest.registered_nodes[node.name]
- if def and not def.buildable_to then
- local meta2 = minetest.get_meta(pos)
- -- This is generally only set on nodes which have fallen.
- if meta2:get_int("protection_cancel") == 1 then
- -- Pretend that we found no protectors.
- -- Continue code as if we found none.
- positions = {}
- end
- end
- end
- for n = 1, #positions do
- meta = minetest.get_meta(positions[n])
- owner = meta:get_string("owner") or ""
- members = meta:get_string("members") or ""
- if owner ~= digger then
- if onlyowner or not protector.is_member(meta, digger) then
- if infolevel == 1 then
- minetest.chat_send_player(digger, "# Server: This area is protected by <" .. rename.gpn(owner) .. ">!")
- elseif infolevel == 2 then
- minetest.chat_send_player(digger, "# Server: This area is protected by <" .. rename.gpn(owner) .. ">.")
- minetest.chat_send_player(digger, "# Server: Protection located at: " .. rc.pos_to_namestr(positions[n]))
- if members ~= "" then
- minetest.chat_send_player(digger, "# Server: Members: [" .. members .. "].")
- end
- end
- return false
- end
- end
- if infolevel == 2 then
- minetest.chat_send_player(digger, "# Server: This area is protected by <" .. rename.gpn(owner) .. ">.")
- minetest.chat_send_player(digger, "# Server: Protection located at: " .. rc.pos_to_namestr(positions[n]))
- if members ~= "" then
- minetest.chat_send_player(digger, "# Server: Members: [" .. members .. "].")
- end
- return false
- end
- end
- if infolevel == 2 then
- if #positions < 1 then
- minetest.chat_send_player(digger, "# Server: This area is not protected.")
- end
- minetest.chat_send_player(digger, "# Server: You can build here.")
- end
- return true
- end
- -- Can node be added or removed, if so return node else true (for protected)
- function protector.punish_player(pos, pname)
- if not pname or pname == "" then
- return
- end
- local player = minetest.get_player_by_name(pname)
- if not player or not player:is_player() then
- return
- end
- -- hurt player if protection violated
- if protector.hurt > 0 then
- local hp = player:get_hp()
- if hp > 0 then -- Avoid writing message twice.
- player:set_hp(hp - protector.hurt)
- if player:get_hp() <= 0 then
- minetest.chat_send_all("# Server: <" .. rename.gpn(pname) .. "> was killed by a protection block.")
- end
- end
- end
- -- flip player when protection violated
- if protector.flip then
- -- yaw +/- 180°
- local yaw = player:get_look_horizontal() + math_random(-math.pi, math.pi)
- 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
- -- drop tool/item if protection violated
- -- This is disabled because it is too easy to exploit using lag -- TenPlus1.
- --[[
- if protector.drop == true then
- local holding = player:get_wielded_item()
- if holding:to_string() ~= "" then
- -- take stack
- local sta = holding:take_item(holding:get_count())
- player:set_wielded_item(holding)
- -- incase of lag, reset stack
- minetest.after(0.1, function()
- -- Get player reference anew, in case player has left game.
- local player = minetest.get_player_by_name(pname)
- if not player then
- return
- end
- player:set_wielded_item(holding)
- -- drop stack
- local obj = minetest.add_item(player:get_pos(), sta)
- if obj then
- obj:setvelocity({x = math_random(-5, 5), y = 5, z = math_random(-5, 5)})
- end
- end)
- end
- end
- --]]
- end
- protector.old_is_protected = minetest.is_protected
- function minetest.is_protected(pos, digger, nodename)
- digger = digger or "" -- nil check
- -- Allow protection to be temporarily disabled for API purposes.
- if not PROTECTION_ENABLED then
- return protector.old_is_protected(pos, digger)
- end
- if not protector.can_dig(protector.radius, 1, "", pos, digger, false, 1) then
- -- Slight delay to separate call stacks; hopefully this fixes the rare recursion/crash issue.
- -- Update: it seems to have fixed the rare crashes, there have been no more related to this since some months.
- minetest.after(0, function()
- protector.punish_player(pos, digger)
- end)
- return true
- end
- return protector.old_is_protected(pos, digger)
- end
- -- Called when protection should be checked, but no retaliation should be carried out.
- function minetest.test_protection(pos, digger)
- digger = digger or "" -- nil check
- -- Allow protection to be temporarily disabled for API purposes.
- if not PROTECTION_ENABLED then
- return protector.old_is_protected(pos, digger)
- end
- -- Don't give chat messages. Infolevel 0.
- if not protector.can_dig(protector.radius, 1, "", pos, digger, false, 0) then
- return true
- end
- return protector.old_is_protected(pos, digger)
- end
- -- Make sure protection block doesn't overlap another protector's area
- function protector.check_overlap_main(protname, pname, spos)
- if not realm_allows_protection(spos, pname) then
- return false, 4
- end
- -- Do not allow protections to be placed near the Outback gate's exit coordinates.
- -- Note: this prevents the admin from placing protection here, too.
- -- Existing protections (if any) remain untouched.
- if not serveressentials.protector_can_place(spos) then
- return false, 5
- end
- if not protector.can_dig(protector.radius, 2, protname, spos, pname, true, 3) then
- -- Overlap with other player's protection.
- return false, 1
- end
- local pos = {x=spos.x, y=spos.y, z=spos.z}
- local rad = protector.radius
- local bones = minetest.find_nodes_in_area(
- {x = pos.x - rad, y = pos.y - rad, z = pos.z - rad},
- {x = pos.x + rad, y = pos.y + rad, z = pos.z + rad},
- {"bones:bones"})
- if bones and #bones > 0 then
- for k, v in ipairs(bones) do
- local meta = minetest.get_meta(v)
- local owner = meta:get_string("owner") or ""
- if owner ~= "" and owner ~= "server" then
- -- fresh bones nearby
- return false, 2
- end
- local oldowner = meta:get_string("oldowner") or ""
- if oldowner ~= "" and oldowner ~= "server" then
- -- old bones nearby
- return false, 3
- end
- end
- end
- -- no overlap with other protection
- return true, 0
- end
- function protector.check_overlap(itemstack, placer, pt)
- if pt.type ~= "node" then
- return itemstack
- end
- local pname = placer:get_player_name()
- local prot_type = itemstack:get_name()
- local success, reason = protector.check_overlap_main(prot_type, pname, pt.above)
- if not success then
- if reason == 1 then
- minetest.chat_send_player(pname, "# Server: Protection bounds overlap into another person's area claim.")
- elseif reason == 2 then
- minetest.chat_send_player(pname, "# Server: You cannot claim this area while someone's fresh corpse is nearby!")
- elseif reason == 3 then
- minetest.chat_send_player(pname, "# Server: You must remove all corpses before you can claim this area.")
- elseif reason == 4 then
- minetest.chat_send_player(pname, "# Server: Cannot claim protection here, there is no land authority.")
- elseif reason == 5 then
- minetest.chat_send_player(pname, "# Server: The area near the Outback gate's exit is public. Cannot claim land here.")
- else
- minetest.chat_send_player(pname, "# Server: Cannot place protection for unknown reason.")
- end
- return
- end
- return minetest.item_place(itemstack, placer, pt)
- end
- -- Called in the `after_place_node` of protector:protect3 and protector:protect4.
- function protector.timed_setup(pos, placer, meta)
- local pname = placer:get_player_name()
- -- If protector was placed by someone without a Key, then it is a temporary protector.
- -- Set up timer stuff if needed.
- if not passport.player_has_key(pname, placer) then
- local timer = minetest.get_node_timer(pos)
- timer:start(60) -- Run once a minute.
- local hours = 720 -- 1 month, or 30 days.
- local minutes = hours * 60
- meta:set_int("temprot", 1)
- meta:set_int("timerot", minutes)
- meta:mark_as_private({"temprot", "timerot"})
- end
- end
- -- Called in the `on_timer` of protector:protect3 and protector:protect4.
- function protector.on_timer(pos, elapsed)
- local meta = minetest.get_meta(pos)
- if meta:get_int("temprot") == 1 then
- local minutes = meta:get_int("timerot")
- minutes = minutes - math_floor(elapsed / 60)
- if minutes >= 0 then
- meta:set_int("timerot", minutes)
- meta:set_string("infotext", protector.get_infotext(meta))
- -- Rerun timer for same timeout.
- minetest.get_node_timer(pos):start(60)
- return
- end
- -- Replace protector with expired protector node.
- -- Preserve param2 and node appearance.
- local node = minetest.get_node(pos)
- local ndef = minetest.registered_nodes[node.name]
- node.name = ndef._expired_protector_name
- minetest.set_node(pos, node)
- end
- end
- -- Using data from the meta, assemble and return an infotext string.
- function protector.get_infotext(meta)
- local owner = meta:get_string("owner")
- local dname = rename.gpn(owner)
- local pdate = meta:get_string("placedate")
- if not pdate or pdate == "" then
- pdate = "an unknown date!"
- end
- local timeout = ""
- if meta:get_int("temprot") == 1 then
- local minutes = meta:get_int("timerot")
- if minutes < 0 then minutes = 0 end
- local hours = math_floor(minutes / 60)
- timeout = "\n------------------------------------------\nExpires in " .. hours .. " hours\nGet KEY to make permanent claims"
- end
- return "Protection (Owned by <" .. dname .. ">!)\nPlaced on " .. pdate .. timeout
- end
- --= Protection Lock
- minetest.register_node("protector:protect", {
- description = "Advanced Protection Lock\nArea Protected: 11x11x11",
- drawtype = "nodebox",
- tiles = {
- "moreblocks_circle_stone_bricks.png",
- "moreblocks_circle_stone_bricks.png",
- "moreblocks_circle_stone_bricks.png^protector_logo.png"
- },
- sounds = default.node_sound_stone_defaults(),
- groups = utility.dig_groups("bigitem", {
- immovable = 1, -- No pistons, no nothing.
- protector = 1,
- }),
- is_ground_content = false,
- paramtype = "light",
- movement_speed_multiplier = default.NORM_SPEED,
- -- Protectors shall not emit light. By MustTest
- --light_source = 4,
- node_box = {
- type = "fixed",
- fixed = {
- {-0.5 ,-0.5, -0.5, 0.5, 0.5, 0.5},
- }
- },
- on_place = protector.check_overlap,
- after_place_node = function(pos, placer)
- local meta = minetest.get_meta(pos)
- local placedate = get_public_time()
- local pname = placer:get_player_name() or ""
- local dname = rename.gpn(pname)
- meta:set_string("placedate", placedate)
- meta:set_string("owner", pname)
- meta:set_string("rename", dname)
- meta:set_string("infotext", protector.get_infotext(meta))
- meta:set_string("members", "")
- -- Notify nearby players.
- protector.update_nearby_players(pos)
- end,
- on_use = function(itemstack, user, pointed_thing)
- if pointed_thing.type ~= "node" then
- return
- end
- protector.can_dig(protector.radius, 1, "protector:protect", 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() or ""
- if meta and protector.can_dig(1, 1, "protector:protect", pos, name, true, 1) then
- player_pos[name] = pos
- minetest.show_formspec(name, "protector:node", protector.generate_formspec(meta))
- end
- end,
- on_punch = function(pos, node, puncher)
- if minetest.test_protection(pos, puncher:get_player_name()) then
- return
- end
- protector.toggle_area_display(pos, "protector:display")
- end,
- can_dig = function(pos, player)
- return player and protector.can_dig(1, 1, "protector:protect", pos, player:get_player_name(), true, 1)
- end,
- -- TNT-proof.
- on_blast = function() end,
- -- Called by rename LBM.
- _on_rename_check = function(pos)
- local meta = minetest.get_meta(pos)
- local owner = meta:get_string("owner")
- -- Nobody placed this block.
- if owner == "" then
- return
- end
- local cname = meta:get_string("rename")
- local dname = rename.gpn(owner)
- meta:set_string("rename", dname)
- meta:set_string("infotext", protector.get_infotext(meta))
- end,
- on_destruct = function(pos)
- -- Notify nearby players.
- minetest.after(0, protector.update_nearby_players, pos)
-
- return protector.remove_area_display(pos)
- end,
- })
- minetest.register_node("protector:protect3", {
- description = "Protection Lock\nArea Protected: 7x7x7",
- drawtype = "nodebox",
- tiles = {"cityblock.png"},
- sounds = default.node_sound_stone_defaults(),
- groups = utility.dig_groups("bigitem", {
- immovable = 1, -- No pistons, no nothing.
- protector = 1,
- }),
- is_ground_content = false,
- paramtype = "light",
- movement_speed_multiplier = default.NORM_SPEED,
- -- Protectors shall not emit light. By MustTest
- --light_source = 4,
- node_box = {
- type = "fixed",
- fixed = {
- {-0.5 ,-0.5, -0.5, 0.5, 0.5, 0.5},
- }
- },
- on_place = protector.check_overlap,
- after_place_node = function(pos, placer)
- local meta = minetest.get_meta(pos)
- protector.timed_setup(pos, placer, meta)
- local placedate = get_public_time()
- local pname = placer:get_player_name() or ""
- local dname = rename.gpn(pname)
- meta:set_string("placedate", placedate)
- meta:set_string("owner", pname)
- meta:set_string("rename", dname)
- meta:set_string("infotext", protector.get_infotext(meta))
- meta:set_string("members", "")
- -- Notify nearby players.
- protector.update_nearby_players(pos)
- end,
- _expired_protector_name = "protector:expired1",
- on_timer = protector.on_timer,
- on_use = function(itemstack, user, pointed_thing)
- if pointed_thing.type ~= "node" then
- return
- end
- protector.can_dig(protector.radius, 1, "protector:protect3", pointed_thing.under, user:get_player_name(), false, 2)
- end,
- -- This protector does not have a formspec, no on_rightclick defined.
- on_punch = function(pos, node, puncher)
- if minetest.test_protection(pos, puncher:get_player_name()) then
- return
- end
- protector.toggle_area_display(pos, "protector:display_small")
- end,
- can_dig = function(pos, player)
- return player and protector.can_dig(1, 1, "protector:protect3", pos, player:get_player_name(), true, 1)
- end,
- -- TNT-proof.
- on_blast = function() end,
- -- Called by rename LBM.
- _on_rename_check = function(pos)
- local meta = minetest.get_meta(pos)
- local owner = meta:get_string("owner")
- local placedate = meta:get_string("placedate")
- -- Nobody placed this block.
- if owner == "" then
- return
- end
- if placedate == "" then
- placedate = "an unknown date!"
- end
- local cname = meta:get_string("rename")
- local dname = rename.gpn(owner)
- meta:set_string("rename", dname)
- meta:set_string("infotext", protector.get_infotext(meta))
- end,
- on_destruct = function(pos)
- -- Notify nearby players.
- minetest.after(0, protector.update_nearby_players, pos)
-
- return protector.remove_area_display(pos)
- end,
- })
- --= Protection Logo
- minetest.register_node("protector:protect2", {
- description = "Advanced Protection Logo\nArea Protected: 11x11x11",
- tiles = {"protector_logo.png"},
- wield_image = "protector_logo.png",
- inventory_image = "protector_logo.png",
- sounds = default.node_sound_stone_defaults(),
- groups = utility.dig_groups("bigitem", {
- immovable = 1, -- No pistons, no nothing.
- protector = 1,
- }),
- paramtype = 'light',
- paramtype2 = "wallmounted",
- legacy_wallmounted = true,
- -- Protectors shall not emit light. By MustTest
- --light_source = 4,
- drawtype = "nodebox",
- sunlight_propagates = true,
- walkable = false,
- 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 = protector.check_overlap,
- after_place_node = function(pos, placer)
- local meta = minetest.get_meta(pos)
- local placedate = get_public_time()
- local pname = placer:get_player_name() or ""
- local dname = rename.gpn(pname)
- meta:set_string("placedate", placedate)
- meta:set_string("owner", pname)
- meta:set_string("rename", dname)
- meta:set_string("infotext", protector.get_infotext(meta))
- meta:set_string("members", "")
- -- Notify nearby players.
- protector.update_nearby_players(pos)
- end,
- on_use = function(itemstack, user, pointed_thing)
- if pointed_thing.type ~= "node" then
- return
- end
- protector.can_dig(protector.radius, 1, "protector:protect2", 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() or ""
- if meta and protector.can_dig(1, 1, "protector:protect2", pos, name, true, 1) then
- player_pos[name] = pos
- minetest.show_formspec(name, "protector:node", protector.generate_formspec(meta))
- end
- end,
- on_punch = function(pos, node, puncher)
- if minetest.test_protection(pos, puncher:get_player_name()) then
- return
- end
- protector.toggle_area_display(pos, "protector:display")
- end,
- can_dig = function(pos, player)
- return player and protector.can_dig(1, 1, "protector:protect2", pos, player:get_player_name(), true, 1)
- end,
- -- TNT-proof.
- on_blast = function() end,
- -- Called by rename LBM.
- _on_rename_check = function(pos)
- local meta = minetest.get_meta(pos)
- local owner = meta:get_string("owner")
- local placedate = meta:get_string("placedate")
- -- Nobody placed this block.
- if owner == "" then
- return
- end
- if placedate == "" then
- placedate = "an unknown date!"
- end
- local cname = meta:get_string("rename")
- local dname = rename.gpn(owner)
- meta:set_string("rename", dname)
- meta:set_string("infotext", protector.get_infotext(meta))
- end,
- on_destruct = function(pos)
- -- Notify nearby players.
- minetest.after(0, protector.update_nearby_players, pos)
-
- return protector.remove_area_display(pos)
- end,
- })
- minetest.register_node("protector:protect4", {
- description = "Protection Logo\nArea Protected: 7x7x7",
- tiles = {"protector_lock.png"},
- wield_image = "protector_lock.png",
- inventory_image = "protector_lock.png",
- sounds = default.node_sound_stone_defaults(),
- groups = utility.dig_groups("bigitem", {
- immovable = 1, -- No pistons, no nothing.
- protector = 1,
- }),
- paramtype = 'light',
- paramtype2 = "wallmounted",
- legacy_wallmounted = true,
- -- Protectors shall not emit light. By MustTest
- --light_source = 4,
- drawtype = "nodebox",
- sunlight_propagates = true,
- walkable = false,
- 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 = protector.check_overlap,
- after_place_node = function(pos, placer)
- local meta = minetest.get_meta(pos)
- protector.timed_setup(pos, placer, meta)
- local placedate = get_public_time()
- local pname = placer:get_player_name() or ""
- local dname = rename.gpn(pname)
- meta:set_string("placedate", placedate)
- meta:set_string("owner", pname)
- meta:set_string("rename", dname)
- meta:set_string("infotext", protector.get_infotext(meta))
- meta:set_string("members", "")
- -- Notify nearby players.
- protector.update_nearby_players(pos)
- end,
- _expired_protector_name = "protector:expired2",
- on_timer = protector.on_timer,
- on_use = function(itemstack, user, pointed_thing)
- if pointed_thing.type ~= "node" then
- return
- end
- protector.can_dig(protector.radius, 1, "protector:protect4", pointed_thing.under, user:get_player_name(), false, 2)
- end,
- -- This protector does not have a formspec, no on_rightclick defined.
- on_punch = function(pos, node, puncher)
- if minetest.test_protection(pos, puncher:get_player_name()) then
- return
- end
- protector.toggle_area_display(pos, "protector:display_small")
- end,
- can_dig = function(pos, player)
- return player and protector.can_dig(1, 1, "protector:protect4", pos, player:get_player_name(), true, 1)
- end,
- -- TNT-proof.
- on_blast = function() end,
- -- Called by rename LBM.
- _on_rename_check = function(pos)
- local meta = minetest.get_meta(pos)
- local owner = meta:get_string("owner")
- local placedate = meta:get_string("placedate")
- -- Nobody placed this block.
- if owner == "" then
- return
- end
- if placedate == "" then
- placedate = "an unknown date!"
- end
- local cname = meta:get_string("rename")
- local dname = rename.gpn(owner)
- meta:set_string("rename", dname)
- meta:set_string("infotext", protector.get_infotext(meta))
- end,
- on_destruct = function(pos)
- -- Notify nearby players.
- minetest.after(0, protector.update_nearby_players, pos)
-
- return protector.remove_area_display(pos)
- end,
- })
- -- If name entered or button press
- minetest.register_on_player_receive_fields(function(player, formname, fields)
- if formname ~= "protector:node" then
- return
- end
- local pname = player:get_player_name() or "" -- Nil check.
- local pos = player_pos[pname] -- Context should have been created during on_rightclick. CSM protection.
- -- Localize field member.
- 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[pname] = nil
- return true
- end
- if not pos then
- return true
- end
- local meta = minetest.get_meta(pos)
- local node = minetest.get_node(pos)
- -- Meta nil check.
- if not meta then
- return true
- end
- -- Are we actually working on a protection node? (CSM protection.)
- if node.name ~= "protector:protect"
- and node.name ~= "protector:protect2"
- and node.name ~= "protector:protect3"
- and node.name ~= "protector:protect4" then
- player_pos[pname] = nil
- return true
- end
- -- Only advanced protectors support member names.
- if node.name == "protector:protect3" or node.name == "protector:protect4" then
- minetest.chat_send_player(pname, "# Server: Sharing feature not supported by basic protectors!")
- return true
- end
- -- Do not permit caller to modify a protector they do not own.
- if not protector.can_dig(1, 1, node.name, pos, pname, true, 1) then
- return true
- end
- if add_member_input then
- for _, i in pairs(add_member_input:split(" ")) do
- protector.add_member(meta, i)
- end
- end
- for field, value in pairs(fields) do
- if string.sub(field, 0, string.len("protector_del_member_")) == "protector_del_member_" then
- protector.del_member(meta, string.sub(field,string.len("protector_del_member_") + 1))
- end
- end
- -- Clear formspec context.
- minetest.show_formspec(pname, formname, protector.generate_formspec(meta))
- return true
- 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 = 1.0 / 1.5, y = 1.0 / 1.5},
- textures = {"protector:display_node"},
- timer = 0,
- glow = 14,
- on_step = function(self, dtime)
- self.timer = self.timer + dtime
- if self.timer > protector.display_time then
- self.object:remove()
- end
- end,
- on_blast = function(self, damage)
- return false, false, {}
- end,
- })
- minetest.register_entity("protector:display_small", {
- 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 = 1.0 / 1.5, y = 1.0 / 1.5},
- textures = {"protector:display_node_small"},
- timer = 0,
- glow = 14,
- on_step = function(self, dtime)
- self.timer = self.timer + dtime
- if self.timer > protector.display_time then
- self.object:remove()
- end
- end,
- on_blast = function(self, damage)
- return false, false, {}
- end,
- })
- -- Display-zone node, Do NOT place the display as a node,
- -- it is made to be used as an entity (see above)
- do
- 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 = utility.dig_groups("item", {not_in_creative_inventory = 1}),
- drop = "",
- })
- end
- do
- local x = protector.radius_small
- minetest.register_node("protector:display_node_small", {
- 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 = utility.dig_groups("item", {not_in_creative_inventory = 1}),
- drop = "",
- })
- end
- function protector.remove_area_display(pos)
- local ents = minetest.get_objects_inside_radius(pos, 0.5)
- for k, n in ipairs(ents) do
- if not n:is_player() and n:get_luaentity() then
- local name = n:get_luaentity().name or ""
- if name == "protector:display" or name == "protector:display_small" then
- n:remove()
- end
- end
- end
- end
- function protector.toggle_area_display(pos, entity)
- local got_any = false
- local ents = minetest.get_objects_inside_radius(pos, 0.5)
- for k, n in ipairs(ents) do
- if not n:is_player() and n:get_luaentity() then
- local name = n:get_luaentity().name or ""
- if name == "protector:display" or name == "protector:display_small" then
- n:remove()
- got_any = true
- end
- end
- end
- if not got_any then
- minetest.add_entity(pos, entity)
- end
- end
- dofile(protector.modpath .. "/crafts.lua")
- -- Expired protector node.
- minetest.register_node("protector:expired1", {
- description = "Expired Protector",
- drawtype = "nodebox",
- tiles = {"cityblock.png"},
- sounds = default.node_sound_stone_defaults(),
- groups = utility.dig_groups("bigitem"),
- paramtype = "light",
- movement_speed_multiplier = default.NORM_SPEED,
- node_box = {
- type = "fixed",
- fixed = {
- {-0.5 ,-0.5, -0.5, 0.5, 0.5, 0.5},
- }
- },
- })
- minetest.register_node("protector:expired2", {
- description = "Expired Protector",
- tiles = {"protector_lock.png"},
- wield_image = "protector_lock.png",
- inventory_image = "protector_lock.png",
- sounds = default.node_sound_stone_defaults(),
- groups = utility.dig_groups("bigitem"),
- paramtype = 'light',
- paramtype2 = "wallmounted",
- legacy_wallmounted = true,
- drawtype = "nodebox",
- sunlight_propagates = true,
- walkable = false,
- 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"},
- })
|