From 14fbc69357dc5cb1d1a2bb87a7ad9a6e5ce3f828 Mon Sep 17 00:00:00 2001 From: ElPumpo Date: Sat, 8 Feb 2020 12:36:18 +0100 Subject: [PATCH] Major improvements, see desc - Fixed selling same vehicle multiple times - Fixed selling vehicle - Major security improvements - Removed buying vehicle for society - Code cleanup - Fixed depopping vehicle not working (not respecting network owner) --- README.md | 18 +- client/main.lua | 417 ++++++++++++++++++----------------------------- client/utils.lua | 4 +- config.lua | 6 +- locales/br.lua | 5 +- locales/en.lua | 13 +- locales/fi.lua | 5 +- locales/fr.lua | 5 +- locales/pl.lua | 5 +- locales/sv.lua | 7 +- server/main.lua | 409 +++++++++++++++++++++------------------------- 11 files changed, 371 insertions(+), 523 deletions(-) diff --git a/README.md b/README.md index 5a7cf9a3..77e40f64 100644 --- a/README.md +++ b/README.md @@ -1,9 +1,11 @@ # esx_vehicleshop +ESX Vehicle Shop adds an vehicle shop to the game, where employeed players can sell vehicles to other players. You can also disable the job part so any player can buy vehicles with a menu based interaction. + ## Requirements * Auto mode (everyone can buy vehicles from the dealer) - * No need to download another resource + * No need to download other resources * Player management (the car dealer job): billing, boss actions and more! * [esx_society](https://github.com/ESX-Org/esx_society) @@ -15,21 +17,25 @@ ## Download & Installation ### Using [fvm](https://github.com/qlaffont/fvm-installer) + ``` fvm install --save --folder=esx esx-org/esx_vehicleshop ``` ### Using Git + ``` cd resources git clone https://github.com/ESX-Org/esx_vehicleshop [esx]/esx_vehicleshop ``` ### Manually + - Download https://github.com/ESX-Org/esx_vehicleshop/archive/master.zip - Put it in the `[esx]` directory -## Installation +### Installation + - Import `esx_vehicleshop.sql` in your database - Add this in your `server.cfg`: @@ -38,14 +44,16 @@ start esx_vehicleshop ``` - If you want player management you have to set `Config.EnablePlayerManagement` to `true` in `config.lua` -# Legal +## Legal + ### License + esx_vehicleshop - vehicle shop for ESX -Copyright (C) 2015-2018 Jérémie N'gadi +Copyright (C) 2015-2020 Jérémie N'gadi This program Is free software: you can redistribute it And/Or modify it under the terms Of the GNU General Public License As published by the Free Software Foundation, either version 3 Of the License, Or (at your option) any later version. This program Is distributed In the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty Of MERCHANTABILITY Or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License For more details. -You should have received a copy Of the GNU General Public License along with this program. If Not, see http://www.gnu.org/licenses/. \ No newline at end of file +You should have received a copy Of the GNU General Public License along with this program. If Not, see http://www.gnu.org/licenses/. diff --git a/client/main.lua b/client/main.lua index a6d2a2b8..e6de7966 100644 --- a/client/main.lua +++ b/client/main.lua @@ -6,7 +6,7 @@ local CurrentActionData = {} local IsInShopMenu = false local Categories = {} local Vehicles = {} -local LastVehicles = {} +local currentDisplayVehicle local CurrentVehicleData ESX = nil @@ -42,6 +42,16 @@ Citizen.CreateThread(function() end end) +function getVehicleLabelFromModel(model) + for k,v in ipairs(Vehicles) do + if v.model == model then + return v.name + end + end + + return +end + RegisterNetEvent('esx:playerLoaded') AddEventHandler('esx:playerLoaded', function(xPlayer) ESX.PlayerData = xPlayer @@ -71,26 +81,33 @@ AddEventHandler('esx_vehicleshop:sendVehicles', function(vehicles) Vehicles = vehicles end) -function DeleteShopInsideVehicles() - while #LastVehicles > 0 do - local vehicle = LastVehicles[1] +function DeleteDisplayVehicleInsideShop() + local attempt = 0 - ESX.Game.DeleteVehicle(vehicle) - table.remove(LastVehicles, 1) + if currentDisplayVehicle and DoesEntityExist(currentDisplayVehicle) then + while DoesEntityExist(currentDisplayVehicle) and not NetworkHasControlOfEntity(currentDisplayVehicle) and attempt < 100 do + Citizen.Wait(100) + NetworkRequestControlOfEntity(currentDisplayVehicle) + attempt = attempt + 1 + end + + if DoesEntityExist(currentDisplayVehicle) and NetworkHasControlOfEntity(currentDisplayVehicle) then + ESX.Game.DeleteVehicle(currentDisplayVehicle) + end end end function ReturnVehicleProvider() ESX.TriggerServerCallback('esx_vehicleshop:getCommercialVehicles', function(vehicles) local elements = {} - local returnPrice - for i=1, #vehicles, 1 do - returnPrice = ESX.Math.Round(vehicles[i].price * 0.75) + for k,v in ipairs(vehicles) do + local returnPrice = ESX.Math.Round(v.price * 0.75) + local vehicleLabel = getVehicleLabelFromModel(v.vehicle) table.insert(elements, { - label = ('%s [%s]'):format(vehicles[i].name, _U('generic_shopitem', ESX.Math.GroupDigits(returnPrice))), - value = vehicles[i].name + label = ('%s [%s]'):format(vehicleLabel, _U('generic_shopitem', ESX.Math.GroupDigits(returnPrice))), + value = v.vehicle }) end @@ -145,7 +162,7 @@ function OpenShopMenu() if IsModelInCdimage(GetHashKey(Vehicles[i].model)) then table.insert(vehiclesByCategory[Vehicles[i].category], Vehicles[i]) else - print(('esx_vehicleshop: vehicle "%s" does not exist'):format(Vehicles[i].model)) + print(('[esx_vehicleshop] [^3ERROR^7] Vehicle "%s" does not exist'):format(Vehicles[i].model)) end end @@ -190,147 +207,58 @@ function OpenShopMenu() }}, function(data2, menu2) if data2.current.value == 'yes' then if Config.EnablePlayerManagement then - ESX.TriggerServerCallback('esx_vehicleshop:buyVehicleSociety', function(hasEnoughMoney) - if hasEnoughMoney then + ESX.TriggerServerCallback('esx_vehicleshop:buyCarDealerVehicle', function(success) + if success then IsInShopMenu = false - - DeleteShopInsideVehicles() - - local playerPed = PlayerPedId() + DeleteDisplayVehicleInsideShop() CurrentAction = 'shop_menu' CurrentActionMsg = _U('shop_menu') CurrentActionData = {} + local playerPed = PlayerPedId() FreezeEntityPosition(playerPed, false) SetEntityVisible(playerPed, true) SetEntityCoords(playerPed, Config.Zones.ShopEntering.Pos) menu2.close() menu.close() - ESX.ShowNotification(_U('vehicle_purchased')) else ESX.ShowNotification(_U('broke_company')) end - end, 'cardealer', vehicleData.model) + end, vehicleData.model) else - local playerData = ESX.GetPlayerData() + local generatedPlate = GeneratePlate() - if Config.EnableSocietyOwnedVehicles and playerData.job.grade_name == 'boss' then - ESX.UI.Menu.Open('default', GetCurrentResourceName(), 'shop_confirm_buy_type', { - title = _U('purchase_type'), - align = 'top-left', - elements = { - {label = _U('staff_type'), value = 'personnal'}, - {label = _U('society_type'), value = 'society'} - }}, function(data3, menu3) + ESX.TriggerServerCallback('esx_vehicleshop:buyVehicle', function(success) + if success then + IsInShopMenu = false + menu2.close() + menu.close() + DeleteDisplayVehicleInsideShop() - if data3.current.value == 'personnal' then - - ESX.TriggerServerCallback('esx_vehicleshop:buyVehicle', function(hasEnoughMoney) - if hasEnoughMoney then - IsInShopMenu = false - - menu3.close() - menu2.close() - menu.close() - DeleteShopInsideVehicles() - - ESX.Game.SpawnVehicle(vehicleData.model, Config.Zones.ShopOutside.Pos, Config.Zones.ShopOutside.Heading, function(vehicle) - TaskWarpPedIntoVehicle(playerPed, vehicle, -1) - - local newPlate = GeneratePlate() - local vehicleProps = ESX.Game.GetVehicleProperties(vehicle) - vehicleProps.plate = newPlate - SetVehicleNumberPlateText(vehicle, newPlate) - - if Config.EnableOwnedVehicles then - TriggerServerEvent('esx_vehicleshop:setVehicleOwned', vehicleProps) - end - - ESX.ShowNotification(_U('vehicle_purchased')) - end) - - FreezeEntityPosition(playerPed, false) - SetEntityVisible(playerPed, true) - else - ESX.ShowNotification(_U('not_enough_money')) - end - end, vehicleData.model) - - elseif data3.current.value == 'society' then - - ESX.TriggerServerCallback('esx_vehicleshop:buyVehicleSociety', function(hasEnoughMoney) - if hasEnoughMoney then - IsInShopMenu = false - - menu3.close() - menu2.close() - menu.close() - - DeleteShopInsideVehicles() - - ESX.Game.SpawnVehicle(vehicleData.model, Config.Zones.ShopOutside.Pos, Config.Zones.ShopOutside.Heading, function(vehicle) - TaskWarpPedIntoVehicle(playerPed, vehicle, -1) - - local newPlate = GeneratePlate() - local vehicleProps = ESX.Game.GetVehicleProperties(vehicle) - vehicleProps.plate = newPlate - SetVehicleNumberPlateText(vehicle, newPlate) - TriggerServerEvent('esx_vehicleshop:setVehicleOwnedSociety', playerData.job.name, vehicleProps) - ESX.ShowNotification(_U('vehicle_purchased')) - end) - - FreezeEntityPosition(playerPed, false) - SetEntityVisible(playerPed, true) - else - ESX.ShowNotification(_U('broke_company')) - end - end, playerData.job.name, vehicleData.model) - - end - end, function(data3, menu3) - menu3.close() - end) - else - ESX.TriggerServerCallback('esx_vehicleshop:buyVehicle', function(hasEnoughMoney) - if hasEnoughMoney then - IsInShopMenu = false - menu2.close() - menu.close() - DeleteShopInsideVehicles() - - ESX.Game.SpawnVehicle(vehicleData.model, Config.Zones.ShopOutside.Pos, Config.Zones.ShopOutside.Heading, function(vehicle) - TaskWarpPedIntoVehicle(playerPed, vehicle, -1) - - local newPlate = GeneratePlate() - local vehicleProps = ESX.Game.GetVehicleProperties(vehicle) - vehicleProps.plate = newPlate - SetVehicleNumberPlateText(vehicle, newPlate) - - if Config.EnableOwnedVehicles then - TriggerServerEvent('esx_vehicleshop:setVehicleOwned', vehicleProps) - end - - ESX.ShowNotification(_U('vehicle_purchased')) - end) + ESX.Game.SpawnVehicle(vehicleData.model, Config.Zones.ShopOutside.Pos, Config.Zones.ShopOutside.Heading, function(vehicle) + TaskWarpPedIntoVehicle(playerPed, vehicle, -1) + SetVehicleNumberPlateText(vehicle, generatedPlate) FreezeEntityPosition(playerPed, false) SetEntityVisible(playerPed, true) - else - ESX.ShowNotification(_U('not_enough_money')) - end - end, vehicleData.model) - end + end) + else + ESX.ShowNotification(_U('not_enough_money')) + end + end, vehicleData.model, generatedPlate) end + else + menu2.close() end end, function(data2, menu2) menu2.close() end) end, function(data, menu) menu.close() - DeleteShopInsideVehicles() + DeleteDisplayVehicleInsideShop() local playerPed = PlayerPedId() CurrentAction = 'shop_menu' @@ -346,22 +274,22 @@ function OpenShopMenu() local vehicleData = vehiclesByCategory[data.current.name][data.current.value + 1] local playerPed = PlayerPedId() - DeleteShopInsideVehicles() + DeleteDisplayVehicleInsideShop() WaitForVehicleToLoad(vehicleData.model) ESX.Game.SpawnLocalVehicle(vehicleData.model, Config.Zones.ShopInside.Pos, Config.Zones.ShopInside.Heading, function(vehicle) - table.insert(LastVehicles, vehicle) + currentDisplayVehicle = vehicle TaskWarpPedIntoVehicle(playerPed, vehicle, -1) FreezeEntityPosition(vehicle, true) SetModelAsNoLongerNeeded(vehicleData.model) end) end) - DeleteShopInsideVehicles() + DeleteDisplayVehicleInsideShop() WaitForVehicleToLoad(firstVehicleData.model) ESX.Game.SpawnLocalVehicle(firstVehicleData.model, Config.Zones.ShopInside.Pos, Config.Zones.ShopInside.Heading, function(vehicle) - table.insert(LastVehicles, vehicle) + currentDisplayVehicle = vehicle TaskWarpPedIntoVehicle(playerPed, vehicle, -1) FreezeEntityPosition(vehicle, true) SetModelAsNoLongerNeeded(firstVehicleData.model) @@ -374,16 +302,16 @@ function WaitForVehicleToLoad(modelHash) if not HasModelLoaded(modelHash) then RequestModel(modelHash) - BeginTextCommandBusyString('STRING') + BeginTextCommandBusyspinnerOn('STRING') AddTextComponentSubstringPlayerName(_U('shop_awaiting_model')) - EndTextCommandBusyString(4) + EndTextCommandBusyspinnerOn(4) while not HasModelLoaded(modelHash) do Citizen.Wait(0) DisableAllControlActions(0) end - RemoveLoadingPrompt() + BusyspinnerOff() end end @@ -402,7 +330,6 @@ function OpenResellerMenu() {label = _U('get_rented_vehicles'), value = 'get_rented_vehicles'}, {label = _U('set_vehicle_owner_sell'), value = 'set_vehicle_owner_sell'}, {label = _U('set_vehicle_owner_rent'), value = 'set_vehicle_owner_rent'}, - {label = _U('set_vehicle_owner_sell_society'), value = 'set_vehicle_owner_sell_society'}, {label = _U('deposit_stock'), value = 'put_stock'}, {label = _U('take_stock'), value = 'get_stock'} }}, function(data, menu) @@ -417,125 +344,94 @@ function OpenResellerMenu() elseif action == 'pop_vehicle' then OpenPopVehicleMenu() elseif action == 'depop_vehicle' then - DeleteShopInsideVehicles() + if currentDisplayVehicle then + DeleteDisplayVehicleInsideShop() + else + ESX.ShowNotification(_U('no_current_vehicle')) + end elseif action == 'return_provider' then ReturnVehicleProvider() elseif action == 'create_bill' then - local closestPlayer, closestDistance = ESX.Game.GetClosestPlayer() - if closestPlayer == -1 or closestDistance > 3.0 then - ESX.ShowNotification(_U('no_players')) - return - end - ESX.UI.Menu.Open('dialog', GetCurrentResourceName(), 'set_vehicle_owner_sell_amount', { - title = _U('invoice_amount') - }, function(data2, menu2) - local amount = tonumber(data2.value) + if closestPlayer ~= -1 and closestDistance < 3 then + ESX.UI.Menu.Open('dialog', GetCurrentResourceName(), 'set_vehicle_owner_sell_amount', { + title = _U('invoice_amount') + }, function(data2, menu2) + local amount = tonumber(data2.value) - if amount == nil then - ESX.ShowNotification(_U('invalid_amount')) - else - menu2.close() - local closestPlayer, closestDistance = ESX.Game.GetClosestPlayer() - - if closestPlayer == -1 or closestDistance > 3.0 then - ESX.ShowNotification(_U('no_players')) + if amount == nil then + ESX.ShowNotification(_U('invalid_amount')) else - TriggerServerEvent('esx_billing:sendBill', GetPlayerServerId(closestPlayer), 'society_cardealer', _U('car_dealer'), tonumber(data2.value)) - end - end - end, function(data2, menu2) - menu2.close() - end) + menu2.close() + local closestPlayer, closestDistance = ESX.Game.GetClosestPlayer() + if closestPlayer == -1 or closestDistance > 3.0 then + ESX.ShowNotification(_U('no_players')) + else + TriggerServerEvent('esx_billing:sendBill', GetPlayerServerId(closestPlayer), 'society_cardealer', _U('car_dealer'), tonumber(data2.value)) + end + end + end, function(data2, menu2) + menu2.close() + end) + else + ESX.ShowNotification(_U('no_players')) + end elseif action == 'get_rented_vehicles' then OpenRentedVehiclesMenu() elseif action == 'set_vehicle_owner_sell' then + if currentDisplayVehicle then + local closestPlayer, closestDistance = ESX.Game.GetClosestPlayer() - local closestPlayer, closestDistance = ESX.Game.GetClosestPlayer() - - if closestPlayer == -1 or closestDistance > 3.0 then - ESX.ShowNotification(_U('no_players')) - else - local newPlate = GeneratePlate() - local vehicleProps = ESX.Game.GetVehicleProperties(LastVehicles[#LastVehicles]) - local model = CurrentVehicleData.model - vehicleProps.plate = newPlate - SetVehicleNumberPlateText(LastVehicles[#LastVehicles], newPlate) - - TriggerServerEvent('esx_vehicleshop:sellVehicle', model) - TriggerServerEvent('esx_vehicleshop:addToList', GetPlayerServerId(closestPlayer), model, newPlate) - - if Config.EnableOwnedVehicles then - TriggerServerEvent('esx_vehicleshop:setVehicleOwnedPlayerId', GetPlayerServerId(closestPlayer), vehicleProps) - ESX.ShowNotification(_U('vehicle_set_owned', vehicleProps.plate, GetPlayerName(closestPlayer))) - else - ESX.ShowNotification(_U('vehicle_sold_to', vehicleProps.plate, GetPlayerName(closestPlayer))) - end - end - - elseif action == 'set_vehicle_owner_sell_society' then - - local closestPlayer, closestDistance = ESX.Game.GetClosestPlayer() - - if closestPlayer == -1 or closestDistance > 3.0 then - ESX.ShowNotification(_U('no_players')) - else - ESX.TriggerServerCallback('esx:getOtherPlayerData', function(xPlayer) - - local newPlate = GeneratePlate() - local vehicleProps = ESX.Game.GetVehicleProperties(LastVehicles[#LastVehicles]) - local model = CurrentVehicleData.model + if closestPlayer ~= -1 and closestDistance < 3 then + local newPlate = GeneratePlate() + local vehicleProps = ESX.Game.GetVehicleProperties(currentDisplayVehicle) vehicleProps.plate = newPlate - SetVehicleNumberPlateText(LastVehicles[#LastVehicles], newPlate) - TriggerServerEvent('esx_vehicleshop:sellVehicle', model) - TriggerServerEvent('esx_vehicleshop:addToList', GetPlayerServerId(closestPlayer), model, newPlate) - - if Config.EnableSocietyOwnedVehicles then - TriggerServerEvent('esx_vehicleshop:setVehicleOwnedSociety', xPlayer.job.name, vehicleProps) - ESX.ShowNotification(_U('vehicle_set_owned', vehicleProps.plate, GetPlayerName(closestPlayer))) - else - ESX.ShowNotification(_U('vehicle_sold_to', vehicleProps.plate, GetPlayerName(closestPlayer))) - end - - end, GetPlayerServerId(closestPlayer)) - end - - elseif action == 'set_vehicle_owner_rent' then - - ESX.UI.Menu.Open('dialog', GetCurrentResourceName(), 'set_vehicle_owner_rent_amount', { - title = _U('rental_amount') - }, function(data2, menu2) - local amount = tonumber(data2.value) - - if amount == nil then - ESX.ShowNotification(_U('invalid_amount')) + SetVehicleNumberPlateText(currentDisplayVehicle, newPlate) + TriggerServerEvent('esx_vehicleshop:setVehicleOwnedPlayerId', GetPlayerServerId(closestPlayer), vehicleProps, CurrentVehicleData.model, CurrentVehicleData.name) + currentDisplayVehicle = nil else - menu2.close() - - local closestPlayer, closestDistance = ESX.Game.GetClosestPlayer() - - if closestPlayer == -1 or closestDistance > 5.0 then - ESX.ShowNotification(_U('no_players')) - else - local newPlate = 'RENT' .. string.upper(ESX.GetRandomString(4)) - local vehicleProps = ESX.Game.GetVehicleProperties(LastVehicles[#LastVehicles]) - local model = CurrentVehicleData.model - vehicleProps.plate = newPlate - SetVehicleNumberPlateText(LastVehicles[#LastVehicles], newPlate) - TriggerServerEvent('esx_vehicleshop:rentVehicle', model, vehicleProps.plate, GetPlayerName(closestPlayer), CurrentVehicleData.price, amount, GetPlayerServerId(closestPlayer)) - - if Config.EnableOwnedVehicles then - TriggerServerEvent('esx_vehicleshop:setVehicleOwnedPlayerId', GetPlayerServerId(closestPlayer), vehicleProps) - end - - ESX.ShowNotification(_U('vehicle_set_rented', vehicleProps.plate, GetPlayerName(closestPlayer))) - end + ESX.ShowNotification(_U('no_players')) end - end, function(data2, menu2) - menu2.close() - end) + else + ESX.ShowNotification(_U('no_current_vehicle')) + end + elseif action == 'set_vehicle_owner_rent' then + if currentDisplayVehicle then + local closestPlayer, closestDistance = ESX.Game.GetClosestPlayer() + + if closestPlayer ~= -1 and closestDistance < 3 then + ESX.UI.Menu.Open('dialog', GetCurrentResourceName(), 'set_vehicle_owner_rent_amount', { + title = _U('rental_amount') + }, function(data2, menu2) + local amount = tonumber(data2.value) + + if not amount then + ESX.ShowNotification(_U('invalid_amount')) + else + menu2.close() + local closestPlayer, closestDistance = ESX.Game.GetClosestPlayer() + + if closestPlayer ~= -1 and closestDistance < 3 then + local newPlate = 'RENT' .. string.upper(ESX.GetRandomString(4)) + local model = CurrentVehicleData.model + SetVehicleNumberPlateText(currentDisplayVehicle, newPlate) + TriggerServerEvent('esx_vehicleshop:rentVehicle', model, newPlate, amount, GetPlayerServerId(closestPlayer)) + currentDisplayVehicle = nil + else + ESX.ShowNotification(_U('no_players')) + end + end + end, function(data2, menu2) + menu2.close() + end) + else + ESX.ShowNotification(_U('no_players')) + end + else + ESX.ShowNotification(_U('no_current_vehicle')) + end end end, function(data, menu) menu.close() @@ -550,10 +446,12 @@ function OpenPopVehicleMenu() ESX.TriggerServerCallback('esx_vehicleshop:getCommercialVehicles', function(vehicles) local elements = {} - for i=1, #vehicles, 1 do + for k,v in ipairs(vehicles) do + local vehicleLabel = getVehicleLabelFromModel(v.vehicle) + table.insert(elements, { - label = ('%s [MSRP %s]'):format(vehicles[i].name, _U('generic_shopitem', ESX.Math.GroupDigits(vehicles[i].price))), - value = vehicles[i].name + label = ('%s [MSRP %s]'):format(vehicleLabel, _U('generic_shopitem', ESX.Math.GroupDigits(v.price))), + value = v.vehicle }) end @@ -563,11 +461,10 @@ function OpenPopVehicleMenu() elements = elements }, function(data, menu) local model = data.current.value - - DeleteShopInsideVehicles() + DeleteDisplayVehicleInsideShop() ESX.Game.SpawnVehicle(model, Config.Zones.ShopInside.Pos, Config.Zones.ShopInside.Heading, function(vehicle) - table.insert(LastVehicles, vehicle) + currentDisplayVehicle = vehicle for i=1, #Vehicles, 1 do if model == Vehicles[i].model then @@ -586,10 +483,12 @@ function OpenRentedVehiclesMenu() ESX.TriggerServerCallback('esx_vehicleshop:getRentedVehicles', function(vehicles) local elements = {} - for i=1, #vehicles, 1 do + for k,v in ipairs(vehicles) do + local vehicleLabel = getVehicleLabelFromModel(v.name) + table.insert(elements, { - label = ('%s: %s - %s'):format(vehicles[i].playerName, vehicles[i].name, vehicles[i].plate), - value = vehicles[i].name + label = ('%s: %s - %s'):format(v.playerName, vehicleLabel, v.plate), + value = v.name }) end @@ -660,10 +559,12 @@ function OpenGetStocksMenu() local elements = {} for i=1, #items, 1 do - table.insert(elements, { - label = 'x' .. items[i].count .. ' ' .. items[i].label, - value = items[i].name - }) + if items[i].count > 0 then + table.insert(elements, { + label = 'x' .. items[i].count .. ' ' .. items[i].label, + value = items[i].name + }) + end end ESX.UI.Menu.Open('default', GetCurrentResourceName(), 'stocks_menu', { @@ -774,7 +675,6 @@ AddEventHandler('esx_vehicleshop:hasEnteredMarker', function(zone) end elseif zone == 'GiveBackVehicle' and Config.EnablePlayerManagement then - local playerPed = PlayerPedId() if IsPedInAnyVehicle(playerPed, false) then @@ -784,14 +684,11 @@ AddEventHandler('esx_vehicleshop:hasEnteredMarker', function(zone) CurrentActionMsg = _U('vehicle_menu') CurrentActionData = {vehicle = vehicle} end - elseif zone == 'ResellVehicle' then - local playerPed = PlayerPedId() if IsPedSittingInAnyVehicle(playerPed) then - - local vehicle = GetVehiclePedIsIn(playerPed, false) + local vehicle = GetVehiclePedIsIn(playerPed, false) local vehicleData, model, resellPrice, plate if GetPedInVehicleSeat(vehicle, -1) == playerPed then @@ -817,15 +714,12 @@ AddEventHandler('esx_vehicleshop:hasEnteredMarker', function(zone) plate = plate } end - end elseif zone == 'BossActions' and Config.EnablePlayerManagement and ESX.PlayerData.job ~= nil and ESX.PlayerData.job.name == 'cardealer' and ESX.PlayerData.job.grade_name == 'boss' then - CurrentAction = 'boss_actions_menu' CurrentActionMsg = _U('shop_menu') CurrentActionData = {} - end end) @@ -842,13 +736,14 @@ AddEventHandler('onResourceStop', function(resource) if IsInShopMenu then ESX.UI.Menu.CloseAll() - DeleteShopInsideVehicles() local playerPed = PlayerPedId() FreezeEntityPosition(playerPed, false) SetEntityVisible(playerPed, true) SetEntityCoords(playerPed, Config.Zones.ShopEntering.Pos) end + + DeleteDisplayVehicleInsideShop() end end) @@ -874,8 +769,8 @@ Citizen.CreateThread(function() SetBlipScale (blip, 1.0) SetBlipAsShortRange(blip, true) - BeginTextCommandSetBlipName("STRING") - AddTextComponentString(_U('car_dealer')) + BeginTextCommandSetBlipName('STRING') + AddTextComponentSubstringPlayerName(_U('car_dealer')) EndTextCommandSetBlipName(blip) end) @@ -979,4 +874,4 @@ Citizen.CreateThread(function() LoadInterior(interiorID) EnableInteriorProp(interiorID, 'csr_beforeMission') -- Load large window RefreshInterior(interiorID) -end) \ No newline at end of file +end) diff --git a/client/utils.lua b/client/utils.lua index 26e586bb..88a30d50 100644 --- a/client/utils.lua +++ b/client/utils.lua @@ -19,7 +19,7 @@ function GeneratePlate() generatedPlate = string.upper(GetRandomLetter(Config.PlateLetters) .. GetRandomNumber(Config.PlateNumbers)) end - ESX.TriggerServerCallback('esx_vehicleshop:isPlateTaken', function (isPlateTaken) + ESX.TriggerServerCallback('esx_vehicleshop:isPlateTaken', function(isPlateTaken) if not isPlateTaken then doBreak = true end @@ -66,4 +66,4 @@ function GetRandomLetter(length) else return '' end -end \ No newline at end of file +end diff --git a/config.lua b/config.lua index 0c87297e..61b2c2ff 100644 --- a/config.lua +++ b/config.lua @@ -1,9 +1,7 @@ Config = {} -Config.DrawDistance = 100.0 -Config.MarkerColor = { r = 120, g = 120, b = 240 } +Config.DrawDistance = 100 +Config.MarkerColor = {r = 120, g = 120, b = 240} Config.EnablePlayerManagement = false -- enables the actual car dealer job. You'll need esx_addonaccount, esx_billing and esx_society -Config.EnableOwnedVehicles = true -Config.EnableSocietyOwnedVehicles = false -- use with EnablePlayerManagement disabled, or else it wont have any effects Config.ResellPercentage = 50 Config.Locale = 'fr' diff --git a/locales/br.lua b/locales/br.lua index c70a5d4d..442ea74c 100644 --- a/locales/br.lua +++ b/locales/br.lua @@ -5,9 +5,6 @@ Locales['br'] = { ['vehicle_belongs'] = 'um veículo com placa ~y~%s~s~ agora pertence a ~b~you~s~', ['broke_company'] = 'você não tem dinheiro suficiente na conta da empresa', ['license_missing'] = 'você não tem carteira de motorista!', - ['purchase_type'] = 'tipo de compra', - ['society_type'] = 'sociedade', - ['staff_type'] = 'uso pessoal', ['buy_vehicle_shop'] = 'comprar %s por $%s?', ['buy_vehicle'] = 'comprar veículo', ['car_dealer'] = 'Concessionária de carros', @@ -18,6 +15,7 @@ Locales['br'] = { ['depop_vehicle'] = 'volte ao veiculo', ['return_provider'] = 'devolver veículo ao fornecedor', ['get_rented_vehicles'] = 'veículos para alugar', + ['no_current_vehicle'] = 'you do not currently have an vehicle displayed', ['invalid_amount'] = 'Montante inválido', ['invoice_amount'] = 'valor da fatura', ['no'] = 'não', @@ -34,7 +32,6 @@ Locales['br'] = { ['sell_menu'] = 'Pressione ~INPUT_CONTEXT~ para vender ', ['set_vehicle_owner_rent'] = 'Atribuir veículo [Alugar]', ['set_vehicle_owner_sell'] = 'Veículos para [Venda]', - ['set_vehicle_owner_sell_society'] = 'atribuir veículo [Sale] [Society]', ['shop_menu'] = 'pressione ~INPUT_CONTEXT~ para acessar o menu', ['generic_shopitem'] = '$%s', ['vehicle_dealer'] = 'Veículo - Concessionária', diff --git a/locales/en.lua b/locales/en.lua index 69197a9c..40c7a1d2 100644 --- a/locales/en.lua +++ b/locales/en.lua @@ -5,9 +5,6 @@ Locales['en'] = { ['vehicle_belongs'] = 'an vehicle with plate ~y~%s~s~ now belongs to ~b~you~s~', ['broke_company'] = 'you do not have enough money in the company account', ['license_missing'] = 'you don\'t have a driver\'s license!', - ['purchase_type'] = 'type of purchase', - ['society_type'] = 'society', - ['staff_type'] = 'personal usage', ['buy_vehicle_shop'] = 'do you want to purchase %s for $%s?', ['buy_vehicle'] = 'buy vehicle', ['car_dealer'] = 'car Dealership', @@ -15,14 +12,15 @@ Locales['en'] = { ['create_bill'] = 'create bill', ['dealer_boss'] = 'car Dealer - Boss', ['delivered'] = 'the vehicle has been ~g~delivered~s~ to the dealer', - ['depop_vehicle'] = 'return vehicle', + ['depop_vehicle'] = 'return vehicle to garage', ['return_provider'] = 'return vehicle to provider', ['get_rented_vehicles'] = 'vehicles for rent', + ['no_current_vehicle'] = 'you do not currently have an vehicle displayed', ['invalid_amount'] = 'invalid amount', ['invoice_amount'] = 'invoice amount', ['no'] = 'no', ['yes'] = 'yes', - ['no_players'] = 'no players nearby', + ['no_players'] = 'there is no players near you', ['not_enough_money'] = 'you do not have enough money', ['not_rental'] = 'this is not a ~r~rental vehicle~s~', ['not_yours'] = 'this vehicle does not belong to you', @@ -32,14 +30,13 @@ Locales['en'] = { ['return_provider_menu'] = 'car Dealer - Return vehicle to provider', ['rental_amount'] = 'rental amount', ['sell_menu'] = 'press ~INPUT_CONTEXT~ to sell your ~y~%s~s~ for ~g~$%s~s~', - ['set_vehicle_owner_rent'] = 'assign vehicle [Location]', + ['set_vehicle_owner_rent'] = 'rent vehicle', ['set_vehicle_owner_sell'] = 'sell vehicle', - ['set_vehicle_owner_sell_society'] = 'assign Vehicle [Sale] [Society]', ['shop_menu'] = 'press ~INPUT_CONTEXT~ to access the menu', ['generic_shopitem'] = '$%s', ['vehicle_dealer'] = 'vehicle - Car Dealer', ['vehicle_menu'] = 'press ~INPUT_CONTEXT~ to give back the rented vehicle', - ['vehicle_purchased'] = 'you bought a vehicle', + ['vehicle_purchased'] = 'you bought an vehicle', ['vehicle_set_owned'] = 'vehicle ~y~%s~s~ has been assigned to ~b~%s~s~', ['vehicle_set_rented'] = 'vehicle ~y~%s~s~ has been rented to ~b~%s~s~', ['vehicle_sold_for'] = 'the ~b~%s~s~ has been ~y~sold~s~ for ~g~$%s~s~', diff --git a/locales/fi.lua b/locales/fi.lua index 3eff6100..03f2804a 100644 --- a/locales/fi.lua +++ b/locales/fi.lua @@ -5,9 +5,6 @@ Locales['fi'] = { ['vehicle_belongs'] = 'ajoneuvo kilvellä ~y~%s~s~ on nyt ~b~sinun~s~ omistuksessasi', ['broke_company'] = 'sinulla ei ole tarpeeksi rahaa yrityksen tilillä', ['license_missing'] = 'you don\'t have a driver\'s license!', - ['purchase_type'] = 'osto tyyppi', - ['society_type'] = 'firma', - ['staff_type'] = 'henkilökunta', ['buy_vehicle_shop'] = 'haluatko ostaa ajoneuvon %s hintaan $%s?', ['buy_vehicle'] = 'osta ajoneuvo', ['car_dealer'] = 'autokauppa', @@ -18,6 +15,7 @@ Locales['fi'] = { ['depop_vehicle'] = 'palauta ajoneuvo', ['return_provider'] = 'return vehicle to provider', ['get_rented_vehicles'] = 'vuokrattavat ajoneuvot', + ['no_current_vehicle'] = 'you do not currently have an vehicle displayed', ['invalid_amount'] = 'virheellinen summa', ['invoice_amount'] = 'laskun summa', ['no'] = 'ei', @@ -34,7 +32,6 @@ Locales['fi'] = { ['sell_menu'] = 'paina ~INPUT_CONTEXT~ myydäksesi ~y~%s~s~ hintaan: ~g~$%s~s~', ['set_vehicle_owner_rent'] = 'määritä ajoneuvon [Vuokra]', ['set_vehicle_owner_sell'] = 'myy ajoneuvo', - ['set_vehicle_owner_sell_society'] = 'määritä ajoneuvon [Hinta] [Firma]', ['shop_menu'] = 'paina ~INPUT_CONTEXT~ avataksesi menu', ['generic_shopitem'] = '$%s', ['vehicle_dealer'] = 'ajonevuo - Autokauppa', diff --git a/locales/fr.lua b/locales/fr.lua index 4c53116f..9a2a8ea4 100644 --- a/locales/fr.lua +++ b/locales/fr.lua @@ -5,9 +5,6 @@ Locales['fr'] = { ['vehicle_belongs'] = 'le véhicule avec la plaque ~y~%s~s~ est désormais à ~b~vous~s~', ['broke_company'] = 'vous n\avez pas assez d\'argent sur le compte de la societé', ['license_missing'] = 'you don\'t have a driver\'s license!', - ['purchase_type'] = 'type d\'achat', - ['society_type'] = 'societé', - ['staff_type'] = 'personnel', ['buy_vehicle_shop'] = 'acheter %s pour $%s?', ['buy_vehicle'] = 'acheter véhicule', ['car_dealer'] = 'concessionnaire', @@ -18,6 +15,7 @@ Locales['fr'] = { ['depop_vehicle'] = 'rentrer véhicule', ['return_provider'] = 'rendre le véhicule', ['get_rented_vehicles'] = 'véhicules en location', + ['no_current_vehicle'] = 'you do not currently have an vehicle displayed', ['invalid_amount'] = 'montant invalide', ['invoice_amount'] = 'montant de la facture', ['no'] = 'non', @@ -34,7 +32,6 @@ Locales['fr'] = { ['sell_menu'] = 'appuyez sur ~INPUT_CONTEXT~ pour vendre ~y~%s~s~ au prix de ~g~$%s~s~', ['set_vehicle_owner_rent'] = 'attribuer véhicule [Location]', ['set_vehicle_owner_sell'] = 'attribuer véhicule [Vente]', - ['set_vehicle_owner_sell_society'] = 'attribuer véhicule [Vente] [Société]', ['shop_menu'] = 'appuyez sur ~INPUT_CONTEXT~ pour accéder au menu', ['generic_shopitem'] = '$%s', ['vehicle_dealer'] = 'concessionnaire - Véhicules', diff --git a/locales/pl.lua b/locales/pl.lua index c0b19aa7..d2eef57a 100644 --- a/locales/pl.lua +++ b/locales/pl.lua @@ -5,9 +5,6 @@ Locales['pl'] = { ['vehicle_belongs'] = 'pojazd z rejestracją ~y~%s~s~ teraz należy do ~b~ciebie~s~', ['broke_company'] = 'twoja firma nie ma wystarczająco pieniedzy', ['license_missing'] = 'you don\'t have a driver\'s license!', - ['purchase_type'] = 'rodzaj zakupu', - ['society_type'] = 'firma', - ['staff_type'] = 'pracownicy', ['buy_vehicle_shop'] = 'czy chcesz kupić %s za $%s?', ['buy_vehicle'] = 'kup pojazd', ['car_dealer'] = 'sprzedawca Aut', @@ -18,6 +15,7 @@ Locales['pl'] = { ['depop_vehicle'] = 'oddaj pojazd', ['return_provider'] = 'return vehicle to provider', ['get_rented_vehicles'] = 'pojazdy do wynajęcia', + ['no_current_vehicle'] = 'you do not currently have an vehicle displayed', ['invalid_amount'] = 'nieprawidłowa ilość', ['invoice_amount'] = 'suma faktury', ['no'] = 'nie', @@ -34,7 +32,6 @@ Locales['pl'] = { ['sell_menu'] = 'wcisnij ~INPUT_CONTEXT~ aby sprzedać ~y~%s~s~ za ~g~$%s~s~', ['set_vehicle_owner_rent'] = 'zarejestruj pojazd [Wynajem]', ['set_vehicle_owner_sell'] = 'zarejestruj pojazd [Kupno]', - ['set_vehicle_owner_sell_society'] = 'zarejestruj pojazd [Firmowe]', ['shop_menu'] = 'wcisnij ~INPUT_CONTEXT~ aby wejść do menu', ['generic_shopitem'] = '$%s', ['vehicle_dealer'] = 'pojazdy - Sprzedawca aut', diff --git a/locales/sv.lua b/locales/sv.lua index 15618054..0ab74f45 100644 --- a/locales/sv.lua +++ b/locales/sv.lua @@ -1,13 +1,10 @@ Locales['sv'] = { -- global menus - ['not_enough_in_society'] = 'det finns inte tillräckligt många ~r~ det föremålet~s~ i förrådet!', + ['not_enough_in_society'] = 'det finns inte tillräckligt många av ~r~det föremålet~s~ i förrådet!', ['player_cannot_hold'] = 'du har ~r~inte~s~ tillräckligt mycket~y~plats~s~ på dig!', ['vehicle_belongs'] = 'fordonet med reg numret ~y~%s~s~ tillhör nu ~b~dig~s~', ['broke_company'] = 'det finns inte tillräckligt mycket pengar i företagskontot', ['license_missing'] = 'du är inte behörig att köpa bilar, B-körkort krävs!', - ['purchase_type'] = 'till vem är fordonet?', - ['society_type'] = 'företag', - ['staff_type'] = 'personlig användning', ['buy_vehicle_shop'] = 'vill du köpa in %s för %s SEK?', ['buy_vehicle'] = 'Köp in fordon', ['car_dealer'] = 'bilförsäljare', @@ -18,6 +15,7 @@ Locales['sv'] = { ['depop_vehicle'] = 'ställ tillbaka fordonet', ['return_provider'] = 'sälj tillbaka fordon till leverantör', ['get_rented_vehicles'] = 'uthyrda fordon', + ['no_current_vehicle'] = 'du har inget fordon ute till salu', ['invalid_amount'] = 'ogiltigt belopp', ['invoice_amount'] = 'belopp att betala', ['no'] = 'nej', @@ -34,7 +32,6 @@ Locales['sv'] = { ['sell_menu'] = 'tryck ~INPUT_CONTEXT~ för att sälja ~y~%s~s~ för ~g~%s SEK~s~', ['set_vehicle_owner_rent'] = 'hyr ut fordon', ['set_vehicle_owner_sell'] = 'sälj fordon', - ['set_vehicle_owner_sell_society'] = 'sälj fordon till företag', ['shop_menu'] = 'tryck ~INPUT_CONTEXT~ för öppna ~y~bilförsäljarsmenyn~s~.', ['generic_shopitem'] = '%s SEK', ['vehicle_dealer'] = 'bilförsäljare - fordon för visning', diff --git a/server/main.lua b/server/main.lua index 00108026..030141a5 100644 --- a/server/main.lua +++ b/server/main.lua @@ -1,5 +1,5 @@ ESX = nil -local Categories, Vehicles = {}, {} +local categories, vehicles = {}, {} TriggerEvent('esx:getSharedObject', function(obj) ESX = obj end) @@ -12,7 +12,7 @@ Citizen.CreateThread(function() if Config.PlateUseSpace then char = char + 1 end if char > 8 then - print(('esx_vehicleshop: ^1WARNING^7 plate character count reached, %s/8 characters.'):format(char)) + print(('[esx_vehicleshop] [^3WARNING^7] Plate character count reached, %s/8 characters!'):format(char)) end end) @@ -23,132 +23,117 @@ function RemoveOwnedVehicle(plate) end MySQL.ready(function() - Categories = MySQL.Sync.fetchAll('SELECT * FROM vehicle_categories') - local vehicles = MySQL.Sync.fetchAll('SELECT * FROM vehicles') + MySQL.Async.fetchAll('SELECT * FROM vehicle_categories', {}, function(_categories) + categories = _categories - for i=1, #vehicles, 1 do - local vehicle = vehicles[i] + MySQL.Async.fetchAll('SELECT * FROM vehicles', {}, function(_vehicles) + vehicles = _vehicles - for j=1, #Categories, 1 do - if Categories[j].name == vehicle.category then - vehicle.categoryLabel = Categories[j].label - break + for k,v in ipairs(vehicles) do + for k2,v2 in ipairs(categories) do + if v2.name == v.category then + vehicles[k].categoryLabel = v2.label + break + end + end end - end - table.insert(Vehicles, vehicle) + -- send information after db has loaded, making sure everyone gets vehicle information + TriggerClientEvent('esx_vehicleshop:sendCategories', -1, categories) + TriggerClientEvent('esx_vehicleshop:sendVehicles', -1, vehicles) + end) + end) +end) + +function getVehicleLabelFromModel(model) + for k,v in ipairs(vehicles) do + if v.model == model then + return v.name + end end - -- send information after db has loaded, making sure everyone gets vehicle information - TriggerClientEvent('esx_vehicleshop:sendCategories', -1, Categories) - TriggerClientEvent('esx_vehicleshop:sendVehicles', -1, Vehicles) -end) + return +end -RegisterServerEvent('esx_vehicleshop:setVehicleOwned') -AddEventHandler('esx_vehicleshop:setVehicleOwned', function(vehicleProps) - local _source = source - local xPlayer = ESX.GetPlayerFromId(_source) +RegisterNetEvent('esx_vehicleshop:setVehicleOwnedPlayerId') +AddEventHandler('esx_vehicleshop:setVehicleOwnedPlayerId', function(playerId, vehicleProps, model, label) + local xPlayer, xTarget = ESX.GetPlayerFromId(source), ESX.GetPlayerFromId(playerId) - MySQL.Async.execute('INSERT INTO owned_vehicles (owner, plate, vehicle) VALUES (@owner, @plate, @vehicle)', - { - ['@owner'] = xPlayer.identifier, - ['@plate'] = vehicleProps.plate, - ['@vehicle'] = json.encode(vehicleProps) - }, function(rowsChanged) - xPlayer.showNotification(_U('vehicle_belongs', vehicleProps.plate)) - end) -end) + if xPlayer.job.name == 'cardealer' and xTarget then + MySQL.Async.fetchAll('SELECT id FROM cardealer_vehicles WHERE vehicle = @vehicle LIMIT 1', { + ['@vehicle'] = model + }, function(result) + if result[1] then + local id = result[1].id -RegisterServerEvent('esx_vehicleshop:setVehicleOwnedPlayerId') -AddEventHandler('esx_vehicleshop:setVehicleOwnedPlayerId', function(playerId, vehicleProps) - local xPlayer = ESX.GetPlayerFromId(playerId) + MySQL.Async.execute('DELETE FROM cardealer_vehicles WHERE id = @id', { + ['@id'] = id + }, function(rowsChanged) + if rowsChanged == 1 then + MySQL.Async.execute('INSERT INTO owned_vehicles (owner, plate, vehicle) VALUES (@owner, @plate, @vehicle)', { + ['@owner'] = xTarget.identifier, + ['@plate'] = vehicleProps.plate, + ['@vehicle'] = json.encode(vehicleProps) + }, function(rowsChanged) + xPlayer.showNotification(_U('vehicle_set_owned', vehicleProps.plate, xTarget.getName())) + xTarget.showNotification(_U('vehicle_belongs', vehicleProps.plate)) + end) - MySQL.Async.execute('INSERT INTO owned_vehicles (owner, plate, vehicle) VALUES (@owner, @plate, @vehicle)', - { - ['@owner'] = xPlayer.identifier, - ['@plate'] = vehicleProps.plate, - ['@vehicle'] = json.encode(vehicleProps) - }, function(rowsChanged) - xPlayer.showNotification(_U('vehicle_belongs', vehicleProps.plate)) - end) -end) + local dateNow = os.date('%Y-%m-%d %H:%M') -RegisterServerEvent('esx_vehicleshop:setVehicleOwnedSociety') -AddEventHandler('esx_vehicleshop:setVehicleOwnedSociety', function(society, vehicleProps) - local _source = source - local xPlayer = ESX.GetPlayerFromId(_source) - - MySQL.Async.execute('INSERT INTO owned_vehicles (owner, plate, vehicle) VALUES (@owner, @plate, @vehicle)', { - ['@owner'] = 'society:' .. society, - ['@plate'] = vehicleProps.plate, - ['@vehicle'] = json.encode(vehicleProps), - }, function(rowsChanged) end) -end) - -RegisterServerEvent('esx_vehicleshop:sellVehicle') -AddEventHandler('esx_vehicleshop:sellVehicle', function(vehicle) - MySQL.Async.fetchAll('SELECT * FROM cardealer_vehicles WHERE vehicle = @vehicle LIMIT 1', { - ['@vehicle'] = vehicle - }, function(result) - local id = result[1].id - - MySQL.Async.execute('DELETE FROM cardealer_vehicles WHERE id = @id', { - ['@id'] = id - }) - end) -end) - -RegisterServerEvent('esx_vehicleshop:addToList') -AddEventHandler('esx_vehicleshop:addToList', function(target, model, plate) - local xPlayer, xTarget = ESX.GetPlayerFromId(source), ESX.GetPlayerFromId(target) - local dateNow = os.date('%Y-%m-%d %H:%M') - - if xPlayer.job.name == 'cardealer' then - MySQL.Async.execute('INSERT INTO vehicle_sold (client, model, plate, soldby, date) VALUES (@client, @model, @plate, @soldby, @date)', { - ['@client'] = xTarget.getName(), - ['@model'] = model, - ['@plate'] = plate, - ['@soldby'] = xPlayer.getName(), - ['@date'] = dateNow - }) - else - print(('esx_vehicleshop: %s attempted to add a sold vehicle to list!'):format(xPlayer.identifier)) + MySQL.Async.execute('INSERT INTO vehicle_sold (client, model, plate, soldby, date) VALUES (@client, @model, @plate, @soldby, @date)', { + ['@client'] = xTarget.getName(), + ['@model'] = label, + ['@plate'] = vehicleProps.plate, + ['@soldby'] = xPlayer.getName(), + ['@date'] = dateNow + }) + end + end) + end + end) end end) ESX.RegisterServerCallback('esx_vehicleshop:getSoldVehicles', function(source, cb) - MySQL.Async.fetchAll('SELECT * FROM vehicle_sold', {}, function(result) + MySQL.Async.fetchAll('SELECT client, model, plate, soldby, date FROM vehicle_sold', {}, function(result) cb(result) end) end) -RegisterServerEvent('esx_vehicleshop:rentVehicle') -AddEventHandler('esx_vehicleshop:rentVehicle', function(vehicle, plate, playerName, basePrice, rentPrice, target) - local xPlayer = ESX.GetPlayerFromId(target) +RegisterNetEvent('esx_vehicleshop:rentVehicle') +AddEventHandler('esx_vehicleshop:rentVehicle', function(vehicle, plate, rentPrice, playerId) + local xPlayer, xTarget = ESX.GetPlayerFromId(source), ESX.GetPlayerFromId(playerId) - MySQL.Async.fetchAll('SELECT * FROM cardealer_vehicles WHERE vehicle = @vehicle LIMIT 1', { - ['@vehicle'] = vehicle - }, function(result) - local id = result[1].id - local price = result[1].price - local owner = xPlayer.identifier + if xPlayer.job.name == 'cardealer' and xTarget then + MySQL.Async.fetchAll('SELECT id, price FROM cardealer_vehicles WHERE vehicle = @vehicle LIMIT 1', { + ['@vehicle'] = vehicle + }, function(result) + if result[1] then + local price = result[1].price - MySQL.Async.execute('DELETE FROM cardealer_vehicles WHERE id = @id', { - ['@id'] = id - }) - - MySQL.Async.execute('INSERT INTO rented_vehicles (vehicle, plate, player_name, base_price, rent_price, owner) VALUES (@vehicle, @plate, @player_name, @base_price, @rent_price, @owner)', { - ['@vehicle'] = vehicle, - ['@plate'] = plate, - ['@player_name'] = playerName, - ['@base_price'] = basePrice, - ['@rent_price'] = rentPrice, - ['@owner'] = owner - }) - end) + MySQL.Async.execute('DELETE FROM cardealer_vehicles WHERE id = @id', { + ['@id'] = result[1].id + }, function(rowsChanged) + if rowsChanged == 1 then + MySQL.Async.execute('INSERT INTO rented_vehicles (vehicle, plate, player_name, base_price, rent_price, owner) VALUES (@vehicle, @plate, @player_name, @base_price, @rent_price, @owner)', { + ['@vehicle'] = vehicle, + ['@plate'] = plate, + ['@player_name'] = xTarget.getName(), + ['@base_price'] = price, + ['@rent_price'] = rentPrice, + ['@owner'] = xTarget.identifier + }, function(rowsChanged2) + xPlayer.showNotification(_U('vehicle_set_rented', plate, xTarget.getName())) + end) + end + end) + end + end) + end end) -RegisterServerEvent('esx_vehicleshop:getStockItem') +RegisterNetEvent('esx_vehicleshop:getStockItem') AddEventHandler('esx_vehicleshop:getStockItem', function(itemName, count) local _source = source local xPlayer = ESX.GetPlayerFromId(_source) @@ -173,7 +158,7 @@ AddEventHandler('esx_vehicleshop:getStockItem', function(itemName, count) end) end) -RegisterServerEvent('esx_vehicleshop:putStockItems') +RegisterNetEvent('esx_vehicleshop:putStockItems') AddEventHandler('esx_vehicleshop:putStockItems', function(itemName, count) local _source = source local xPlayer = ESX.GetPlayerFromId(_source) @@ -192,98 +177,107 @@ AddEventHandler('esx_vehicleshop:putStockItems', function(itemName, count) end) ESX.RegisterServerCallback('esx_vehicleshop:getCategories', function(source, cb) - cb(Categories) + cb(categories) end) ESX.RegisterServerCallback('esx_vehicleshop:getVehicles', function(source, cb) - cb(Vehicles) + cb(vehicles) end) -ESX.RegisterServerCallback('esx_vehicleshop:buyVehicle', function(source, cb, vehicleModel) +ESX.RegisterServerCallback('esx_vehicleshop:buyVehicle', function(source, cb, model, plate) local xPlayer = ESX.GetPlayerFromId(source) - local vehicleData + local modelPrice - for i=1, #Vehicles, 1 do - if Vehicles[i].model == vehicleModel then - vehicleData = Vehicles[i] + for k,v in ipairs(vehicles) do + if model == v.model then + modelPrice = v.price break end end - if vehicleData and xPlayer.getMoney() >= vehicleData.price then - xPlayer.removeMoney(vehicleData.price) - cb(true) + if modelPrice and xPlayer.getMoney() >= modelPrice then + xPlayer.removeMoney(modelPrice) + + MySQL.Async.execute('INSERT INTO owned_vehicles (owner, plate, vehicle) VALUES (@owner, @plate, @vehicle)', { + ['@owner'] = xPlayer.identifier, + ['@plate'] = plate, + ['@vehicle'] = json.encode({model = GetHashKey(model)}) + }, function(rowsChanged) + xPlayer.showNotification(_U('vehicle_belongs', plate)) + cb(true) + end) else cb(false) end end) -ESX.RegisterServerCallback('esx_vehicleshop:buyVehicleSociety', function(source, cb, society, vehicleModel) - local vehicleData +ESX.RegisterServerCallback('esx_vehicleshop:getCommercialVehicles', function(source, cb) + MySQL.Async.fetchAll('SELECT price, vehicle FROM cardealer_vehicles ORDER BY vehicle ASC', {}, function(result) + cb(result) + end) +end) - for i=1, #Vehicles, 1 do - if Vehicles[i].model == vehicleModel then - vehicleData = Vehicles[i] - break +ESX.RegisterServerCallback('esx_vehicleshop:buyCarDealerVehicle', function(source, cb, model) + local xPlayer = ESX.GetPlayerFromId(source) + + if xPlayer.job.name == 'cardealer' then + local modelPrice + + for k,v in ipairs(vehicles) do + if model == v.model then + modelPrice = v.price + break + end + end + + if modelPrice then + TriggerEvent('esx_addonaccount:getSharedAccount', 'society_cardealer', function(account) + if account.money >= modelPrice then + account.removeMoney(modelPrice) + + MySQL.Async.execute('INSERT INTO cardealer_vehicles (vehicle, price) VALUES (@vehicle, @price)', { + ['@vehicle'] = model, + ['@price'] = modelPrice + }, function(rowsChanged) + cb(true) + end) + else + cb(false) + end + end) end end - - TriggerEvent('esx_addonaccount:getSharedAccount', 'society_' .. society, function(account) - if account.money >= vehicleData.price then - account.removeMoney(vehicleData.price) - - MySQL.Async.execute('INSERT INTO cardealer_vehicles (vehicle, price) VALUES (@vehicle, @price)', { - ['@vehicle'] = vehicleData.model, - ['@price'] = vehicleData.price - }, function(rowsChanged) - cb(true) - end) - else - cb(false) - end - end) end) -ESX.RegisterServerCallback('esx_vehicleshop:getCommercialVehicles', function(source, cb) - MySQL.Async.fetchAll('SELECT * FROM cardealer_vehicles ORDER BY vehicle ASC', {}, function(result) - local vehicles = {} - - for i=1, #result, 1 do - table.insert(vehicles, { - name = result[i].vehicle, - price = result[i].price - }) - end - - cb(vehicles) - end) -end) - - -RegisterServerEvent('esx_vehicleshop:returnProvider') +RegisterNetEvent('esx_vehicleshop:returnProvider') AddEventHandler('esx_vehicleshop:returnProvider', function(vehicleModel) - local _source = source + local xPlayer = ESX.GetPlayerFromId(source) - MySQL.Async.fetchAll('SELECT * FROM cardealer_vehicles WHERE vehicle = @vehicle LIMIT 1', { - ['@vehicle'] = vehicleModel - }, function(result) - if result[1] then - local id = result[1].id - local price = ESX.Math.Round(result[1].price * 0.75) + if xPlayer.job.name == 'cardealer' then + MySQL.Async.fetchAll('SELECT id, price FROM cardealer_vehicles WHERE vehicle = @vehicle LIMIT 1', { + ['@vehicle'] = vehicleModel + }, function(result) + if result[1] then + local id = result[1].id - TriggerEvent('esx_addonaccount:getSharedAccount', 'society_cardealer', function(account) - account.addMoney(price) - end) + MySQL.Async.execute('DELETE FROM cardealer_vehicles WHERE id = @id', { + ['@id'] = id + }, function(rowsChanged) + if rowsChanged == 1 then + TriggerEvent('esx_addonaccount:getSharedAccount', 'society_cardealer', function(account) + local price = ESX.Math.Round(result[1].price * 0.75) + local vehicleLabel = getVehicleLabelFromModel(vehicleModel) - MySQL.Async.execute('DELETE FROM cardealer_vehicles WHERE id = @id', { - ['@id'] = id - }) - - xPlayer.showNotification(_U('vehicle_sold_for', vehicleModel, ESX.Math.GroupDigits(price))) - else - print(('esx_vehicleshop: %s attempted selling an invalid vehicle!'):format(GetPlayerIdentifiers(_source)[1])) - end - end) + account.addMoney(price) + xPlayer.showNotification(_U('vehicle_sold_for', vehicleLabel, ESX.Math.GroupDigits(price))) + end) + end + end) + else + print(('[esx_vehicleshop] [^3WARNING^7] %s attempted selling an invalid vehicle!'):format(xPlayer.identifier)) + end + end) + end end) ESX.RegisterServerCallback('esx_vehicleshop:getRentedVehicles', function(source, cb) @@ -303,24 +297,24 @@ ESX.RegisterServerCallback('esx_vehicleshop:getRentedVehicles', function(source, end) ESX.RegisterServerCallback('esx_vehicleshop:giveBackVehicle', function(source, cb, plate) - MySQL.Async.fetchAll('SELECT * FROM rented_vehicles WHERE plate = @plate', { + MySQL.Async.fetchAll('SELECT base_price, vehicle FROM rented_vehicles WHERE plate = @plate', { ['@plate'] = plate }, function(result) if result[1] then local vehicle = result[1].vehicle local basePrice = result[1].base_price - MySQL.Async.execute('INSERT INTO cardealer_vehicles (vehicle, price) VALUES (@vehicle, @price)', { - ['@vehicle'] = vehicle, - ['@price'] = basePrice - }) - MySQL.Async.execute('DELETE FROM rented_vehicles WHERE plate = @plate', { ['@plate'] = plate - }) - - RemoveOwnedVehicle(plate) - cb(true) + }, function(rowsChanged) + MySQL.Async.execute('INSERT INTO cardealer_vehicles (vehicle, price) VALUES (@vehicle, @price)', { + ['@vehicle'] = vehicle, + ['@price'] = basePrice + }) + + RemoveOwnedVehicle(plate) + cb(true) + end) else cb(false) end @@ -328,18 +322,18 @@ ESX.RegisterServerCallback('esx_vehicleshop:giveBackVehicle', function(source, c end) ESX.RegisterServerCallback('esx_vehicleshop:resellVehicle', function(source, cb, plate, model) - local resellPrice = 0 + local resellPrice -- calculate the resell price - for i=1, #Vehicles, 1 do - if GetHashKey(Vehicles[i].model) == model then - resellPrice = ESX.Math.Round(Vehicles[i].price / 100 * Config.ResellPercentage) + for i=1, #vehicles, 1 do + if GetHashKey(vehicles[i].model) == model then + resellPrice = ESX.Math.Round(vehicles[i].price / 100 * Config.ResellPercentage) break end end - if resellPrice == 0 then - print(('esx_vehicleshop: %s attempted to sell an unknown vehicle!'):format(GetPlayerIdentifiers(source)[1])) + if not resellPrice then + print(('[esx_vehicleshop] [^3WARNING^7] %s attempted to sell an unknown vehicle!'):format(GetPlayerIdentifiers(source)[1])) cb(false) else MySQL.Async.fetchAll('SELECT * FROM rented_vehicles WHERE plate = @plate', { @@ -363,40 +357,11 @@ ESX.RegisterServerCallback('esx_vehicleshop:resellVehicle', function(source, cb, RemoveOwnedVehicle(plate) cb(true) else - print(('esx_vehicleshop: %s attempted to sell an vehicle with plate mismatch!'):format(xPlayer.identifier)) + print(('[esx_vehicleshop] [^3WARNING^7] %s attempted to sell an vehicle with plate mismatch!'):format(xPlayer.identifier)) cb(false) end else - print(('esx_vehicleshop: %s attempted to sell an vehicle with model mismatch!'):format(xPlayer.identifier)) - cb(false) - end - else - if xPlayer.job.grade_name == 'boss' then - MySQL.Async.fetchAll('SELECT * FROM owned_vehicles WHERE owner = @owner AND @plate = plate', { - ['@owner'] = 'society:' .. xPlayer.job.name, - ['@plate'] = plate - }, function(result) - if result[1] then - local vehicle = json.decode(result[1].vehicle) - - if vehicle.model == model then - if vehicle.plate == plate then - xPlayer.addMoney(resellPrice) - RemoveOwnedVehicle(plate) - cb(true) - else - print(('esx_vehicleshop: %s attempted to sell an vehicle with plate mismatch!'):format(xPlayer.identifier)) - cb(false) - end - else - print(('esx_vehicleshop: %s attempted to sell an vehicle with model mismatch!'):format(xPlayer.identifier)) - cb(false) - end - else - cb(false) - end - end) - else + print(('[esx_vehicleshop] [^3WARNING^7] %s attempted to sell an vehicle with model mismatch!'):format(xPlayer.identifier)) cb(false) end end @@ -439,7 +404,7 @@ ESX.RegisterServerCallback('esx_vehicleshop:retrieveJobVehicles', function(sourc end) end) -RegisterServerEvent('esx_vehicleshop:setJobVehicleState') +RegisterNetEvent('esx_vehicleshop:setJobVehicleState') AddEventHandler('esx_vehicleshop:setJobVehicleState', function(plate, state) local xPlayer = ESX.GetPlayerFromId(source) @@ -449,7 +414,7 @@ AddEventHandler('esx_vehicleshop:setJobVehicleState', function(plate, state) ['@job'] = xPlayer.job.name }, function(rowsChanged) if rowsChanged == 0 then - print(('esx_vehicleshop: %s exploited the garage!'):format(xPlayer.identifier)) + print(('[esx_vehicleshop] [^3WARNING^7] %s exploited the garage!'):format(xPlayer.identifier)) end end) end)