diff --git a/README.md b/README.md index 7c8b1e8b..3f67c05e 100644 --- a/README.md +++ b/README.md @@ -1 +1,15 @@ -# fxserver-esx_atm \ No newline at end of file +# fxserver-esx_atm +FXServer ESX ATM + +[INSTALLATION] + +1) CD in your resources/[esx] folder +2) Clone the repository +``` +git clone https://github.com/FXServer-ESX/fxserver-esx_atm esx_atm +``` +3) Add this in your server.cfg : + +``` +start esx_atm +``` diff --git a/__resource.lua b/__resource.lua new file mode 100644 index 00000000..10f49234 --- /dev/null +++ b/__resource.lua @@ -0,0 +1,18 @@ +description 'ESX ATM' + +server_script 'server/esx_atm_sv.lua' + +client_script { + 'config.lua', + 'client/esx_atm_cl.lua' +} + +ui_page 'html/ui.html' + +files { + 'html/ui.html', + 'html/pdown.ttf', + 'html/img/cursor.png', + 'html/css/app.css', + 'html/scripts/app.js' +} \ No newline at end of file diff --git a/client/esx_atm_cl.lua b/client/esx_atm_cl.lua new file mode 100644 index 00000000..89cb175d --- /dev/null +++ b/client/esx_atm_cl.lua @@ -0,0 +1,129 @@ +local GUI = {} +local hasAlreadyEnteredMarker = false +GUI.MenuIsShowed = false + +ESX = nil + +Citizen.CreateThread(function() + while ESX == nil do + TriggerEvent('esx:getSharedObject', function(obj) ESX = obj end) + Citizen.Wait(0) + end +end) + +TriggerEvent('es:setDefaultSettings', { + nativeMoneySystem = false, +}) + +RegisterNetEvent('esx_atm:closeATM') +AddEventHandler('esx_atm:closeATM', function() + SetNuiFocus(false) + GUI.MenuIsShowed = false + SendNUIMessage({ + hideAll = true + }) +end) + +RegisterNUICallback('escape', function(data, cb) + TriggerEvent('esx_atm:closeATM') + cb('ok') +end) + +RegisterNUICallback('deposit', function(data, cb) + TriggerServerEvent('esx_atm:deposit', data.amount) + cb('ok') +end) + +RegisterNUICallback('withdraw', function(data, cb) + TriggerServerEvent('esx_atm:withdraw', data.amount) + cb('ok') +end) + +-- Create blips +Citizen.CreateThread(function() + for i=1, #Config.ATMS, 1 do + local blip = AddBlipForCoord(Config.ATMS[i].x, Config.ATMS[i].y, Config.ATMS[i].z - Config.ZDiff) + SetBlipSprite (blip, Config.BlipSprite) + SetBlipDisplay(blip, 4) + SetBlipScale (blip, 0.9) + SetBlipColour (blip, 2) + SetBlipAsShortRange(blip, true) + BeginTextCommandSetBlipName("STRING") + AddTextComponentString("ATM") + EndTextCommandSetBlipName(blip) + end +end) + +-- Render markers +Citizen.CreateThread(function() + while true do + Wait(0) + local coords = GetEntityCoords(GetPlayerPed(-1)) + for i=1, #Config.ATMS, 1 do + if(GetDistanceBetweenCoords(coords, Config.ATMS[i].x, Config.ATMS[i].y, Config.ATMS[i].z, true) < Config.DrawDistance) then + DrawMarker(Config.MarkerType, Config.ATMS[i].x, Config.ATMS[i].y, Config.ATMS[i].z - Config.ZDiff, 0.0, 0.0, 0.0, 0, 0.0, 0.0, Config.ZoneSize.x, Config.ZoneSize.y, Config.ZoneSize.z, Config.MarkerColor.r, Config.MarkerColor.g, Config.MarkerColor.b, 100, false, true, 2, false, false, false, false) + end + end + end +end) + +-- Activate menu when player is inside marker +Citizen.CreateThread(function() + while true do + Wait(0) + local coords = GetEntityCoords(GetPlayerPed(-1)) + local isInMarker = false + for i=1, #Config.ATMS, 1 do + if(GetDistanceBetweenCoords(coords, Config.ATMS[i].x, Config.ATMS[i].y, Config.ATMS[i].z, true) < Config.ZoneSize.x / 2) then + isInMarker = true + SetTextComponentFormat('STRING') + AddTextComponentString('Appuyez sur ~INPUT_PICKUP~ pour déposer ou retirer du ~g~cash~s~.') + DisplayHelpTextFromStringLabel(0, 0, 1, -1) + end + end + if isInMarker and not hasAlreadyEnteredMarker then + hasAlreadyEnteredMarker = true + --TriggerEvent('esx_atm:hasEnteredMarker') + end + if not isInMarker and hasAlreadyEnteredMarker then + hasAlreadyEnteredMarker = false + SetNuiFocus(false) + GUI.MenuIsShowed = false + SendNUIMessage({ + hideAll = true + }) + end + end +end) + +-- Menu interactions +Citizen.CreateThread(function() + while true do + Wait(0) + if GUI.MenuIsShowed then + DisableControlAction(0, 1, true) -- LookLeftRight + DisableControlAction(0, 2, true) -- LookUpDown + DisableControlAction(0, 142, true) -- MeleeAttackAlternate + DisableControlAction(0, 106, true) -- VehicleMouseControlOverride + if IsDisabledControlJustReleased(0, 142) then -- MeleeAttackAlternate + SendNUIMessage({ + click = true + }) + end + else + if IsControlJustReleased(0, 38) then + GUI.MenuIsShowed = true + ESX.TriggerServerCallback('esx:getPlayerData', function(data) + SendNUIMessage({ + showMenu = true, + player = { + money = data.money, + accounts = data.accounts + } + }) + end) + SetNuiFocus(true) + end + end + end +end) diff --git a/config.lua b/config.lua new file mode 100644 index 00000000..a57596af --- /dev/null +++ b/config.lua @@ -0,0 +1,53 @@ +Config = {} +Config.MarkerType = 1 +Config.DrawDistance = 100.0 +Config.ZoneSize = {x = 3.0, y = 3.0, z = 0.3} +Config.MarkerColor = {r = 100, g = 100, b = 204} +Config.ZDiff = 2.0 +Config.BlipSprite = 431 + + Config.ATMS = { + { ['x'] = -386.733, ['y'] = 6045.953, ['z'] = 31.501}, + { ['x'] = -110.753, ['y'] = 6467.703, ['z'] = 31.784}, + { ['x'] = 155.4300, ['y'] = 6641.991, ['z'] = 31.784}, + { ['x'] = 174.6720, ['y'] = 6637.218, ['z'] = 31.784}, + { ['x'] = 1703.138, ['y'] = 6426.783, ['z'] = 32.730}, + { ['x'] = 1735.114, ['y'] = 6411.035, ['z'] = 35.164}, + { ['x'] = 1702.842, ['y'] = 4933.593, ['z'] = 42.051}, + { ['x'] = 1967.333, ['y'] = 3744.293, ['z'] = 32.272}, + { ['x'] = 1174.532, ['y'] = 2705.278, ['z'] = 38.027}, + { ['x'] = 2564.399, ['y'] = 2585.100, ['z'] = 38.016}, + { ['x'] = 2558.683, ['y'] = 349.6010, ['z'] = 108.050}, + { ['x'] = 2558.051, ['y'] = 389.4817, ['z'] = 108.660}, + { ['x'] = 1077.692, ['y'] = -775.796, ['z'] = 58.218}, + { ['x'] = 1139.018, ['y'] = -469.886, ['z'] = 66.789}, + { ['x'] = 1168.975, ['y'] = -457.241, ['z'] = 66.641}, + { ['x'] = 1153.884, ['y'] = -326.540, ['z'] = 69.245}, + { ['x'] = 236.4638, ['y'] = 217.4718, ['z'] = 106.840}, + { ['x'] = 265.0043, ['y'] = 212.1717, ['z'] = 106.780}, + { ['x'] = -164.568, ['y'] = 233.5066, ['z'] = 94.919}, + { ['x'] = -1827.04, ['y'] = 785.5159, ['z'] = 138.020}, + { ['x'] = -1409.39, ['y'] = -99.2603, ['z'] = 52.473}, + { ['x'] = -1215.64, ['y'] = -332.231, ['z'] = 37.881}, + { ['x'] = -2072.41, ['y'] = -316.959, ['z'] = 13.345}, + { ['x'] = -2975.72, ['y'] = 379.7737, ['z'] = 14.992}, + { ['x'] = -2962.60, ['y'] = 482.1914, ['z'] = 15.762}, + { ['x'] = -3144.13, ['y'] = 1127.415, ['z'] = 20.868}, + { ['x'] = -1305.40, ['y'] = -706.240, ['z'] = 25.352}, + { ['x'] = -717.614, ['y'] = -915.880, ['z'] = 19.268}, + { ['x'] = -526.566, ['y'] = -1222.90, ['z'] = 18.434}, + { ['x'] = 149.4551, ['y'] = -1038.95, ['z'] = 29.366}, + { ['x'] = -846.304, ['y'] = -340.402, ['z'] = 38.687}, + { ['x'] = -1216.27, ['y'] = -331.461, ['z'] = 37.773}, + { ['x'] = -56.1935, ['y'] = -1752.53, ['z'] = 29.452}, + { ['x'] = -273.001, ['y'] = -2025.60, ['z'] = 30.197}, + { ['x'] = 314.187, ['y'] = -278.621, ['z'] = 54.170}, + { ['x'] = -351.534, ['y'] = -49.529, ['z'] = 49.042}, + { ['x'] = -1570.197, ['y'] = -546.651, ['z'] = 34.955}, + { ['x'] = 33.232, ['y'] = -1347.849, ['z'] = 29.497}, + { ['x'] = 129.216, ['y'] = -1292.347, ['z'] = 29.269}, + { ['x'] = 289.012, ['y'] = -1256.545, ['z'] = 29.440}, + { ['x'] = 1686.753, ['y'] = 4815.809, ['z'] = 42.008}, + { ['x'] = -302.408, ['y'] = -829.945, ['z'] = 32.417}, + { ['x'] = 5.134, ['y'] = -919.949, ['z'] = 29.557} +} \ No newline at end of file diff --git a/html/css/app.css b/html/css/app.css new file mode 100644 index 00000000..af32745a --- /dev/null +++ b/html/css/app.css @@ -0,0 +1,49 @@ +@font-face { + font-family: pcdown; + src: url('pdown.ttf'); +} +body { + font-family: roboto; +} +#cursor { + position: absolute; + z-index: 999999; + display: none; +} +#menu { + position: absolute; + top: 50%; + left: 50%; +} +#menu { + display : flex; + flex-direction: column; + width : 500px; + height : 150px; + margin-top : -75px; + margin-left: -250px; +} +#menu div { + display: flex; + flex-direction: row; +} +#deposit_btn { + width : 250px; + height: 50px; + font-size: 2em; +} +#deposit_amount { + width : 250px; + height : 50px; + font-size: 2em; +} +#withdraw_btn { + width : 250px; + height: 50px; + font-size: 2em; +} +#withdraw_amount { + width : 250px; + height : 50px; + font-size: 2em; +} \ No newline at end of file diff --git a/html/img/cursor.png b/html/img/cursor.png new file mode 100644 index 00000000..39536f95 Binary files /dev/null and b/html/img/cursor.png differ diff --git a/html/pdown.ttf b/html/pdown.ttf new file mode 100644 index 00000000..69c76cf3 Binary files /dev/null and b/html/pdown.ttf differ diff --git a/html/scripts/app.js b/html/scripts/app.js new file mode 100644 index 00000000..46261858 --- /dev/null +++ b/html/scripts/app.js @@ -0,0 +1,78 @@ +var documentWidth = document.documentElement.clientWidth; +var documentHeight = document.documentElement.clientHeight; + +var cursor = document.getElementById("cursor"); +var cursorX = documentWidth / 2; +var cursorY = documentHeight / 2; + +function UpdateCursorPos() { + cursor.style.left = cursorX; + cursor.style.top = cursorY; +} + +function Click(x, y) { + var element = $(document.elementFromPoint(x, y)); + element.focus().click(); +} + +$(document).mousemove(function(event) { + cursorX = event.pageX; + cursorY = event.pageY; + UpdateCursorPos(); +}); + +window.onload = function(e){ + // NUI Callback + window.addEventListener('message', function(event){ + let data = event.data; + if(data.showControls){ + $('#container').show(); + $('#menu' ).hide(); + $(cursor ).hide(); + } + if(data.showMenu){ + $('#container' ).show(); + $('#menu' ).show(); + $(cursor ).show(); + $('#deposit_amount').val(data.player.money) + let bankAmount = 0; + for(let i=0; i= 10000) + $('#withdraw_amount').val(10000) + else + $('#withdraw_amount').val(bankAmount) + } + + if(data.hideAll){ + $('#container').hide(); + $(cursor ).hide(); + } + if (data.click) { + // Avoid clicking the cursor itself, click 1px to the top/left; + Click(cursorX - 1, cursorY - 1); + } + + }) +} + +document.onkeyup = function (data) { + if (data.which == 27) { + $.post('http://esx_atm/escape', '{}'); + } +}; + +$('#container').hide() + +$('#deposit_btn').click(() => { + $.post('http://esx_atm/deposit', JSON.stringify({ + amount: $('#deposit_amount').val() + })); +}) + +$('#withdraw_btn').click(() => { + $.post('http://esx_atm/withdraw', JSON.stringify({ + amount: $('#withdraw_amount').val() + })); +}) \ No newline at end of file diff --git a/html/ui.html b/html/ui.html new file mode 100644 index 00000000..112567b7 --- /dev/null +++ b/html/ui.html @@ -0,0 +1,28 @@ + + + + + + + + +
+ +
+ + + + + + + \ No newline at end of file diff --git a/server/esx_atm_sv.lua b/server/esx_atm_sv.lua new file mode 100644 index 00000000..ca05e499 --- /dev/null +++ b/server/esx_atm_sv.lua @@ -0,0 +1,35 @@ +ESX = nil +TriggerEvent('esx:getSharedObject', function(obj) ESX = obj end) + +RegisterServerEvent('esx_atm:deposit') +AddEventHandler('esx_atm:deposit', function(amount) + local _source = source + local xPlayer = ESX.GetPlayerFromId(_source) + amount = tonumber(amount) + if amount == nil or amount <= 0 or amount > xPlayer.getMoney() then + TriggerClientEvent('esx:showNotification', _source, '~r~Montant invalide') + else + xPlayer.removeMoney(amount) + xPlayer.addAccountMoney('bank', amount) + TriggerClientEvent('esx:showNotification', _source, 'Vous avez déposé ~g~' .. amount .. '$~s~.') + TriggerClientEvent('esx_atm:closeATM', _source) + end +end) + + +RegisterServerEvent('esx_atm:withdraw') +AddEventHandler('esx_atm:withdraw', function(amount) + local _source = source + local xPlayer = ESX.GetPlayerFromId(_source) + amount = tonumber(amount) + local accountMoney = 0 + accountMoney = xPlayer.getAccount('bank').money + if amount == nil or amount <= 0 or amount > accountMoney then + TriggerClientEvent('esx:showNotification', _source, '~r~Montant invalide') + else + xPlayer.removeAccountMoney('bank', amount) + xPlayer.addMoney(amount) + TriggerClientEvent('esx:showNotification', _source, 'Vous avez retiré ~g~' .. amount .. '$~s~.') + TriggerClientEvent('esx_atm:closeATM', _source) + end +end) \ No newline at end of file