-- protector placement tool (thanks to Shara for code and idea) local S = protector.intllib -- get protection radius local r = tonumber(minetest.settings:get("protector_radius")) or 5 protector.tool = { registered_protectors = {}, register_protector = function(self, nodename, data) data.nodes = data.nodes or {} table.insert(data.nodes, nodename) -- Collect parameters droppping anything that is not used self.registered_protectors[nodename] = { radius = data.radius or r, param2 = data.param2 or 0, nodes = data.nodes, on_place = data.on_place, after_place = data.after_place, } print(S('[MOD] Protector Redo Tool: registered protector:tool for @1', nodename)) if data.nodes ~= nil then if type(data.nodes) == 'table' then for i,name in ipairs(data.nodes) do -- create links for nodes for fast and straightforward lookup if name ~= nodename then print(S('[MOD] Protector Redo Tool: registering alternative @1 for @2', name, nodename)) end self.registered_protectors[name] = self.registered_protectors[nodename] end else print(S('[MOD] Protector Redo Tool: invalid data.nodes in register_protector @1', nodename)) end end end, get_protector_data = function(self, nodename) return self.registered_protectors[nodename] end, get_registered_alternatives = function(self, nodename) if self.registered_protectors[nodename] then return self.registered_protectors[nodename].nodes end return {} end, get_registered_protectors = function(self) if self.registered_protectors_cache == nil then self.registered_protectors_cache = {} for nodename,_ in pairs(self.registered_protectors) do table.insert(self.registered_protectors_cache, nodename) end end return self.registered_protectors_cache end, find_protector = function(self, pos, radius) local pp = minetest.find_nodes_in_area( vector.subtract(pos, radius), vector.add(pos, radius), self:get_registered_protectors()) return #pp > 0 and pp[1] or nil -- take position of first protector found end, find_from_inventory = function(self, user, node) -- do we have protectors to use? local available_node = nil local inv = user:get_inventory() -- first look for specified node (normally one user is standing on) and then any compatible nodes if inv:contains_item("main", node.name) then available_node = node.name elseif self.registered_protectors[node.name].nodes then for i,nodename in ipairs(self.registered_protectors[node.name].nodes) do if nodename ~= node.name and inv:contains_item("main", nodename) then available_node = nodename break end end end if not available_node then return end -- return node name that should be used return available_node end, place_protector = function(self, user, pos, nodename, source_pos, source_node) local p = self:get_protector_data(nodename) if p.on_place then -- on_place event, callback should place nodes to world p.on_place(user, pos, source_pos, nodename) elseif user:get_player_control().sneak then -- default on_place while sneaking, place node to world with param2 copied local param2 = minetest.get_node(source_pos).param2 minetest.set_node(pos, {name = nodename, param2 = param2}) else -- default on_place, place node to world minetest.set_node(pos, {name = nodename, param2 = p.param2}) end local meta = minetest.get_meta(pos) local name = user:get_player_name() meta:set_string("owner", name) if p.after_place then -- execute after_place event where metadata can be changed easily local src_meta = minetest.get_meta(source_pos) p.after_place(user, meta, src_meta, nodename) end end, } minetest.register_craftitem("protector:tool", { description = S("Protector Placer Tool (stand near protector, face direction and use)"), inventory_image = "protector_display.png^protector_logo.png", stack_max = 1, on_use = function(itemstack, user, pointed_thing) local name = user:get_player_name() local pos = user:get_pos() -- check for protector near player (2 block radius), abort if not found local source_pos = protector.tool:find_protector(pos, 2) if source_pos == nil then return end local source_node = minetest.get_node(source_pos) local radius = protector.tool:get_protector_data(source_node.name).radius -- 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 = (radius * 2) + 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 pos.x = source_pos.x + vec.x pos.y = source_pos.y + vec.y pos.z = source_pos.z + vec.z -- does placing a protector overlap existing area if not protector.can_dig(radius * 2, pos, user:get_player_name(), true, 3) then minetest.chat_send_player(name, S("Overlaps into above players protected area")) return end -- does a protector already exist ? if #minetest.find_nodes_in_area( vector.subtract(pos, 1), vector.add(pos, 1), protector.tool:get_registered_alternatives(source_node.name)) > 0 then minetest.chat_send_player(name, S("Protector already in place!")) return end local protector_node = protector.tool:find_from_inventory(user, source_node) if not protector_node then -- compatible protector nodes not in inventory minetest.chat_send_player(name, S("No protectors available to place!")) return end -- do not replace containers with inventory space local inv = minetest.get_inventory({type = "node", pos = pos}) if inv then minetest.chat_send_player(name, S("Cannot place protector, container at") .. " " .. minetest.pos_to_string(pos)) return end -- protection check for other mods like Areas if minetest.is_protected(pos, name) then minetest.chat_send_player(name, S("Cannot place protector, already protected at") .. " " .. minetest.pos_to_string(pos)) return end local user_inv = user:get_inventory() user_inv:remove_item("main", protector_node) protector.tool:place_protector(user, pos, protector_node, source_pos, source_node.name) minetest.chat_send_player(name, S("Protector placed at") .. " " .. minetest.pos_to_string(pos)) end, }) -- tool recipe local df = "default:steel_ingot" if not minetest.registered_items[df] then df = "mcl_core:iron_ingot" end minetest.register_craft({ output = "protector:tool", recipe = { {df, df, df}, {df, "protector:protect", df}, {df, df, df}, } })