Files
2026-03-31 10:27:04 +03:00

328 lines
11 KiB
Lua
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
local PLUGIN = PLUGIN
util.AddNetworkString("ixPromoCodeActivate")
util.AddNetworkString("ixPromoCodeResult")
util.AddNetworkString("ixPromoCodeCreate")
util.AddNetworkString("ixPromoCodeDelete")
util.AddNetworkString("ixPromoCodeList")
util.AddNetworkString("ixPromoCodeSync")
PLUGIN.promoCodes = PLUGIN.promoCodes or {}
PLUGIN.promoUsage = PLUGIN.promoUsage or {} -- [code] = {[steamID] = true}
-- Путь к файлу сохранения
local dataPath = "militaryrp/promocodes.txt"
-- Сохранение промокодов
function PLUGIN:SavePromoCodes()
local data = {
codes = self.promoCodes,
usage = self.promoUsage
}
file.CreateDir("militaryrp")
file.Write(dataPath, util.TableToJSON(data))
print("[PROMOCODES] Промокоды сохранены")
end
-- Загрузка промокодов
function PLUGIN:LoadPromoCodes()
if file.Exists(dataPath, "DATA") then
local jsonData = file.Read(dataPath, "DATA")
local data = util.JSONToTable(jsonData)
if data then
self.promoCodes = data.codes or {}
self.promoUsage = data.usage or {}
print("[PROMOCODES] Загружено " .. table.Count(self.promoCodes) .. " промокодов")
end
else
print("[PROMOCODES] Файл промокодов не найден, создается новый")
end
end
-- Генерация случайного кода
function PLUGIN:GenerateCode(length)
local chars = "ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789"
local code = ""
for i = 1, length do
local rand = math.random(1, #chars)
code = code .. string.sub(chars, rand, rand)
end
return code
end
-- Валидация именного промокода
function PLUGIN:ValidateCustomCode(code)
-- Проверка на пустоту
if not code or code == "" then
return false, "Код не может быть пустым"
end
-- Проверка длины (минимум 3, максимум 32 символа)
if #code < 3 then
return false, "Код должен содержать минимум 3 символа"
end
if #code > 32 then
return false, "Код должен содержать максимум 32 символа"
end
-- Проверка на допустимые символы (только A-Z, 0-9 и _)
if not string.match(code, "^[A-Z0-9_]+$") then
return false, "Код может содержать только буквы A-Z, цифры 0-9 и символ подчеркивания _"
end
return true, "OK"
end
-- Создание промокода
function PLUGIN:CreatePromoCode(admin, codeText, amount, maxUses, expiresAt, allowedRanks)
if not IsValid(admin) then return false, "Недействительный игрок" end
-- Проверка прав
if not admin:IsSuperAdmin() then
return false, "У вас нет прав для создания промокодов"
end
-- Генерация кода если не указан
if not codeText or codeText == "" then
codeText = self:GenerateCode(8)
print(string.format("[PROMOCODES] Сгенерирован случайный промокод: %s", codeText))
else
-- Валидация именного кода
local valid, error = self:ValidateCustomCode(codeText)
if not valid then
return false, error
end
print(string.format("[PROMOCODES] Создается именной промокод: %s", codeText))
end
codeText = string.upper(codeText)
-- Проверка существования
if self.promoCodes[codeText] then
return false, "Промокод с таким кодом уже существует"
end
-- Создание промокода
self.promoCodes[codeText] = {
code = codeText,
amount = math.max(1, tonumber(amount) or 100),
maxUses = math.max(1, tonumber(maxUses) or 1),
currentUses = 0,
expiresAt = tonumber(expiresAt) or (os.time() + 86400 * 30), -- По умолчанию 30 дней
allowedRanks = allowedRanks or {}, -- Пустой массив = доступно всем
createdBy = admin:SteamID(),
createdAt = os.time()
}
self.promoUsage[codeText] = {}
self:SavePromoCodes()
return true, "Промокод '" .. codeText .. "' создан на " .. self.promoCodes[codeText].amount .. " IGS"
end
-- Удаление промокода
function PLUGIN:DeletePromoCode(admin, codeText)
if not IsValid(admin) then return false, "Недействительный игрок" end
if not admin:IsSuperAdmin() then
return false, "У вас нет прав для удаления промокодов"
end
codeText = string.upper(codeText)
if not self.promoCodes[codeText] then
return false, "Промокод не найден"
end
self.promoCodes[codeText] = nil
self.promoUsage[codeText] = nil
self:SavePromoCodes()
return true, "Промокод '" .. codeText .. "' удален"
end
-- Проверка доступности промокода для игрока
function PLUGIN:CanUsePromoCode(client, codeText)
local promo = self.promoCodes[codeText]
if not promo then
return false, "Промокод не найден"
end
local steamID = client:SteamID()
-- Проверка использования игроком
if self.promoUsage[codeText] and self.promoUsage[codeText][steamID] then
return false, "Вы уже использовали этот промокод"
end
-- Проверка лимита использований
if promo.currentUses >= promo.maxUses then
return false, "Промокод исчерпан"
end
-- Проверка срока действия
if os.time() > promo.expiresAt then
return false, "Срок действия промокода истек"
end
-- Проверка доступных рангов
if promo.allowedRanks and #promo.allowedRanks > 0 then
local playerRank = client:GetUserGroup()
local hasAccess = false
for _, rank in ipairs(promo.allowedRanks) do
if playerRank == rank then
hasAccess = true
break
end
end
if not hasAccess then
return false, "Этот промокод недоступен для вашего ранга"
end
end
return true, "OK"
end
-- Активация промокода
function PLUGIN:ActivatePromoCode(client, codeText)
if not IsValid(client) then return false, "Недействительный игрок" end
codeText = string.upper(string.Trim(codeText))
if codeText == "" then
return false, "Введите промокод"
end
local canUse, reason = self:CanUsePromoCode(client, codeText)
if not canUse then
return false, reason
end
local promo = self.promoCodes[codeText]
local steamID = client:SteamID()
-- Начисление валюты через F4 плагин
local f4Plugin = ix.plugin.Get("f4menu")
if f4Plugin and f4Plugin.AdjustIGSBalance then
local success, error = f4Plugin:AdjustIGSBalance(client, promo.amount)
if not success then
return false, "Ошибка начисления валюты: " .. (error or "неизвестная ошибка")
end
else
return false, "Система доната недоступна"
end
-- Обновление данных промокода
promo.currentUses = promo.currentUses + 1
if not self.promoUsage[codeText] then
self.promoUsage[codeText] = {}
end
self.promoUsage[codeText][steamID] = true
self:SavePromoCodes()
-- Лог
print(string.format("[PROMOCODES] %s активировал промокод '%s' (+%d IGS)", client:Name(), codeText, promo.amount))
return true, string.format("Промокод активирован! Вы получили %d IGS", promo.amount)
end
-- Загрузка при старте
function PLUGIN:InitializedPlugins()
self:LoadPromoCodes()
end
-- Сетевые обработчики
net.Receive("ixPromoCodeActivate", function(len, client)
local code = net.ReadString()
local plugin = ix.plugin.Get("promocodes")
if not plugin then return end
local success, message = plugin:ActivatePromoCode(client, code)
net.Start("ixPromoCodeResult")
net.WriteBool(success)
net.WriteString(message)
net.Send(client)
end)
net.Receive("ixPromoCodeCreate", function(len, client)
if not client:IsSuperAdmin() then return end
local code = net.ReadString()
local amount = net.ReadUInt(32)
local maxUses = net.ReadUInt(16)
local expiresAt = net.ReadUInt(32)
local ranksCount = net.ReadUInt(8)
local allowedRanks = {}
for i = 1, ranksCount do
table.insert(allowedRanks, net.ReadString())
end
local plugin = ix.plugin.Get("promocodes")
if not plugin then return end
local success, message = plugin:CreatePromoCode(client, code, amount, maxUses, expiresAt, allowedRanks)
net.Start("ixPromoCodeResult")
net.WriteBool(success)
net.WriteString(message)
net.Send(client)
if success then
-- Отправляем обновленный список
plugin:SyncPromoCodesList(client)
end
end)
net.Receive("ixPromoCodeDelete", function(len, client)
if not client:IsSuperAdmin() then return end
local code = net.ReadString()
local plugin = ix.plugin.Get("promocodes")
if not plugin then return end
local success, message = plugin:DeletePromoCode(client, code)
net.Start("ixPromoCodeResult")
net.WriteBool(success)
net.WriteString(message)
net.Send(client)
if success then
plugin:SyncPromoCodesList(client)
end
end)
net.Receive("ixPromoCodeList", function(len, client)
if not client:IsSuperAdmin() then return end
local plugin = ix.plugin.Get("promocodes")
if not plugin then return end
plugin:SyncPromoCodesList(client)
end)
-- Синхронизация списка промокодов
function PLUGIN:SyncPromoCodesList(client)
if not IsValid(client) or not client:IsSuperAdmin() then return end
local codesList = {}
for code, data in pairs(self.promoCodes) do
table.insert(codesList, data)
end
net.Start("ixPromoCodeSync")
net.WriteString(util.TableToJSON(codesList))
net.Send(client)
end