-- client/finance.lua print("^2[turfwar]^7 finance client loaded") if IsDuplicityVersion() then return end Config = Config or {} Config.Finance = Config.Finance or {} local uiOpen = false local atmToken = nil local lastUse = 0 local USE_COOLDOWN = 800 local function CanUse() local now = GetGameTimer() if (now - lastUse) < USE_COOLDOWN then return false end lastUse = now return true end local function Notify(msg) BeginTextCommandThefeedPost("STRING") AddTextComponentSubstringPlayerName(msg) EndTextCommandThefeedPostTicker(false, false) end local function Draw3DText(coords, text) local onScreen, x, y = World3dToScreen2d(coords.x, coords.y, coords.z) if not onScreen then return end SetTextScale(0.35, 0.35) SetTextFont(4) SetTextCentre(true) SetTextEntry("STRING") AddTextComponentSubstringPlayerName(text) DrawText(x, y) end local function ForceCloseATMUI() uiOpen = false atmToken = nil SetNuiFocus(false, false) SendNUIMessage({ type = "atm:close" }) end AddEventHandler("onClientResourceStart", function(res) if res ~= GetCurrentResourceName() then return end Wait(800) ForceCloseATMUI() end) AddEventHandler("playerSpawned", function() Wait(800) ForceCloseATMUI() end) -- Server says OK -> open UI RegisterNetEvent("turfwar:atm:openGranted", function(token) atmToken = token uiOpen = true SetNuiFocus(true, true) SendNUIMessage({ type = "atm:open" }) TriggerServerEvent("turfwar:atm:balance", atmToken) end) RegisterNetEvent("turfwar:atm:openDenied", function(reason) print(("^1[turfwar]^7 ATM denied: %s"):format(tostring(reason))) Notify(("~r~ATM denied~s~ (%s)"):format(tostring(reason))) end) -- NUI callbacks RegisterNUICallback("atm:close", function(_, cb) ForceCloseATMUI() cb(true) end) RegisterNUICallback("atm:deposit", function(data, cb) if not uiOpen or not atmToken then cb(false) return end TriggerServerEvent("turfwar:bank:deposit", atmToken, data.amount) cb(true) end) RegisterNUICallback("atm:withdraw", function(data, cb) if not uiOpen or not atmToken then cb(false) return end TriggerServerEvent("turfwar:bank:withdraw", atmToken, data.amount) cb(true) end) -- Only update UI when it’s open RegisterNetEvent("turfwar:money:update", function(cash, bank) if not uiOpen then return end SendNUIMessage({ type = "atm:balances", cash = cash, bank = bank }) end) -- ATM Detection (CLIENT!) CreateThread(function() while true do Wait(0) local ped = PlayerPedId() if ped == 0 then Wait(500) goto continue end local pcoords = GetEntityCoords(ped) local dist = Config.Finance.INTERACT_DIST or 1.5 local key = Config.Finance.INTERACT_KEY or 38 local found = false for _, model in ipairs(Config.Finance.ATM_MODELS or {}) do -- ✅ correct signature local atm = GetClosestObjectOfType(pcoords.x, pcoords.y, pcoords.z, 1.6, model, false, false, false) if atm and atm ~= 0 then found = true local acoords = GetEntityCoords(atm) Draw3DText(vector3(acoords.x, acoords.y, acoords.z + 0.95), "~g~E~w~ Use ATM") if #(pcoords - acoords) <= dist then if IsControlJustPressed(0, key) and CanUse() then -- ✅ send payload server expects TriggerServerEvent("turfwar:atm:open", { x = acoords.x, y = acoords.y, z = acoords.z, model = model }) end end end end if not found then Wait(150) end ::continue:: end end)