123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393 |
- -- protector placement tool (thanks to Shara for code and idea)
- -- Localize for performance.
- local vector_round = vector.round
- local get_public_time = function()
- return os.date("!%Y/%m/%d UTC")
- end
- minetest.register_craftitem("protector:tool", {
- description = "Claim Expansion Tool\n\nStand near protector, face direction and use.\nHold sneak to copy member names.\nHold 'E' to double the gap distance.",
- inventory_image = "nodeinspector.png^protector_lock.png",
- stack_max = 1,
- groups = {not_repaired_by_anvil=1},
- on_use = function(itemstack, user, pointed_thing)
- local name = user:get_player_name()
- -- check for protector near player (2 block radius)
- local pos = vector_round(user:get_pos())
- local pp = minetest.find_nodes_in_area(
- vector.subtract(pos, 2), vector.add(pos, 2),
- {"protector:protect", "protector:protect2",
- "protector:protect3", "protector:protect4"})
- if #pp == 0 then return end -- none found
- if #pp > 1 then
- minetest.chat_send_player(name, "# Server: Too many protectors nearby, choice would be ambiguous.")
- return
- end
- pos = pp[1] -- take position of first protector found
- -- get type of protector, its radius and size class
- local r -- Protector radius
- local s -- Small protector: true, else false
- local node = minetest.get_node(pos)
- local protname
- if node.name == "protector:protect" or node.name == "protector:protect2" then
- r = protector.radius
- s = false
- protname = node.name
- elseif node.name == "protector:protect3" or node.name == "protector:protect4" then
- r = protector.radius_small
- s = true
- protname = node.name
- else
- minetest.chat_send_player(name, "# Server: PPT internal error!")
- return
- end
- -- get members on protector
- local meta = minetest.get_meta(pos)
- local members = meta:get_string("members") or ""
- local owner = meta:get_string("owner") or ""
- -- require the tool user to be the owner of the initial protector node
- if owner ~= name then
- minetest.chat_send_player(name, "# Server: Cannot expand claim from origin, the protector is not yours!")
- return
- end
- -- get direction player is facing
- local dir = minetest.dir_to_facedir( user:get_look_dir() )
- local vec = {x = 0, y = 0, z = 0}
- local gap = (r * 2) + 1
- local pit = user:get_look_vertical()
- -- double the gap distance if player is holding 'E'
- if user:get_player_control().aux1 then
- gap = gap * 2
- end
- -- set placement coords
- if pit > 1.2 then
- vec.y = -gap -- up
- elseif pit < -1.2 then
- vec.y = gap -- down
- elseif dir == 0 then
- vec.z = gap -- north
- elseif dir == 1 then
- vec.x = gap -- east
- elseif dir == 2 then
- vec.z = -gap -- south
- elseif dir == 3 then
- vec.x = -gap -- west
- end
- -- new position
- pos.x = pos.x + vec.x
- pos.y = pos.y + vec.y
- pos.z = pos.z + vec.z
- -- ensure position is within a valid realm
- if not rc.is_valid_realm_pos(pos) then
- minetest.chat_send_player(name, "# Server: Cannot place protector in the Void!")
- return
- end
- if not minetest.get_node_or_nil(pos) then
- minetest.chat_send_player(name, "# Server: Cannot place protector within IGNORE!")
- return
- end
- -- does placing a protector overlap existing area
- -- this is the most important check! must not mess this up!
- local success, reason = protector.check_overlap_main(protname, name, pos)
- if not success then
- if reason == 1 then
- minetest.chat_send_player(name, "# Server: Protection bounds overlap into another person's area claim.")
- elseif reason == 2 then
- minetest.chat_send_player(name, "# Server: You cannot claim this area while someone's fresh corpse is nearby!")
- elseif reason == 3 then
- minetest.chat_send_player(name, "# Server: You must remove all corpses before you can claim this area.")
- else
- minetest.chat_send_player(name, "# Server: Cannot place protection for unknown reason.")
- end
- return
- end
- -- Does location already have a protector?
- if minetest.get_node(pos).name:find("^protector:protect") then
- minetest.chat_send_player(name, "# Server: Protector already in place!")
- return
- end
- -- does a protector already exist nearby?
- if #minetest.find_nodes_in_area(vector.subtract(pos, 1), vector.add(pos, 1),
- {"protector:protect", "protector:protect2", "protector:protect3", "protector:protect4"}) > 0 then
- minetest.chat_send_player(name, "# Server: Protector already near target!")
- return
- end
- -- do not replace containers with inventory space
- if minetest.get_inventory({type = "node", pos = pos}) then
- minetest.chat_send_player(name, "# Server: Cannot place protector, container at " .. rc.pos_to_namestr(pos) .. ".")
- return
- end
- -- protection check for other stuff, like bedrock, etc
- if minetest.is_protected(pos, name) then
- minetest.chat_send_player(name, "Cannot place protector, already protected at " .. rc.pos_to_namestr(pos) .. ".")
- return
- end
- -- check not replacing an immovable object
- local node = minetest.get_node(pos)
- if minetest.get_item_group(node.name, "immovable") ~= 0 then
- minetest.chat_send_player(name, "# Server: Cannot place protector in place of immovable object!")
- return
- end
- local nod
- local inv = user:get_inventory()
- -- try to take protector from player inventory (block first then logo)
- if s then
- if inv:contains_item("main", "protector:protect3") then
- inv:remove_item("main", "protector:protect3")
- nod = "protector:protect3"
- elseif inv:contains_item("main", "protector:protect4") then
- inv:remove_item("main", "protector:protect4")
- nod = "protector:protect4"
- end
- else
- if inv:contains_item("main", "protector:protect") then
- inv:remove_item("main", "protector:protect")
- nod = "protector:protect"
- elseif inv:contains_item("main", "protector:protect2") then
- inv:remove_item("main", "protector:protect2")
- nod = "protector:protect2"
- end
- end
- -- did we get a protector to use ?
- if not nod then
- if s then
- minetest.chat_send_player(name, "# Server: No basic protectors available to place!")
- else
- minetest.chat_send_player(name, "# Server: No advanced protectors available to place!")
- end
- return
- end
- -- place protector
- minetest.set_node(pos, {name = nod, param2 = 1})
- -- We are going to execute callbacks.
- local protdef = minetest.registered_nodes[nod]
- if protdef.on_construct then
- protdef.on_construct(pos)
- end
- if protdef.after_place_node then
- -- Assume callback only requires 'pos' and 'user'.
- protdef.after_place_node(pos, user)
- end
- -- Copy members across if holding sneak when using tool.
- local members_copied = false
- if user:get_player_control().sneak then
- local meta = minetest.get_meta(pos)
- meta:set_string("members", members)
- members_copied = true
- else
- local meta = minetest.get_meta(pos)
- meta:set_string("members", "")
- end
- ambiance.sound_play(electric_screwdriver.sound, pos, electric_screwdriver.sound_gain, electric_screwdriver.sound_dist)
- if members_copied and not s then
- minetest.chat_send_player(name, "# Server: Protector placed at " .. rc.pos_to_namestr(pos) .. ". Members copied.")
- else
- minetest.chat_send_player(name, "# Server: Protector placed at " .. rc.pos_to_namestr(pos) .. ".")
- end
- end,
- })
- -- tool recipe
- minetest.register_craft({
- output = "protector:tool",
- recipe = {
- {"protector:protect4"},
- {"nodeinspector:nodeinspector"},
- }
- })
- -- This tool is useful if you just want to move a protector without resetting
- -- some of its meta, e.g., placement date.
- minetest.register_craftitem("protector:tool2", {
- description = "Protector Mover Tool\n\nStand near protector, face direction and use.",
- inventory_image = "nodeinspector.png^protector_lock.png",
- stack_max = 1,
- groups = {not_repaired_by_anvil=1},
- on_use = function(itemstack, user, pointed_thing)
- local name = user:get_player_name()
- -- check for protector near player (2 block radius)
- local pos = vector_round(user:get_pos())
- local pp = minetest.find_nodes_in_area(
- vector.subtract(pos, 2), vector.add(pos, 2),
- {"protector:protect", "protector:protect2",
- "protector:protect3", "protector:protect4"})
- if #pp == 0 then return end -- none found
- if #pp > 1 then
- minetest.chat_send_player(name, "# Server: Too many protectors nearby, choice would be ambiguous.")
- return
- end
- pos = pp[1] -- take position of first protector found
- -- get members on protector
- local meta = minetest.get_meta(pos)
- local members = meta:get_string("members") or ""
- local owner = meta:get_string("owner") or ""
- local placedate = meta:get_string("placedate") or ""
- local protname = minetest.get_node(pos).name
- -- require the tool user to be the owner of the initial protector node
- if not minetest.check_player_privs(name, {protection_bypass=true}) then
- if owner ~= name then
- minetest.chat_send_player(name, "# Server: Cannot expand claim from origin, the protector is not yours!")
- return
- end
- end
- -- get direction player is facing
- local dir = minetest.dir_to_facedir( user:get_look_dir() )
- local vec = {x = 0, y = 0, z = 0}
- local gap = 1
- local pit = user:get_look_vertical()
- -- set placement coords
- if pit > 1.2 then
- vec.y = -gap -- up
- elseif pit < -1.2 then
- vec.y = gap -- down
- elseif dir == 0 then
- vec.z = gap -- north
- elseif dir == 1 then
- vec.x = gap -- east
- elseif dir == 2 then
- vec.z = -gap -- south
- elseif dir == 3 then
- vec.x = -gap -- west
- end
- -- new position (save old position)
- local oldpos = {x=pos.x, y=pos.y, z=pos.z}
- pos.x = pos.x + vec.x
- pos.y = pos.y + vec.y
- pos.z = pos.z + vec.z
- -- ensure position is within a valid realm
- if not rc.is_valid_realm_pos(pos) then
- minetest.chat_send_player(name, "# Server: Cannot place protector in the Void!")
- return
- end
- if not minetest.get_node_or_nil(pos) then
- minetest.chat_send_player(name, "# Server: Cannot place protector within IGNORE!")
- return
- end
- -- does placing a protector overlap existing area
- -- this is the most important check! must not mess this up!
- local success, reason = protector.check_overlap_main(protname, owner, pos)
- if not success then
- if reason == 1 then
- minetest.chat_send_player(name, "# Server: Protection bounds overlap into another person's area claim.")
- elseif reason == 2 then
- minetest.chat_send_player(name, "# Server: You cannot claim this area while someone's fresh corpse is nearby!")
- elseif reason == 3 then
- minetest.chat_send_player(name, "# Server: You must remove all corpses before you can claim this area.")
- else
- minetest.chat_send_player(name, "# Server: Cannot place protection for unknown reason.")
- end
- return
- end
- -- does a protector already exist ?
- if #minetest.find_nodes_in_area(vector.subtract(pos, 0), vector.add(pos, 0),
- {"protector:protect", "protector:protect2", "protector:protect3", "protector:protect4"}) > 0 then
- minetest.chat_send_player(name, "# Server: Protector already in place!")
- return
- end
- -- do not replace containers with inventory space
- if minetest.get_inventory({type = "node", pos = pos}) then
- minetest.chat_send_player(name, "# Server: Cannot place protector, container at " .. rc.pos_to_namestr(pos) .. ".")
- return
- end
- -- protection check for other stuff, like bedrock, etc
- if minetest.is_protected(pos, owner) then
- minetest.chat_send_player(name, "Cannot place protector, already protected at " .. rc.pos_to_namestr(pos) .. ".")
- return
- end
- -- check not replacing an immovable object
- local node = minetest.get_node(pos)
- if minetest.get_item_group(node.name, "immovable") ~= 0 then
- minetest.chat_send_player(name, "# Server: Cannot place protector in place of immovable object!")
- return
- end
- local nod = minetest.get_node(oldpos).name
- -- place protector
- minetest.set_node(pos, {name = nod, param2 = 1})
- minetest.remove_node(oldpos)
- -- We are going to execute callbacks.
- local protdef = minetest.registered_nodes[nod]
- if protdef.on_construct then
- protdef.on_construct(pos)
- end
- if protdef.after_place_node then
- -- Assume callback only requires 'pos' and 'user'.
- protdef.after_place_node(pos, user)
- end
- -- set protector metadata
- local meta = minetest.get_meta(pos)
- local dname = rename.gpn(owner)
- -- Restore original placement date and members list.
- meta:set_string("placedate", placedate)
- meta:set_string("members", members)
- ambiance.sound_play(electric_screwdriver.sound, pos, electric_screwdriver.sound_gain, electric_screwdriver.sound_dist)
- minetest.chat_send_player(name, "# Server: Protector moved to " .. rc.pos_to_namestr(pos) .. ".")
- end,
- })
- -- tool recipe
- minetest.register_craft({
- output = "protector:tool2",
- recipe = {
- {"nodeinspector:nodeinspector"},
- {"protector:protect4"},
- }
- })
|