--[[ m-banking — customize_me.lua Every place where this script talks to something project-specific. Reskin your server's notifications, sounds and progress bars here and never touch the core logic. This file is shared (client + server). Server-side calls pass a `source`, client-side calls pass nil. ]] Bank = Bank or {} local isServer = IsDuplicityVersion() -- ───────────────────────────────────────────────────────────────────────────── -- Notifications -- ───────────────────────────────────────────────────────────────────────────── --- Show a notification. --- @param source number|nil server id on the server, nil on the client --- @param message string --- @param type string 'success' | 'error' | 'inform' | 'warning' function Bank.Notify(source, message, type) type = type or 'inform' if isServer then if not source then return end TriggerClientEvent('ox_lib:notify', source, { title = L('notify.title'), description = message, type = type, position = 'top-right' }) else lib.notify({ title = L('notify.title'), description = message, type = type, position = 'top-right' }) end -- Example replacement (esx notifications): -- if isServer then TriggerClientEvent('esx:showNotification', source, message) -- else ESX.ShowNotification(message) end end -- ───────────────────────────────────────────────────────────────────────────── -- Progress bar (client only) -- ───────────────────────────────────────────────────────────────────────────── --- Blocking progress circle. Return false to cancel the action. --- @param label string --- @param duration number milliseconds --- @return boolean completed function Bank.Progress(label, duration) if isServer then return true end return lib.progressCircle({ label = label, duration = duration, position = 'bottom', useWhileDead = false, canCancel = true, disable = { move = false, car = true, combat = true } }) or false end -- ───────────────────────────────────────────────────────────────────────────── -- Sounds (client only) -- ───────────────────────────────────────────────────────────────────────────── --- @param name string 'beep' | 'cash' | 'error' | 'card' function Bank.PlaySound(name) if isServer then return end local sounds = { beep = { 'ATM_WINDOW', 'HUD_FRONTEND_DEFAULT_SOUNDSET' }, cash = { 'PURCHASE', 'HUD_LIQUOR_STORE_SOUNDSET' }, error = { 'ERROR', 'HUD_FRONTEND_DEFAULT_SOUNDSET' }, card = { 'SELECT', 'HUD_FRONTEND_DEFAULT_SOUNDSET' } } local sound = sounds[name] if not sound then return end PlaySoundFrontend(-1, sound[1], sound[2], true) -- Example replacement (interact-sound): -- TriggerServerEvent('InteractSound_SV:PlayWithinDistance', 5.0, name, 0.4) end -- ───────────────────────────────────────────────────────────────────────────── -- Hooks for other resources (server only) -- ───────────────────────────────────────────────────────────────────────────── -- Listen to these from your logging / Discord webhook resource: -- AddEventHandler('m-banking:onTransfer', function(data) ... end) -- -- data = { -- identifier, source, iban, amount, fee, balance, -- targetIban, targetIdentifier, note, atm, type -- } --- @param event string 'onDeposit' | 'onWithdraw' | 'onTransfer' | 'onIbanChange' | 'onCardIssued' | 'onLockout' --- @param data table function Bank.Hook(event, data) if not isServer then return end TriggerEvent('m-banking:' .. event, data) if Config.Debug then print(('[m-banking] %s %s'):format(event, json.encode(data))) end -- Example Discord webhook: -- PerformHttpRequest(WEBHOOK_URL, function() end, 'POST', json.encode({ -- content = ('%s | %s | %s€'):format(event, data.identifier, data.amount) -- }), { ['Content-Type'] = 'application/json' }) end -- ───────────────────────────────────────────────────────────────────────────── -- Money helpers — change these if your server uses a modified account system -- ───────────────────────────────────────────────────────────────────────────── --- @param xPlayer table ESX player object --- @return number --- @param xPlayer table --- @return number function Bank.GetCash(xPlayer) -- Stanje preverimo direktno in izključno preko ox_inventory, da se izognemo desyncu local count = exports.ox_inventory:Search(xPlayer.source, 'count', 'money') return count or 0 end --- @param xPlayer table --- @return number function Bank.GetBank(xPlayer) -- Banka ostane nespremenjena, saj ni fizičen "item" v inventoryju return xPlayer.getAccount(Config.BankAccount).money end --- @param xPlayer table --- @param amount number --- @return boolean function Bank.AddCash(xPlayer, amount) -- Vrnemo vrednost (true/false), da koda, ki to kliče, ve, če je bil item uspešno dodan return exports.ox_inventory:AddItem(xPlayer.source, 'money', amount) end --- @param xPlayer table --- @param amount number --- @return boolean function Bank.RemoveCash(xPlayer, amount) -- ox_inventory:RemoveItem samo po sebi preveri, ali ima igralec dovolj denarja in ga odvzame. -- Vrne 'true', če je uspešno, in 'false', če igralec nima dovolj denarja. return exports.ox_inventory:RemoveItem(xPlayer.source, 'money', amount) end --- @param xPlayer table --- @param amount number function Bank.AddBank(xPlayer, amount) xPlayer.addAccountMoney(Config.BankAccount, amount) end --- @param xPlayer table --- @param amount number function Bank.RemoveBank(xPlayer, amount) xPlayer.removeAccountMoney(Config.BankAccount, amount) end -- ───────────────────────────────────────────────────────────────────────────── -- Formatting -- ───────────────────────────────────────────────────────────────────────────── --- 1234567 -> "1.234.567" --- @param amount number --- @return string function Bank.FormatMoney(amount) local formatted = tostring(math.floor(math.abs(amount or 0))) while true do local replaced formatted, replaced = formatted:gsub('^(%d+)(%d%d%d)', '%1.%2') if replaced == 0 then break end end if (amount or 0) < 0 then formatted = '-' .. formatted end return formatted end