Деньги и счета
Читать и менять балансы игрока, счета работ и банд, перемещать деньги между двумя счетами одной транзакцией, читать типы счетов.
У каждого персонажа есть по одному балансу на каждый тип счёта. Типы берутся из списка Accounts в админ-панели; на новом сервере есть cash, bank, black_money и crypto. У каждой работы и банды тоже есть по одному счёту каждого типа (деньги организации), который изначально пуст.
Как работают деньги в ai-core:
- Суммы - целые числа (доллары, без центов). Дробь,
NaNили число за пределами безопасного диапазона целых в JavaScript отклоняются. - Изменение сразу применяется в памяти и записывается в базу данных примерно в течение 50 мс вместе со строкой журнала операций (
ai_core_transactions). Журнал хранит переданный вамиreason; без него он хранит имя вызвавшего ресурса. - Баланс не может опуститься ниже 0, если у его типа счёта в панели не включено Can go below zero.
- Каждое изменение счёта игрока вызывает серверное событие
ai-core:moneyChanged (src, account, balance, delta, reason)и доходит до игры самого игрока. См. События и состояние.
GetMoney
Баланс игрока на одном счёте.
Сторона: сервер · Ожидание: нет · Библиотека: нет
GetMoney(src: number, account: string): number | nulllocal balance = exports['ai-core']:GetMoney(source, 'bank') -- number или nilПараметры
Prop
Type
Возвращает
number | null: баланс. null, когда у игрока нет загруженного персонажа или тип счёта не существует.
Пример
import { onClientCallback, resourceExport } from "@aicore-fivem/lib/server";
import { fail } from "@aicore-fivem/lib/shared";
const core = resourceExport("ai-core");
onClientCallback("myscript:balance", (source) => {
const bank = core.GetMoney(source, "bank");
if (bank === null) return fail("NO_CHARACTER");
return { ok: true, bank };
});AddMoney
Добавляет деньги на счёт игрока. Используйте для наград, зарплат, которые платит ваш скрипт, или дохода от продаж.
Сторона: сервер · Ожидание: нет · Библиотека: нет
AddMoney(src: number, account: string, amount: number, reason?: string): booleanlocal ok = exports['ai-core']:AddMoney(source, 'cash', 250, 'fishing_sale')Параметры
Prop
Type
Возвращает
boolean: true, когда деньги добавлены. false, когда у игрока нет загруженного персонажа, тип счёта не существует или amount не целое число больше 0.
Пример
import { onClientCallback, inventory, resourceExport, near } from "@aicore-fivem/lib/server";
import { fail } from "@aicore-fivem/lib/shared";
const core = resourceExport("ai-core");
const BUYER = { x: -1845.2, y: -1197.4, z: 14.3 };
onClientCallback("myscript:sellFish", { guards: [near(BUYER, 3)], lock: true }, (source) => {
const fish = inventory.getItemCount(source, "fish");
if (fish < 1) return fail("NO_FISH");
if (!inventory.removeItem(source, "fish", fish)) return fail("SELL_FAILED");
core.AddMoney(source, "cash", fish * 25, "fishing_sale");
return { ok: true };
});Чтобы переместить деньги с одного счёта на другой (игрок платит работе, банковский перевод), используйте TransferMoney, а не пару RemoveMoney + AddMoney: перевод - это одна транзакция в базе данных, а пара - два отдельных изменения.
RemoveMoney
Забирает деньги со счёта игрока. Используйте, чтобы взять плату за что-либо.
Сторона: сервер · Ожидание: нет · Библиотека: нет
RemoveMoney(src: number, account: string, amount: number, reason?: string): booleanlocal paid = exports['ai-core']:RemoveMoney(source, 'bank', 500, 'license_fee')Параметры
Prop
Type
Возвращает
boolean: true, когда деньги забраны. false, когда баланса не хватает (а тип счёта не разрешает отрицательный баланс), у игрока нет загруженного персонажа, тип счёта не существует или amount не целое число больше 0. При false ничего не изменилось.
Пример
import { onClientCallback, inventory, resourceExport } from "@aicore-fivem/lib/server";
import { fail } from "@aicore-fivem/lib/shared";
const core = resourceExport("ai-core");
const PRICE = 500;
onClientCallback("myscript:buyLicense", { lock: true }, (source) => {
if (!inventory.canCarryItem(source, "driver_license")) return fail("NO_SPACE");
if (!core.RemoveMoney(source, "bank", PRICE, "license_fee")) return fail("NOT_ENOUGH_MONEY");
inventory.addItem(source, "driver_license");
return { ok: true };
});Проверьте то, что может не получиться, до того как забрать деньги (место в инвентаре, наличие товара), или верните деньги через AddMoney, когда следующий шаг не удался.
SetMoney
Устанавливает баланс игрока в точное значение. Используйте для админских инструментов; игровые функции должны добавлять и забирать.
Сторона: сервер · Ожидание: нет · Библиотека: нет
SetMoney(src: number, account: string, amount: number, reason?: string): booleanlocal ok = exports['ai-core']:SetMoney(source, 'cash', 0, 'admin_reset')Параметры
Prop
Type
Возвращает
boolean: true, когда баланс теперь равен amount (и тогда, когда уже был). false, когда у игрока нет загруженного персонажа, тип счёта не существует, amount не целое число или он ниже 0 на счёте, который этого не разрешает.
Пример
import { addCommand, resourceExport } from "@aicore-fivem/lib/server";
const core = resourceExport("ai-core");
addCommand("setcash", {
help: "Sets a player cash",
params: [{ name: "id", type: "playerId" }, { name: "amount", type: "number" }],
restricted: true,
}, (_source, args) => {
console.log(core.SetMoney(args.id, "cash", args.amount, "admin_set") ? "done" : "refused");
});GetSharedMoney
Баланс счёта работы или банды (деньги организации).
Сторона: сервер · Ожидание: нет · Библиотека: нет (banking.societyBalance спрашивает банковский слой, который может читать банковский скрипт)
GetSharedMoney(ownerType: "job" | "gang", ownerId: string, account: string): number | nulllocal balance = exports['ai-core']:GetSharedMoney('job', 'police', 'bank') -- number или nilПараметры
Prop
Type
Возвращает
number | null: баланс. null, когда работа, банда или тип счёта не существует (или её счета ещё не загружены).
Пример
import { onClientCallback, online, resourceExport } from "@aicore-fivem/lib/server";
import { fail } from "@aicore-fivem/lib/shared";
const core = resourceExport("ai-core");
// Меню босса показывает деньги работы; спрашивать могут только сотрудники этой работы.
onClientCallback("myscript:societyBalance", (source) => {
const job = online.dutyJob(source);
if (!job) return fail("NOT_ON_DUTY");
return { ok: true, balance: core.GetSharedMoney("job", job, "bank") ?? 0 };
});Когда в настройке панели Job and gang accounts выбрано The script's own accounts, счета bank работ и банд живут в этом скрипте: тогда этот экспорт читает баланс скрипта. См. Банк.
AddSharedMoney
Добавляет деньги на счёт работы или банды.
Сторона: сервер · Ожидание: нет · Библиотека: нет
AddSharedMoney(
ownerType: "job" | "gang",
ownerId: string,
account: string,
amount: number,
reason?: string,
): booleanlocal ok = exports['ai-core']:AddSharedMoney('job', 'mechanic', 'bank', 300, 'repair_fee')Параметры
Prop
Type
Возвращает
boolean: true, когда деньги добавлены. false, когда работа, банда или счёт не существует или amount не целое число больше 0.
Пример
import { resourceExport } from "@aicore-fivem/lib/server";
const core = resourceExport("ai-core");
/** A sale made by an NPC customer goes into the restaurant's account. */
export function restaurantSale(job: string, price: number): void {
if (!core.AddSharedMoney("job", job, "bank", price, "npc_sale"))
console.log(`job ${job} has no bank account`);
}Когда игрок платит работе, используйте TransferMoney со счёта игрока на счёт работы: одна транзакция, обе строки журнала.
RemoveSharedMoney
Забирает деньги со счёта работы или банды.
Сторона: сервер · Ожидание: нет · Библиотека: нет
RemoveSharedMoney(
ownerType: "job" | "gang",
ownerId: string,
account: string,
amount: number,
reason?: string,
): booleanlocal ok = exports['ai-core']:RemoveSharedMoney('job', 'police', 'bank', 2000, 'equipment')Параметры
Prop
Type
Возвращает
boolean: true, когда деньги забраны. false, когда баланса не хватает (а отрицательный баланс не разрешён), работа, банда или счёт не существует или amount не целое число больше 0.
Пример
import { onClientCallback, online, resourceExport } from "@aicore-fivem/lib/server";
import { fail } from "@aicore-fivem/lib/shared";
const core = resourceExport("ai-core");
// Работа заказывает материалы со своего счёта.
onClientCallback("myscript:orderSupplies", { lock: true }, (source) => {
const job = online.dutyJob(source);
if (!job) return fail("NOT_ON_DUTY");
if (!core.RemoveSharedMoney("job", job, "bank", 1500, "supplies")) return fail("SOCIETY_NO_MONEY");
return { ok: true };
});TransferMoney
Перемещает деньги с одного счёта на другой одной транзакцией в базе данных с обеими строками журнала. Каждая сторона может быть счётом загруженного игрока или счётом работы или банды. Используйте для каждого платежа между двумя счетами: игрок платит бизнесу, банковский перевод, взнос в организацию.
Сторона: сервер · Ожидание: нет · Библиотека: money.transfer
TransferMoney(from: MoneyRef, to: MoneyRef, amount: number, reason?: string, fee?: number): booleanlocal ok = exports['ai-core']:TransferMoney(
{ source = source, account = 'bank' },
{ owner = 'job', id = 'mechanic', account = 'bank' },
750, 'repair', 0)Параметры
Prop
Type
MoneyRef - это { source, account } для счёта загруженного игрока или { owner, id, account } для счёта работы или банды. См. MoneyRef.
Возвращает
boolean: true, когда from заплатил amount + fee, а to получил amount. false, когда счёт отсутствует (игрок не загружен, неизвестная работа, неизвестный тип счёта), обе стороны - один и тот же счёт, from не может заплатить amount + fee, amount не целое число больше 0 или fee не целое число от 0. При false ничего не изменилось.
Пример
import { onClientCallback, resourceExport } from "@aicore-fivem/lib/server";
import { fail, readInt } from "@aicore-fivem/lib/shared";
const core = resourceExport("ai-core");
// Взнос через банкомат на счёт собственной банды игрока, с комиссией 2%.
onClientCallback(
"myscript:gangDeposit",
{ args: ([amount]) => { const n = readInt(amount, 1, 1_000_000); return n === null ? null : [n]; }, lock: true },
(source, amount) => {
const gang = core.GetActiveGang(source);
if (!gang) return fail("NO_GANG");
const fee = Math.ceil(amount * 0.02);
const ok = core.TransferMoney(
{ source, account: "bank" },
{ owner: "gang", id: gang, account: "bank" },
amount, "gang_deposit", fee,
);
return ok ? { ok: true } : fail("NOT_ENOUGH_MONEY");
},
);Обе стороны вызывают своё обычное событие изменения (сторона игрока вызывает ai-core:moneyChanged). Обеими сторонами могут быть два игрока: { source: a, account: "bank" } в { source: b, account: "bank" }.
GetAccountTypes
Все типы счетов из списка Accounts в панели, с подписью, начальной суммой и тем, может ли баланс уходить в минус. Используйте, чтобы построить меню счетов или проверить имя.
Сторона: сервер · Ожидание: нет · Библиотека: нет
GetAccountTypes(): Record<string, AccountTypeDefinition>local types = exports['ai-core']:GetAccountTypes() -- таблица с ключами по имени счётаПараметры
Нет.
Возвращает
Record<string, AccountTypeDefinition>: копия с ключами по имени счёта (cash, bank...). У каждого значения есть label (видят игроки), start (что получает новый персонаж) и allowNegative. См. AccountTypeDefinition.
Пример
import { onClientCallback, resourceExport } from "@aicore-fivem/lib/server";
const core = resourceExport("ai-core");
// Экран кошелька показывает каждый счёт с подписью и балансом.
onClientCallback("myscript:wallet", (source) => {
const rows = Object.entries(core.GetAccountTypes()).map(([name, type]) => ({
name,
label: type.label,
balance: core.GetMoney(source, name) ?? 0,
}));
return { ok: true, rows };
});Персонажи и игроки
Прочитать данные и персонажа загруженного игрока, найти игрока по id персонажа или citizen id, сменить персонажа, переместить офлайн-персонажа, игроки в зоне видимости.
Работы и банды
Читать и менять работы, банды, ранги и дежурство персонажа, считать игроков на дежурстве, прайм-тайм, читать определения работ и банд.