diff options
-rw-r--r-- | builtin/game/chat.lua | 174 |
1 files changed, 82 insertions, 92 deletions
diff --git a/builtin/game/chat.lua b/builtin/game/chat.lua index 945707623..ecd413e25 100644 --- a/builtin/game/chat.lua +++ b/builtin/game/chat.lua @@ -418,121 +418,111 @@ core.register_chatcommand("remove_player", { end, }) + +-- pos may be a non-integer position +local function find_free_position_near(pos) + local tries = { + {x=1, y=0, z=0}, + {x=-1, y=0, z=0}, + {x=0, y=0, z=1}, + {x=0, y=0, z=-1}, + } + for _, d in ipairs(tries) do + local p = vector.add(pos, d) + local n = core.get_node_or_nil(p) + if n then + local def = core.registered_nodes[n.name] + if def and not def.walkable then + return p + end + end + end + return pos +end + +-- Teleports player <name> to <p> if possible +local function teleport_to_pos(name, p) + local lm = 31000 + if p.x < -lm or p.x > lm or p.y < -lm or p.y > lm + or p.z < -lm or p.z > lm then + return false, "Cannot teleport out of map bounds!" + end + local teleportee = core.get_player_by_name(name) + if not teleportee then + return false, "Cannot get player with name " .. name + end + if teleportee:get_attach() then + return false, "Cannot teleport, " .. name .. + " is attached to an object!" + end + teleportee:set_pos(p) + return true, "Teleporting " .. name .. " to " .. core.pos_to_string(p, 1) +end + +-- Teleports player <name> next to player <target_name> if possible +local function teleport_to_player(name, target_name) + if name == target_name then + return false, "One does not teleport to oneself." + end + local teleportee = core.get_player_by_name(name) + if not teleportee then + return false, "Cannot get teleportee with name " .. name + end + if teleportee:get_attach() then + return false, "Cannot teleport, " .. name .. + " is attached to an object!" + end + local target = core.get_player_by_name(target_name) + if not target then + return false, "Cannot get target player with name " .. target_name + end + local p = find_free_position_near(target:get_pos()) + teleportee:set_pos(p) + return true, "Teleporting " .. name .. " to " .. target_name .. " at " .. + core.pos_to_string(p, 1) +end + core.register_chatcommand("teleport", { - params = "<X>,<Y>,<Z> | <to_name> | (<name> <X>,<Y>,<Z>) | (<name> <to_name>)", + params = "<X>,<Y>,<Z> | <to_name> | <name> <X>,<Y>,<Z> | <name> <to_name>", description = "Teleport to position or player", privs = {teleport=true}, func = function(name, param) - -- Returns (pos, true) if found, otherwise (pos, false) - local function find_free_position_near(pos) - local tries = { - {x=1,y=0,z=0}, - {x=-1,y=0,z=0}, - {x=0,y=0,z=1}, - {x=0,y=0,z=-1}, - } - for _, d in ipairs(tries) do - local p = {x = pos.x+d.x, y = pos.y+d.y, z = pos.z+d.z} - local n = core.get_node_or_nil(p) - if n and n.name then - local def = core.registered_nodes[n.name] - if def and not def.walkable then - return p, true - end - end - end - return pos, false - end - local p = {} - p.x, p.y, p.z = string.match(param, "^([%d.-]+)[, ] *([%d.-]+)[, ] *([%d.-]+)$") - p.x = tonumber(p.x) - p.y = tonumber(p.y) - p.z = tonumber(p.z) + p.x, p.y, p.z = param:match("^([%d.-]+)[, ] *([%d.-]+)[, ] *([%d.-]+)$") + p = vector.apply(p, tonumber) if p.x and p.y and p.z then - - local lm = 31000 - if p.x < -lm or p.x > lm or p.y < -lm or p.y > lm or p.z < -lm or p.z > lm then - return false, "Cannot teleport out of map bounds!" - end - local teleportee = core.get_player_by_name(name) - if teleportee then - if teleportee:get_attach() then - return false, "Can't teleport, you're attached to an object!" - end - teleportee:set_pos(p) - return true, "Teleporting to "..core.pos_to_string(p) - end + return teleport_to_pos(name, p) end local target_name = param:match("^([^ ]+)$") - local teleportee = core.get_player_by_name(name) - - p = nil if target_name then - local target = core.get_player_by_name(target_name) - if target then - p = target:get_pos() - end + return teleport_to_player(name, target_name) end - if teleportee and p then - if teleportee:get_attach() then - return false, "Can't teleport, you're attached to an object!" - end - p = find_free_position_near(p) - teleportee:set_pos(p) - return true, "Teleporting to " .. target_name - .. " at "..core.pos_to_string(p) - end + local has_bring_priv = core.check_player_privs(name, {bring=true}) + local missing_bring_msg = "You don't have permission to teleport " .. + "other players (missing bring privilege)" - if not core.check_player_privs(name, {bring=true}) then - return false, "You don't have permission to teleport other players (missing bring privilege)" - end - - teleportee = nil - p = {} local teleportee_name teleportee_name, p.x, p.y, p.z = param:match( "^([^ ]+) +([%d.-]+)[, ] *([%d.-]+)[, ] *([%d.-]+)$") - p.x, p.y, p.z = tonumber(p.x), tonumber(p.y), tonumber(p.z) - if teleportee_name then - teleportee = core.get_player_by_name(teleportee_name) - end - if teleportee and p.x and p.y and p.z then - if teleportee:get_attach() then - return false, "Can't teleport, player is attached to an object!" + p = vector.apply(p, tonumber) + if teleportee_name and p.x and p.y and p.z then + if not has_bring_priv then + return false, missing_bring_msg end - teleportee:set_pos(p) - return true, "Teleporting " .. teleportee_name - .. " to " .. core.pos_to_string(p) + return teleport_to_pos(teleportee_name, p) end - teleportee = nil - p = nil teleportee_name, target_name = string.match(param, "^([^ ]+) +([^ ]+)$") - if teleportee_name then - teleportee = core.get_player_by_name(teleportee_name) - end - if target_name then - local target = core.get_player_by_name(target_name) - if target then - p = target:get_pos() - end - end - if teleportee and p then - if teleportee:get_attach() then - return false, "Can't teleport, player is attached to an object!" + if teleportee_name and target_name then + if not has_bring_priv then + return false, missing_bring_msg end - p = find_free_position_near(p) - teleportee:set_pos(p) - return true, "Teleporting " .. teleportee_name - .. " to " .. target_name - .. " at " .. core.pos_to_string(p) + return teleport_to_player(teleportee_name, target_name) end - return false, 'Invalid parameters ("' .. param - .. '") or player not found (see /help teleport)' + return false end, }) |