MAATRIX GAMES / Блог / FiveM: банковская система и кредиты

FiveM: банковская система и кредиты

MAATRIX GAMES

Банк на RP-сервере уже стоит, игроки кладут и снимают деньги — и тут в чате начинают спрашивать «а кредит на тачку дадите?». Кредитная система — это не косметика поверх банка, а полноценный экономический механизм со своими рисками: если раздать займы без лимитов и без плана погашения, через пару недель половина сервера будет в долгах, которые никто не собирается возвращать, а вторая половина обнаружит, что деньги обесценились. Разберём, как выстроить кредиты так, чтобы они работали на геймплей, а не разносили экономику, которую ты уже настраивал.

Как устроена кредитная система поверх банка

Кредит на FiveM RP-сервере — это отдельная сущность, а не просто «минус на счету». Минимально нужна таблица в базе, где хранится сумма долга, ставка, срок и статус, плюс серверный скрипт, который раз в определённый интервал списывает платёж и проверяет просрочки. Готового «стандартного» решения нет ни в ESX, ни в QBCore — банковские ресурсы (qb-banking, esx_atm и форки) обычно ограничиваются переводами и историей операций, кредиты добавляются либо кастомным скриптом, либо через сторонние ресурсы с форума CFX/Tebex.

Базовая структура таблицы под MySQL, от которой можно оттолкнуться:

CREATE TABLE loans (
    id INT AUTO_INCREMENT PRIMARY KEY,
    citizenid VARCHAR(50) NOT NULL,
    amount INT NOT NULL,
    rate FLOAT NOT NULL,
    term_days INT NOT NULL,
    remaining INT NOT NULL,
    daily_payment INT NOT NULL,
    missed_payments INT DEFAULT 0,
    status ENUM('active','closed','defaulted') DEFAULT 'active',
    created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
);

Серверная логика в общих чертах: при выдаче кредита создаётся запись, remaining считается как сумма с учётом процента (amount * (1 + rate)), daily_payment — это remaining / term_days. Дальше по таймеру (SetInterval на сервере, раз в игровые сутки — удобно синхронизировать с циклом зарплат) скрипт проходит по активным кредитам и списывает очередной платёж со счёта игрока. Не хватает баланса — растёт счётчик missed_payments, от него зависит, что будет дальше.

Если банковская система на сервере ещё не настроена по деньгам в принципе — стартовые балансы, зарплаты и money sinks — сначала разберись с базовой настройкой экономики, кредиты имеет смысл добавлять поверх уже сбалансированной системы, а не вместо неё.

Процентная ставка: как её выбрать и не разрушить экономику

Ставка по кредиту — это одновременно и money sink (проценты выводят деньги из оборота), и риск (чем выше ставка, тем чаще игроки уходят в дефолт вместо погашения). Универсальной цифры для RP-сервера нет — она зависит от темпа заработка на конкретном сервере, но есть рабочий принцип: ставка должна быть заметно выше банковского депозита (если он у тебя вообще есть), но не настолько высокой, чтобы платёж по кредиту съедал большую часть дневного дохода среднего игрока.

Ориентир, от которого можно оттолкнуться: 5-15% годовых в пересчёте на игровое время, разбитых на равные ежедневные или еженедельные платежи. Это именно ориентир, не измеренное значение — тестируй на живых цифрах своей экономики.

Практичнее закладывать не единую ставку, а сетку — чтобы игроки с большей историей на сервере или более надёжным статусом получали более выгодные условия:

Config.LoanRates = {
    default = 0.15,   -- базовая ставка для новых игроков
    verified = 0.10,  -- для игроков с whitelist-статусом дольше N дней
    vip = 0.07,       -- для доверенных / донат-статусов, если такое есть на сервере
}

Дифференцированная ставка выполняет двойную функцию: снижает риск для банка (те, кто дольше на сервере, реже пропадают без возврата долга) и даёт игрокам стимул «расти» на сервере — ещё один крючок для удержания.

Поднять сервер FiveM (GTA V) за пару минут

Готовый образ MAATRIX GAMES: NVMe, AMD EPYC, DDoS-защита, панель управления. Локации UK, US, RU. Оплата картой РФ, СБП или криптой.

Создать сервер

Лимит кредита по job и статусу игрока

Выдавать кредит без ограничения суммы под фиксированный доход — прямой путь к тому, что игрок берёт займ, который физически не может закрыть своей зарплатой. Логичнее привязывать максимальную сумму кредита к тому, сколько игрок реально зарабатывает — а это напрямую завязано на job. Если экономика зарплат уже настроена (см. систему работ на RP-сервере), лимит кредита логично считать как множитель от условной «дневной ставки» по текущей работе игрока.

Пример реализации в стиле QBCore — функция считает максимум по job-грейду и по общему статусу аккаунта:

function GetMaxLoanAmount(Player)
    local job = Player.PlayerData.job
    local basePay = job.grade.payment or 50
    local jobMultiplier = 30 -- сколько "дневных зарплат" максимум можно занять

    local baseLimit = basePay * jobMultiplier

    -- бонус для боссов и госслужащих (полиция, EMS) — считаем более надёжными плательщиками
    if job.isboss or job.type == 'leo' then
        baseLimit = baseLimit * 1.5
    end

    -- штраф для безработных или недавно созданных персонажей
    if job.name == 'unemployed' then
        baseLimit = baseLimit * 0.3
    end

    return math.floor(baseLimit)
end

Отдельно стоит учитывать возраст персонажа (сколько дней с момента создания) и наличие активных банов/жалоб в системе модерации — если у тебя уже настроена Discord-интеграция с тикетами, логично подтягивать оттуда статус доверия при расчёте лимита. Игроку с активными нарушениями или без whitelist-подтверждения крупные кредиты давать рискованно — он вряд ли задержится настолько, чтобы закрыть долг.

Второй кредит поверх непогашенного первого — частая дыра в самодельных скриптах. Проверка перед выдачей обязана блокировать новый займ, пока статус предыдущего не closed:

local hasActiveLoan = MySQL.scalar.await('SELECT COUNT(*) FROM loans WHERE citizenid = ? AND status = ?', {citizenid, 'active'})
if hasActiveLoan > 0 then
    TriggerClientEvent('QBCore:Notify', src, 'У вас уже есть непогашенный кредит', 'error')
    return
end

Погашение: график платежей и автосписание

Ручное погашение кредита («игрок сам не забудет прийти в банк и заплатить») на практике не работает — забывают все, не по злому умыслу, а просто потому что RP-сессия редко длится достаточно долго. Рабочая схема — автосписание по таймеру прямо со счёта bank, с уведомлением при каждом списании и при неудачной попытке.

CreateThread(function()
    while true do
        Wait(24 * 60 * 60 * 1000) -- раз в игровые сутки, подстрой под темп сервера
        local activeLoans = MySQL.query.await('SELECT * FROM loans WHERE status = ?', {'active'})
        for _, loan in ipairs(activeLoans) do
            ProcessLoanPayment(loan)
        end
    end
end)

Важный нюанс: списание должно идти именно со счёта в банке (bank), а не с нала на руках — иначе игрок, который держит деньги в кармане, физически не может расплатиться автоматически, и просрочка будет не по его вине. Если денег не хватает на весь платёж, разумно списать частично то, что есть, а остаток добавить к счётчику пропусков — полностью пропускать платёж из-за недостатка даже одной монеты негуманно.

Отдельно стоит дать игроку возможность закрыть кредит досрочно одной суммой — это снимает административную нагрузку и обычно воспринимается как честная опция.

Просрочки: коллекторы, чёрный список, конфискация

Что происходит после нескольких пропущенных платежей — вопрос, который стоит продумать до запуска кредитов, а не постфактум, когда в чате уже поднимется шум из-за первого «наказанного» игрока. Градация строится по нарастающей:

  • 1-2 пропуска — предупреждение (уведомление в игре + сообщение в Discord, если есть привязка аккаунта), процентная ставка на оставшийся долг может немного вырасти как штраф.
  • 3+ пропуска — блокировка новых кредитов и части банковских операций (например, крупных переводов) до погашения текущего долга.
  • Затяжной дефолт (пропуски выше настроенного порога) — передача долга «коллекторам»: это может быть чисто игровой RP-элемент (NPC-фракция или игроки-коллекторы с квестом на взыскание) либо механическая мера — конфискация части имущества/транспорта в пользу банка.
function CheckLoanDefault(loan)
    if loan.missed_payments >= Config.DefaultThreshold then
        MySQL.update('UPDATE loans SET status = ? WHERE id = ?', {'defaulted', loan.id})
        -- триггерим RP-событие или административную меру
        TriggerEvent('bank:loanDefaulted', loan.citizenid, loan.id)
    end
end

Конфискация транспорта под залог кредита требует отдельной аккуратности: если машина уже продана другому игроку или разбита, скрипт должен это корректно обработать, а не падать в ошибку или конфисковывать чужое имущество. Проще всего оформить это отдельным флагом collateral_vehicle_plate в таблице loans, привязанным к госномеру на момент выдачи, с проверкой владельца перед изъятием.

Полный «бан» игрока за невозврат кредита — плохая идея почти всегда: это выглядит как наказание за игровую механику, а не за нарушение правил, и бьёт по удержанию сильнее, чем сам недополученный долг. Ограничений в рамках банка (нет новых кредитов, заморожен счёт сверх минимума) достаточно почти всегда.

Риск для экономики: массовые невозвраты

Отдельный кредит, который не вернули, — локальная проблема одного игрока и банка. Массовые невозвраты — уже системный риск для всей экономики, и на него стоит смотреть заранее. Механика возникает обычно в двух сценариях: волна вайпов/банов игроков с активными кредитами (долг «испаряется» вместе с персонажем) или скоординированный фарм — группа игроков массово берёт максимальные кредиты и намеренно уходит в дефолт, зная, что последствий для них нет.

Несколько практических мер, которые снижают этот риск:

  • Резерв на балансе банка. Если в системе есть условный «баланс банка» как отдельная сущность, закладывай в него часть процентов от выданных кредитов как буфер на случай невозвратов выше ожидаемых.
  • Лимит суммарной кредитной массы. Ограничь не только сумму на игрока, но и совокупный объём активных кредитов относительно денежной массы сервера — SQL-запрос раз в неделю (SUM(remaining) FROM loans WHERE status = 'active') покажет, не разрослась ли нагрузка.
  • Привязка к персонажу с ретеншном долга. Если персонаж удаляется через мультичарактер-меню, реши заранее: списывать долг как убыток банка или переносить обязательство иначе — поведение должно быть зафиксировано в скрипте, а не отдано на «как получится».
  • Постепенное ужесточение, а не резкое. Если невозвраты идут выше ожидаемого — снижай лимиты и поднимай требования к статусу постепенно (10-20% за итерацию), резкое ужесточение воспринимается как несправедливость.

Таблица для ориентира, как разные пороги влияют на риск — цифры условные, подстраивай под темп своей экономики:

ПорогКонсервативноСбалансированноАгрессивно
Множитель к дневной зарплате15-20x25-35x40x+
Ставка12-18%8-12%3-7%
Порог дефолта (пропусков)357+
Риск для экономикинизкийсреднийвысокий при росте онлайна

Если сервер только запускается или ещё не набрал стабильное комьюнити — начинай с консервативных значений: гораздо проще потом ослаблять условия под запросы игроков, чем откатывать уже розданные крупные кредиты после того, как экономика поплыла.

Поднять сервер FiveM (GTA V) за пару минут

Готовый образ MAATRIX GAMES: NVMe, AMD EPYC, DDoS-защита, панель управления. Локации UK, US, RU. Оплата картой РФ, СБП или криптой.

Создать сервер

Частые вопросы

Нужен ли отдельный ресурс для кредитов или можно встроить в банковский скрипт?

Можно дописать таблицу и функции прямо в qb-banking/esx_atm, но отдельный ресурс проще поддерживать независимо от банковского ядра, особенно если оно обновляется форком с CFX.

Как кредиты сочетаются с ESX и QBCore, если сервер использует нестандартный core?

Логика (таблица, ставки, лимиты) переносится почти без изменений, отличаются только вызовы job и баланса — под ESX это xPlayer.job и xPlayer.getAccount('bank'), под QBCore — Player.PlayerData.job.

Стоит ли давать кредиты новым игрокам сразу после регистрации?

Разумнее ввести порог по времени на сервере (персонаж существует от нескольких игровых дней) — это отсекает часть скоординированного фарма на свежесозданных персонажах, которых потом удаляют.

Можно ли выдавать кредиты в чёрном нале (black money)?

Технически да, но с точки зрения RP это нелогично — банк не работает с нелегальными деньгами, большинство серверов ограничивают кредиты легальным счётом bank, оставляя чёрный нал отдельной параллельной экономикой.