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


-- Tokens_kdm1eHvH.lua
-- Система токенов + промокоды

-- ============================================================
-- БД
-- ============================================================
local function InitDB()
    -- Токены игроков
    if not sql.TableExists("player_tokens") then
        sql.Query([[
            CREATE TABLE player_tokens (
                steamid TEXT PRIMARY KEY,
                tokens INTEGER DEFAULT 0
            )
        ]])
        print("[Tokens] Таблица player_tokens создана")
    end

    -- Промокоды
    if not sql.TableExists("promo_codes") then
        sql.Query([[
            CREATE TABLE promo_codes (
                code TEXT PRIMARY KEY,
                tokens INTEGER DEFAULT 0,
                max_uses INTEGER DEFAULT 1,
                uses INTEGER DEFAULT 0,
                created INTEGER DEFAULT 0,
                created_by TEXT DEFAULT ''
            )
        ]])
        print("[Tokens] Таблица promo_codes создана")
    end

    -- Кто использовал промокоды
    if not sql.TableExists("promo_used") then
        sql.Query([[
            CREATE TABLE promo_used (
                code TEXT,
                steamid TEXT,
                used_at INTEGER DEFAULT 0
            )
        ]])
        print("[Tokens] Таблица promo_used создана")
    end
end

InitDB()

-- ============================================================
-- Функции токенов
-- ============================================================
function GetTokens(ply)
    if not IsValid(ply) then return 0 end
    local steamid = ply:SteamID()
    local q = "SELECT tokens FROM player_tokens WHERE steamid = " .. sql.SQLStr(steamid)
    local res = sql.QueryRow(q, 1)
    if res then return tonumber(res.tokens) or 0 end
    return 0
end

function AddTokens(ply, amount)
    if not IsValid(ply) then return end
    local steamid = ply:SteamID()
    local current = GetTokens(ply)
    local new = current + amount

    sql.Query("INSERT INTO player_tokens (steamid, tokens) VALUES (" ..
        sql.SQLStr(steamid) .. ", " .. new .. ") " ..
        "ON CONFLICT(steamid) DO UPDATE SET tokens = " .. new)

    ply:SetNWInt("kdm1e_Tokens", new)
end

function RemoveTokens(ply, amount)
    if not IsValid(ply) then return end
    local steamid = ply:SteamID()
    local current = GetTokens(ply)
    local new = math.max(0, current - amount)

    sql.Query("UPDATE player_tokens SET tokens = " .. new .. " WHERE steamid = " .. sql.SQLStr(steamid))
    ply:SetNWInt("kdm1e_Tokens", new)
end

-- ============================================================
-- Загрузка токенов при заходе
-- ============================================================
hook.Add("PlayerInitialSpawn", "Tokens_Load", function(ply)
    timer.Simple(1.5, function()
        if not IsValid(ply) then return end
        local t = GetTokens(ply)
        ply:SetNWInt("kdm1e_Tokens", t)
    end)
end)

-- ============================================================
-- КОМАНДЫ
-- ============================================================

-- !mytokens — свой баланс
concommand.Add("kdm1e_mytokens", function(ply)
    if not IsValid(ply) then return end
    ply:PrintMessage(HUD_PRINTTALK, "У тебя токенов: " .. GetTokens(ply))
end)

-- !promo КОД — активировать
concommand.Add("kdm1e_promo", function(ply, cmd, args)
    if not IsValid(ply) then return end
    if #args < 1 then
        ply:PrintMessage(HUD_PRINTTALK, "Использование: !promo КОД")
        return
    end

    local code = string.upper(args[1])
    local steamid = ply:SteamID()

    -- Проверяем, есть ли такой код
    local q = "SELECT * FROM promo_codes WHERE code = " .. sql.SQLStr(code)
    local res = sql.QueryRow(q, 1)

    if not res then
        ply:PrintMessage(HUD_PRINTTALK, "Промокод не найден!")
        return
    end

    -- Проверяем лимит
    local uses = tonumber(res.uses) or 0
    local max_uses = tonumber(res.max_uses) or 1
    if uses >= max_uses then
        ply:PrintMessage(HUD_PRINTTALK, "Промокод больше не действует!")
        return
    end

    -- Проверяем, не использовал ли уже
    local q2 = "SELECT * FROM promo_used WHERE code = " .. sql.SQLStr(code) ..
               " AND steamid = " .. sql.SQLStr(steamid)
    local res2 = sql.QueryRow(q2, 1)
    if res2 then
        ply:PrintMessage(HUD_PRINTTALK, "Ты уже использовал этот промокод!")
        return
    end

    -- Активируем
    local tokens = tonumber(res.tokens) or 0
    AddTokens(ply, tokens)

    sql.Query("UPDATE promo_codes SET uses = " .. (uses + 1) .. " WHERE code = " .. sql.SQLStr(code))
    sql.Query("INSERT INTO promo_used (code, steamid, used_at) VALUES (" ..
        sql.SQLStr(code) .. ", " .. sql.SQLStr(steamid) .. ", " .. os.time() .. ")")

    ply:PrintMessage(HUD_PRINTTALK, "Промокод активирован! +" .. tokens .. " токенов")
end)

-- !promocodeadmin "код" "лимит" "токены" — создать промокод
concommand.Add("kdm1e_promocodeadmin", function(ply, cmd, args)
    -- Проверка прав
    if IsValid(ply) then
        local ok = ply:IsSuperAdmin() or (RANKS and RANKS.HasPerm(ply, "canEverything"))
        if not ok then
            ply:PrintMessage(HUD_PRINTTALK, "Нет прав!")
            return
        end
    end

    if #args < 3 then
        local msg = "Использование: !promocodeadmin \"КОД\" \"ЛИМИТ\" \"ТОКЕНЫ\""
        if IsValid(ply) then ply:PrintMessage(HUD_PRINTTALK, msg) else print(msg) end
        return
    end

    local code = string.upper(args[1])
    local maxUses = tonumber(args[2]) or 1
    local tokens = tonumber(args[3]) or 0

    -- Проверяем, есть ли уже
    local q = "SELECT * FROM promo_codes WHERE code = " .. sql.SQLStr(code)
    if sql.QueryRow(q, 1) then
        local msg = "Промокод уже существует!"
        if IsValid(ply) then ply:PrintMessage(HUD_PRINTTALK, msg) else print(msg) end
        return
    end

    local creator = IsValid(ply) and ply:SteamID() or "console"

    sql.Query("INSERT INTO promo_codes (code, tokens, max_uses, uses, created, created_by) VALUES (" ..
        sql.SQLStr(code) .. ", " .. tokens .. ", " .. maxUses .. ", 0, " .. os.time() .. ", " ..
        sql.SQLStr(creator) .. ")")

    local msg = "Промокод '" .. code .. "' создан! Токенов: " .. tokens .. ", лимит: " .. maxUses
    if IsValid(ply) then ply:PrintMessage(HUD_PRINTTALK, msg) else print(msg) end
end)

-- !promolist — список промокодов
concommand.Add("kdm1e_promolist", function(ply)
    if IsValid(ply) then
        local ok = ply:IsSuperAdmin() or (RANKS and RANKS.HasPerm(ply, "canEverything"))
        if not ok then
            ply:PrintMessage(HUD_PRINTTALK, "Нет прав!")
            return
        end
    end

    local res = sql.Query("SELECT * FROM promo_codes ORDER BY created DESC LIMIT 20")
    if not res or #res == 0 then
        if IsValid(ply) then ply:PrintMessage(HUD_PRINTTALK, "Промокодов нет") end
        return
    end

    if IsValid(ply) then
        ply:PrintMessage(HUD_PRINTTALK, "=== ПРОМОКОДЫ ===")
        for _, row in ipairs(res) do
            ply:PrintMessage(HUD_PRINTTALK,
                row.code .. " | " .. row.tokens .. " токенов | " ..
                row.uses .. "/" .. row.max_uses)
        end
    else
        print("=== ПРОМОКОДЫ ===")
        for _, row in ipairs(res) do
            print(row.code .. " | " .. row.tokens .. " | " .. row.uses .. "/" .. row.max_uses)
        end
    end
end)

-- !deletepromo КОД — удалить
concommand.Add("kdm1e_deletepromo", function(ply, cmd, args)
    if IsValid(ply) then
        local ok = ply:IsSuperAdmin() or (RANKS and RANKS.HasPerm(ply, "canEverything"))
        if not ok then
            ply:PrintMessage(HUD_PRINTTALK, "Нет прав!")
            return
        end
    end

    if #args < 1 then
        if IsValid(ply) then ply:PrintMessage(HUD_PRINTTALK, "Использование: !deletepromo КОД") end
        return
    end

    local code = string.upper(args[1])
    sql.Query("DELETE FROM promo_codes WHERE code = " .. sql.SQLStr(code))

    if IsValid(ply) then
        ply:PrintMessage(HUD_PRINTTALK, "Промокод '" .. code .. "' удалён")
    end
end)

-- !givetokens SteamID кол-во — выдать
concommand.Add("kdm1e_givetokens", function(ply, cmd, args)
    if IsValid(ply) then
        local ok = ply:IsSuperAdmin() or (RANKS and RANKS.HasPerm(ply, "canEverything"))
        if not ok then
            ply:PrintMessage(HUD_PRINTTALK, "Нет прав!")
            return
        end
    end

    if #args < 2 then
        if IsValid(ply) then ply:PrintMessage(HUD_PRINTTALK, "Использование: !givetokens SteamID кол-во") end
        return
    end

    local sid = args[1]
    local amount = tonumber(args[2]) or 0

    for _, p in ipairs(player.GetAll()) do
        if IsValid(p) and (p:SteamID() == sid or p:SteamID64() == sid) then
            AddTokens(p, amount)
            if IsValid(ply) then
                ply:PrintMessage(HUD_PRINTTALK, "Выдано " .. amount .. " токенов игроку " .. p:Nick())
            end
            p:PrintMessage(HUD_PRINTTALK, "Тебе выдано " .. amount .. " токенов!")
            return
        end
    end

    -- Если оффлайн — пишем в БД
    local q = "SELECT tokens FROM player_tokens WHERE steamid = " .. sql.SQLStr(sid)
    local res = sql.QueryRow(q, 1)
    local current = res and tonumber(res.tokens) or 0
    local new = current + amount

    sql.Query("INSERT INTO player_tokens (steamid, tokens) VALUES (" ..
        sql.SQLStr(sid) .. ", " .. new .. ") " ..
        "ON CONFLICT(steamid) DO UPDATE SET tokens = " .. new)

    if IsValid(ply) then
        ply:PrintMessage(HUD_PRINTTALK, "Выдано " .. amount .. " токенов (оффлайн)")
    end
end)

-- !removetokens SteamID кол-во — забрать
concommand.Add("kdm1e_removetokens", function(ply, cmd, args)
    if IsValid(ply) then
        local ok = ply:IsSuperAdmin() or (RANKS and RANKS.HasPerm(ply, "canEverything"))
        if not ok then
            ply:PrintMessage(HUD_PRINTTALK, "Нет прав!")
            return
        end
    end

    if #args < 2 then
        if IsValid(ply) then ply:PrintMessage(HUD_PRINTTALK, "Использование: !removetokens SteamID кол-во") end
        return
    end

    local sid = args[1]
    local amount = tonumber(args[2]) or 0

    for _, p in ipairs(player.GetAll()) do
        if IsValid(p) and (p:SteamID() == sid or p:SteamID64() == sid) then
            RemoveTokens(p, amount)
            if IsValid(ply) then
                ply:PrintMessage(HUD_PRINTTALK, "Снято " .. amount .. " токенов у " .. p:Nick())
            end
            p:PrintMessage(HUD_PRINTTALK, "У тебя снято " .. amount .. " токенов!")
            return
        end
    end
end)

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

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

    if string.StartWith(lower, "!promo ") or string.StartWith(lower, "/promo ") then
        local args = string.Explode(" ", text)
        table.remove(args, 1)
        ply:ConCommand("kdm1e_promo " .. table.concat(args, " "))
        return ""
    end

    if string.StartWith(lower, "!promocodeadmin ") or string.StartWith(lower, "/promocodeadmin ") then
        local args = string.Explode(" ", text)
        table.remove(args, 1)
        ply:ConCommand("kdm1e_promocodeadmin " .. table.concat(args, " "))
        return ""
    end

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

print("[Tokens] Система токенов загружена")