mirror of
https://github.com/minetest-mods/areas.git
synced 2024-12-24 17:50:40 +01:00
307 lines
8.8 KiB
Lua
307 lines
8.8 KiB
Lua
local S = minetest.get_translator("areas")
|
|
|
|
-- I could depend on WorldEdit for this, but you need to have the 'worldedit'
|
|
-- permission to use those commands and you don't have
|
|
-- /area_pos{1,2} [X Y Z|X,Y,Z].
|
|
-- Since this is mostly copied from WorldEdit it is mostly
|
|
-- licensed under the AGPL. (select_area is an exception)
|
|
|
|
areas.marker1 = {}
|
|
areas.marker2 = {}
|
|
areas.set_pos = {}
|
|
areas.pos1 = {}
|
|
areas.pos2 = {}
|
|
|
|
local LIMIT = 30992 -- this is due to MAPBLOCK_SIZE=16!
|
|
|
|
local function posLimit(pos)
|
|
return {
|
|
x = math.max(math.min(pos.x, LIMIT), -LIMIT),
|
|
y = math.max(math.min(pos.y, LIMIT), -LIMIT),
|
|
z = math.max(math.min(pos.z, LIMIT), -LIMIT)
|
|
}
|
|
end
|
|
|
|
local parse_relative_pos
|
|
|
|
if minetest.parse_relative_number then
|
|
parse_relative_pos = function(x_str, y_str, z_str, pos)
|
|
|
|
local x = pos and minetest.parse_relative_number(x_str, pos.x)
|
|
or tonumber(x_str)
|
|
local y = pos and minetest.parse_relative_number(y_str, pos.y)
|
|
or tonumber(y_str)
|
|
local z = pos and minetest.parse_relative_number(z_str, pos.z)
|
|
or tonumber(z_str)
|
|
if x and y and z then
|
|
return vector.new(x, y, z)
|
|
end
|
|
end
|
|
else
|
|
parse_relative_pos = function(x_str, y_str, z_str, pos)
|
|
local x = tonumber(x_str)
|
|
local y = tonumber(y_str)
|
|
local z = tonumber(z_str)
|
|
if x and y and z then
|
|
return vector.new(x, y, z)
|
|
elseif string.sub(x_str, 1, 1) == "~"
|
|
or string.sub(y_str, 1, 1) == "~"
|
|
or string.sub(z_str, 1, 1) == "~" then
|
|
return nil, S("Relative coordinates is not supported on this server. " ..
|
|
"Please upgrade Minetest to 5.7.0 or newer versions.")
|
|
end
|
|
end
|
|
end
|
|
|
|
minetest.register_chatcommand("select_area", {
|
|
params = S("<ID>"),
|
|
description = S("Select an area by ID."),
|
|
func = function(name, param)
|
|
local id = tonumber(param)
|
|
if not id then
|
|
return false, S("Invalid usage, see /help @1.", "select_area")
|
|
end
|
|
if not areas.areas[id] then
|
|
return false, S("The area @1 does not exist.", id)
|
|
end
|
|
|
|
areas:setPos1(name, areas.areas[id].pos1)
|
|
areas:setPos2(name, areas.areas[id].pos2)
|
|
return true, S("Area @1 selected.", id)
|
|
end,
|
|
})
|
|
|
|
minetest.register_chatcommand("area_pos1", {
|
|
params = "[X Y Z|X,Y,Z]",
|
|
description = S("Set area protection region position @1 to your"
|
|
.." location or the one specified", "1"),
|
|
privs = {},
|
|
func = function(name, param)
|
|
local pos
|
|
local player = minetest.get_player_by_name(name)
|
|
if player then
|
|
pos = vector.round(player:get_pos())
|
|
end
|
|
local found, _, x_str, y_str, z_str = param:find(
|
|
"^(~?-?%d*)[, ](~?-?%d*)[, ](~?-?%d*)$")
|
|
if found then
|
|
local get_pos, reason = parse_relative_pos(x_str, y_str, z_str, pos)
|
|
if get_pos then
|
|
pos = get_pos
|
|
elseif not get_pos and reason then
|
|
return false, reason
|
|
end
|
|
elseif param ~= "" then
|
|
return false, S("Invalid usage, see /help @1.", "area_pos1")
|
|
end
|
|
if not pos then
|
|
return false, S("Unable to get position.")
|
|
end
|
|
pos = posLimit(vector.round(pos))
|
|
areas:setPos1(name, pos)
|
|
return true, S("Area position @1 set to @2", "1",
|
|
minetest.pos_to_string(pos))
|
|
end,
|
|
})
|
|
|
|
minetest.register_chatcommand("area_pos2", {
|
|
params = "[X Y Z|X,Y,Z]",
|
|
description = S("Set area protection region position @1 to your"
|
|
.." location or the one specified", "2"),
|
|
func = function(name, param)
|
|
local pos
|
|
local player = minetest.get_player_by_name(name)
|
|
if player then
|
|
pos = vector.round(player:get_pos())
|
|
end
|
|
local found, _, x_str, y_str, z_str = param:find(
|
|
"^(~?-?%d*)[, ](~?-?%d*)[, ](~?-?%d*)$")
|
|
if found then
|
|
local get_pos, reason = parse_relative_pos(x_str, y_str, z_str, pos)
|
|
if get_pos then
|
|
pos = get_pos
|
|
elseif not get_pos and reason then
|
|
return false, reason
|
|
end
|
|
elseif param ~= "" then
|
|
return false, S("Invalid usage, see /help @1.", "area_pos2")
|
|
end
|
|
if not pos then
|
|
return false, S("Unable to get position.")
|
|
end
|
|
pos = posLimit(vector.round(pos))
|
|
areas:setPos2(name, pos)
|
|
return true, S("Area position @1 set to @2", "2",
|
|
minetest.pos_to_string(pos))
|
|
end,
|
|
})
|
|
|
|
|
|
minetest.register_chatcommand("area_pos", {
|
|
params = "set/set1/set2/get",
|
|
description = S("Set area protection region, position 1, or position 2"
|
|
.." by punching nodes, or display the region"),
|
|
func = function(name, param)
|
|
if param == "set" then -- Set both area positions
|
|
areas.set_pos[name] = "pos1"
|
|
return true, S("Select positions by punching two nodes.")
|
|
elseif param == "set1" then -- Set area position 1
|
|
areas.set_pos[name] = "pos1only"
|
|
return true, S("Select position @1 by punching a node.", "1")
|
|
elseif param == "set2" then -- Set area position 2
|
|
areas.set_pos[name] = "pos2"
|
|
return true, S("Select position @1 by punching a node.", "2")
|
|
elseif param == "get" then -- Display current area positions
|
|
local pos1str, pos2str = S("Position @1: ", "1"), S("Position @1: ", "2")
|
|
if areas.pos1[name] then
|
|
pos1str = pos1str..minetest.pos_to_string(areas.pos1[name])
|
|
else
|
|
pos1str = pos1str..S("<not set>")
|
|
end
|
|
if areas.pos2[name] then
|
|
pos2str = pos2str..minetest.pos_to_string(areas.pos2[name])
|
|
else
|
|
pos2str = pos2str..S("<not set>")
|
|
end
|
|
return true, pos1str.."\n"..pos2str
|
|
else
|
|
return false, S("Unknown subcommand: @1", param)
|
|
end
|
|
end,
|
|
})
|
|
|
|
function areas:getPos(playerName)
|
|
local pos1, pos2 = areas.pos1[playerName], areas.pos2[playerName]
|
|
if not (pos1 and pos2) then
|
|
return nil
|
|
end
|
|
-- Copy positions so that the area table doesn't contain multiple
|
|
-- references to the same position.
|
|
pos1, pos2 = vector.new(pos1), vector.new(pos2)
|
|
return areas:sortPos(pos1, pos2)
|
|
end
|
|
|
|
function areas:setPos1(playerName, pos)
|
|
areas.pos1[playerName] = posLimit(pos)
|
|
areas.markPos1(playerName)
|
|
end
|
|
|
|
function areas:setPos2(playerName, pos)
|
|
areas.pos2[playerName] = posLimit(pos)
|
|
areas.markPos2(playerName)
|
|
end
|
|
|
|
|
|
minetest.register_on_punchnode(function(pos, node, puncher)
|
|
local name = puncher:get_player_name()
|
|
-- Currently setting position
|
|
if name ~= "" and areas.set_pos[name] then
|
|
if areas.set_pos[name] == "pos1" then
|
|
areas.pos1[name] = pos
|
|
areas.markPos1(name)
|
|
areas.set_pos[name] = "pos2"
|
|
minetest.chat_send_player(name,
|
|
S("Position @1 set to @2", "1",
|
|
minetest.pos_to_string(pos)))
|
|
elseif areas.set_pos[name] == "pos1only" then
|
|
areas.pos1[name] = pos
|
|
areas.markPos1(name)
|
|
areas.set_pos[name] = nil
|
|
minetest.chat_send_player(name,
|
|
S("Position @1 set to @2", "1",
|
|
minetest.pos_to_string(pos)))
|
|
elseif areas.set_pos[name] == "pos2" then
|
|
areas.pos2[name] = pos
|
|
areas.markPos2(name)
|
|
areas.set_pos[name] = nil
|
|
minetest.chat_send_player(name,
|
|
S("Position @1 set to @2", "2",
|
|
minetest.pos_to_string(pos)))
|
|
end
|
|
end
|
|
end)
|
|
|
|
-- Modifies positions `pos1` and `pos2` so that each component of `pos1`
|
|
-- is less than or equal to its corresponding component of `pos2`,
|
|
-- returning the two positions.
|
|
function areas:sortPos(pos1, pos2)
|
|
if pos1.x > pos2.x then
|
|
pos2.x, pos1.x = pos1.x, pos2.x
|
|
end
|
|
if pos1.y > pos2.y then
|
|
pos2.y, pos1.y = pos1.y, pos2.y
|
|
end
|
|
if pos1.z > pos2.z then
|
|
pos2.z, pos1.z = pos1.z, pos2.z
|
|
end
|
|
return pos1, pos2
|
|
end
|
|
|
|
-- Marks area position 1
|
|
areas.markPos1 = function(name)
|
|
local pos = areas.pos1[name]
|
|
if areas.marker1[name] ~= nil then -- Marker already exists
|
|
areas.marker1[name]:remove() -- Remove marker
|
|
areas.marker1[name] = nil
|
|
end
|
|
if pos ~= nil then -- Add marker
|
|
areas.marker1[name] = minetest.add_entity(pos, "areas:pos1")
|
|
areas.marker1[name]:get_luaentity().active = true
|
|
end
|
|
end
|
|
|
|
-- Marks area position 2
|
|
areas.markPos2 = function(name)
|
|
local pos = areas.pos2[name]
|
|
if areas.marker2[name] ~= nil then -- Marker already exists
|
|
areas.marker2[name]:remove() -- Remove marker
|
|
areas.marker2[name] = nil
|
|
end
|
|
if pos ~= nil then -- Add marker
|
|
areas.marker2[name] = minetest.add_entity(pos, "areas:pos2")
|
|
areas.marker2[name]:get_luaentity().active = true
|
|
end
|
|
end
|
|
|
|
minetest.register_entity("areas:pos1", {
|
|
initial_properties = {
|
|
visual = "cube",
|
|
visual_size = {x=1.1, y=1.1},
|
|
textures = {"areas_pos1.png", "areas_pos1.png",
|
|
"areas_pos1.png", "areas_pos1.png",
|
|
"areas_pos1.png", "areas_pos1.png"},
|
|
collisionbox = {-0.55, -0.55, -0.55, 0.55, 0.55, 0.55},
|
|
},
|
|
on_step = function(self, dtime)
|
|
if self.active == nil then
|
|
self.object:remove()
|
|
end
|
|
end,
|
|
on_punch = function(self, hitter)
|
|
self.object:remove()
|
|
local name = hitter:get_player_name()
|
|
areas.marker1[name] = nil
|
|
end,
|
|
})
|
|
|
|
minetest.register_entity("areas:pos2", {
|
|
initial_properties = {
|
|
visual = "cube",
|
|
visual_size = {x=1.1, y=1.1},
|
|
textures = {"areas_pos2.png", "areas_pos2.png",
|
|
"areas_pos2.png", "areas_pos2.png",
|
|
"areas_pos2.png", "areas_pos2.png"},
|
|
collisionbox = {-0.55, -0.55, -0.55, 0.55, 0.55, 0.55},
|
|
},
|
|
on_step = function(self, dtime)
|
|
if self.active == nil then
|
|
self.object:remove()
|
|
end
|
|
end,
|
|
on_punch = function(self, hitter)
|
|
self.object:remove()
|
|
local name = hitter:get_player_name()
|
|
areas.marker2[name] = nil
|
|
end,
|
|
})
|