Загрузка данных


-- AdminTP_kdm1eHvH.lua
-- Админ-команды телепортации: !goto, !bring, !return, !respawn

-- ============================================================
-- Хранилище последних телепортов
-- ============================================================
local lastTeleport = {}  -- [steamid_админа] = { ply = игрок, pos = позиция }

-- ============================================================
-- Утилиты
-- ============================================================
local function findPlayer(name)
    if not name or name == "" then return nil end
    local lower = string.lower(name)
    for _, p in ipairs(player.GetAll()) do
        if IsValid(p) and string.find(string.lower(p:Nick()), lower, 1, true) then
            return p
        end
    end
    return nil
end

local function notify(ply, msg, color)
    if IsValid(ply) then
        ply:PrintMessage(HUD_PRINTTALK, "[Админ] " .. msg)
    else
        print("[Админ] " .. msg)
    end
end

-- ============================================================
-- !goto — телепорт к игроку
-- ============================================================
local function doGoto(ply, target)
    if not IsValid(ply) or not IsValid(target) then return end

    -- Сохраняем текущую позицию админа (для !return)
    lastTeleport[ply:SteamID()] = {
        ply = target,
        pos = ply:GetPos(),
        ang = ply:EyeAngles()
    }

    local targetPos = target:GetPos()
    -- Встаём чуть сбоку, чтобы не застрять в игроке
    local offset = Vector(math.random(-30, 30), math.random(-30, 30), 0)

    ply:SetPos(targetPos + offset)
    ply:SetEyeAngles(Angle(0, ply:EyeAngles().yaw, 0))

    notify(ply, "Телепорт к " .. target:Nick())
end

-- ============================================================
-- !bring — телепорт игрока к себе
-- ============================================================
local function doBring(ply, target)
    if not IsValid(ply) or not IsValid(target) then return end

    -- Сохраняем текущую позицию игрока (для !return)
    lastTeleport[ply:SteamID()] = {
        ply = target,
        pos = target:GetPos(),
        ang = target:EyeAngles()
    }

    local myPos = ply:GetPos()
    local offset = Vector(math.random(-30, 30), math.random(-30, 30), 0)

    target:SetPos(myPos + offset + Vector(0, 0, 10))
    notify(ply, "Телепортировал " .. target:Nick() .. " к себе")
    notify(target, ply:Nick() .. " телепортировал тебя к себе")
end

-- ============================================================
-- !return — вернуть последнего телепортированного
-- ============================================================
local function doReturn(ply)
    if not IsValid(ply) then return end

    local data = lastTeleport[ply:SteamID()]
    if not data then
        notify(ply, "Нечего возвращать — ты никого не телепортировал")
        return
    end

    if not IsValid(data.ply) then
        notify(ply, "Игрок уже вышел с сервера")
        lastTeleport[ply:SteamID()] = nil
        return
    end

    data.ply:SetPos(data.pos)
    if data.ang then
        data.ply:SetEyeAngles(data.ang)
    end

    notify(ply, "Вернул " .. data.ply:Nick() .. " на прошлое место")
    notify(data.ply, ply:Nick() .. " вернул тебя на прошлое место")

    lastTeleport[ply:SteamID()] = nil
end

-- ============================================================
-- !respawn — респавн игрока
-- ============================================================
local function doRespawn(ply, target)
    if not IsValid(ply) or not IsValid(target) then return end

    -- Убиваем и респавним
    if target:Alive() then
        target:KillSilent()
    end
    target:Spawn()

    notify(ply, "Заспавнил " .. target:Nick())
    notify(target, ply:Nick() .. " заспавнил тебя")
end

-- ============================================================
-- ConCommands
-- ============================================================
concommand.Add("kdm1e_goto", function(ply, cmd, args)
    if IsValid(ply) then
        if not RANKS or not RANKS.HasPerm(ply, "canNoclip") then
            notify(ply, "У тебя нет прав!")
            return
        end
    end

    if #args < 1 then
        notify(ply, "Использование: !goto <ник>")
        return
    end

    local target = findPlayer(args[1])
    if not IsValid(target) then
        notify(ply, "Игрок не найден: " .. args[1])
        return
    end

    doGoto(ply, target)
end)

concommand.Add("kdm1e_bring", function(ply, cmd, args)
    if IsValid(ply) then
        if not RANKS or not RANKS.HasPerm(ply, "canNoclip") then
            notify(ply, "У тебя нет прав!")
            return
        end
    end

    if #args < 1 then
        notify(ply, "Использование: !bring <ник>")
        return
    end

    local target = findPlayer(args[1])
    if not IsValid(target) then
        notify(ply, "Игрок не найден: " .. args[1])
        return
    end

    doBring(ply, target)
end)

concommand.Add("kdm1e_return", function(ply, cmd, args)
    if IsValid(ply) then
        if not RANKS or not RANKS.HasPerm(ply, "canNoclip") then
            notify(ply, "У тебя нет прав!")
            return
        end
    end

    doReturn(ply)
end)

concommand.Add("kdm1e_respawn", function(ply, cmd, args)
    if IsValid(ply) then
        if not RANKS or not RANKS.HasPerm(ply, "canNoclip") then
            notify(ply, "У тебя нет прав!")
            return
        end
    end

    if #args < 1 then
        notify(ply, "Использование: !respawn <ник>")
        return
    end

    local target = findPlayer(args[1])
    if not IsValid(target) then
        notify(ply, "Игрок не найден: " .. args[1])
        return
    end

    doRespawn(ply, target)
end)

-- ============================================================
-- Чат-команды с ! и /
-- ============================================================
hook.Add("PlayerSay", "AdminTP_kdm1eHvH", function(ply, text, team)
    if not IsValid(ply) then return end
    local lower = string.lower(text)

    local function parseCmd(prefix)
        local args = string.Explode(" ", text)
        table.remove(args, 1)
        return table.concat(args, " ")
    end

    if string.StartWith(lower, "!goto ") or string.StartWith(lower, "/goto ") then
        ply:ConCommand("kdm1e_goto " .. parseCmd())
        return ""
    end

    if lower == "!goto" or lower == "/goto" then
        notify(ply, "Использование: !goto <ник>")
        return ""
    end

    if string.StartWith(lower, "!bring ") or string.StartWith(lower, "/bring ") then
        ply:ConCommand("kdm1e_bring " .. parseCmd())
        return ""
    end

    if lower == "!bring" or lower == "/bring" then
        notify(ply, "Использование: !bring <ник>")
        return ""
    end

    if lower == "!return" or lower == "/return" then
        ply:ConCommand("kdm1e_return")
        return ""
    end

    if string.StartWith(lower, "!respawn ") or string.StartWith(lower, "/respawn ") then
        ply:ConCommand("kdm1e_respawn " .. parseCmd())
        return ""
    end

    if lower == "!respawn" or lower == "/respawn" then
        notify(ply, "Использование: !respawn <ник>")
        return ""
    end
end)

print("[AdminTP] Админ-команды телепортации загружены")