448 lines
14 KiB
Lua
448 lines
14 KiB
Lua
local categories, vehicles = {}, {}
|
|
local vehiclesByModel = {}
|
|
|
|
CreateThread(function()
|
|
exports["esx_society"]:registerSociety('cardealer', TranslateCap('car_dealer'), 'society_cardealer', 'society_cardealer', 'society_cardealer', {type = 'private'})
|
|
end)
|
|
|
|
CreateThread(function()
|
|
local char = Config.PlateLetters
|
|
char = char + Config.PlateNumbers
|
|
if Config.PlateUseSpace then char = char + 1 end
|
|
|
|
if char > 8 then
|
|
print(('[^3WARNING^7] Character Limit Exceeded, ^5%s/8^7!'):format(char))
|
|
end
|
|
end)
|
|
|
|
function RemoveOwnedVehicle(plate)
|
|
MySQL.update('DELETE FROM owned_vehicles WHERE plate = ?', {plate})
|
|
end
|
|
|
|
AddEventHandler('onResourceStart', function(resourceName)
|
|
if resourceName == GetCurrentResourceName() then
|
|
SQLVehiclesAndCategories()
|
|
end
|
|
end)
|
|
|
|
function SQLVehiclesAndCategories()
|
|
categories = MySQL.query.await('SELECT * FROM vehicle_categories')
|
|
vehicles = MySQL.query.await('SELECT vehicles.*, vehicle_categories.label AS categoryLabel FROM vehicles JOIN vehicle_categories ON vehicles.category = vehicle_categories.name')
|
|
|
|
for _, vehicle in pairs(vehicles) do
|
|
vehiclesByModel[vehicle.model] = vehicle
|
|
end
|
|
|
|
TriggerClientEvent("esx_vehicleshop:updateVehiclesAndCategories", -1, vehicles, categories, vehiclesByModel)
|
|
end
|
|
|
|
function getVehicleFromModel(model)
|
|
return vehiclesByModel[model]
|
|
end
|
|
|
|
RegisterNetEvent("esx_vehicleshop:getVehiclesAndCategories", function()
|
|
TriggerClientEvent("esx_vehicleshop:updateVehiclesAndCategories", source, vehicles, categories, vehiclesByModel)
|
|
end)
|
|
|
|
RegisterNetEvent('esx_vehicleshop:setVehicleOwnedPlayerId')
|
|
AddEventHandler('esx_vehicleshop:setVehicleOwnedPlayerId', function(playerId, vehicleProps, model, label)
|
|
local xPlayer, xTarget = ESX.Player(source), ESX.Player(playerId)
|
|
|
|
if xPlayer.getJob().name ~= 'cardealer' or not xTarget then
|
|
return
|
|
end
|
|
local xTargetName = xTarget.getName()
|
|
MySQL.scalar('SELECT id FROM cardealer_vehicles WHERE vehicle = ?', {model},
|
|
function(id)
|
|
if not id then
|
|
return
|
|
end
|
|
|
|
MySQL.update('DELETE FROM cardealer_vehicles WHERE id = ?', {id},
|
|
function(rowsChanged)
|
|
if rowsChanged == 1 then
|
|
MySQL.insert('INSERT INTO owned_vehicles (owner, plate, vehicle) VALUES (?, ?, ?)', {xTarget.getIdentifier(), vehicleProps.plate, json.encode(vehicleProps)},
|
|
function(id)
|
|
xPlayer.showNotification(TranslateCap('vehicle_set_owned', vehicleProps.plate, xTargetName))
|
|
xTarget.showNotification(TranslateCap('vehicle_belongs', vehicleProps.plate))
|
|
end)
|
|
|
|
MySQL.insert('INSERT INTO vehicle_sold (client, model, plate, soldby, date) VALUES (?, ?, ?, ?, ?)', {xTargetName, label, vehicleProps.plate, xPlayer.getName(), os.date('%Y-%m-%d %H:%M')})
|
|
end
|
|
end)
|
|
end)
|
|
end)
|
|
|
|
ESX.RegisterServerCallback('esx_vehicleshop:getSoldVehicles', function(source, cb)
|
|
MySQL.query('SELECT client, model, plate, soldby, date FROM vehicle_sold ORDER BY DATE DESC', function(result)
|
|
cb(result)
|
|
end)
|
|
end)
|
|
|
|
RegisterNetEvent('esx_vehicleshop:rentVehicle')
|
|
AddEventHandler('esx_vehicleshop:rentVehicle', function(vehicle, plate, rentPrice, playerId)
|
|
local xPlayer, xTarget = ESX.Player(source), ESX.Player(playerId)
|
|
|
|
if xPlayer.getJob().name ~= 'cardealer' or not xTarget then
|
|
return
|
|
end
|
|
local xTargetName = xTarget.getName()
|
|
MySQL.single('SELECT id, price FROM cardealer_vehicles WHERE vehicle = ?', {vehicle},
|
|
function(result)
|
|
if not result then
|
|
return
|
|
end
|
|
|
|
MySQL.update('DELETE FROM cardealer_vehicles WHERE id = ?', {result.id},
|
|
function(rowsChanged)
|
|
if rowsChanged ~= 1 then
|
|
return
|
|
end
|
|
|
|
MySQL.insert('INSERT INTO rented_vehicles (vehicle, plate, player_name, base_price, rent_price, owner) VALUES (?, ?, ?, ?, ?, ?)', {vehicle, plate, xTargetName, result.price, rentPrice, xTarget.getIdentifier()},
|
|
function(id)
|
|
xPlayer.showNotification(TranslateCap('vehicle_set_rented', plate, xTargetName))
|
|
end)
|
|
end)
|
|
end)
|
|
end)
|
|
|
|
RegisterNetEvent('esx_vehicleshop:getStockItem')
|
|
AddEventHandler('esx_vehicleshop:getStockItem', function(itemName, count)
|
|
local source = source
|
|
local xPlayer = ESX.Player(source)
|
|
|
|
TriggerEvent('esx_addoninventory:getSharedInventory', 'society_cardealer', function(inventory)
|
|
local item = inventory.getItem(itemName)
|
|
|
|
-- is there enough in the society?
|
|
if count > 0 and item.count >= count then
|
|
|
|
-- can the player carry the said amount of x item?
|
|
if not xPlayer.canCarryItem(itemName, count) then
|
|
return xPlayer.showNotification(TranslateCap('player_cannot_hold'))
|
|
end
|
|
inventory.removeItem(itemName, count)
|
|
xPlayer.addInventoryItem(itemName, count)
|
|
xPlayer.showNotification(TranslateCap('have_withdrawn', count, item.label))
|
|
else
|
|
xPlayer.showNotification(TranslateCap('not_enough_in_society'))
|
|
end
|
|
end)
|
|
end)
|
|
|
|
RegisterNetEvent('esx_vehicleshop:putStockItems')
|
|
AddEventHandler('esx_vehicleshop:putStockItems', function(itemName, count)
|
|
local source = source
|
|
local xPlayer = ESX.Player(source)
|
|
|
|
TriggerEvent('esx_addoninventory:getSharedInventory', 'society_cardealer', function(inventory)
|
|
local item = inventory.getItem(itemName)
|
|
|
|
if item.count >= 0 then
|
|
xPlayer.removeInventoryItem(itemName, count)
|
|
inventory.addItem(itemName, count)
|
|
xPlayer.showNotification(TranslateCap('have_deposited', count, item.label))
|
|
else
|
|
xPlayer.showNotification(TranslateCap('invalid_amount'))
|
|
end
|
|
end)
|
|
end)
|
|
|
|
ESX.RegisterServerCallback('esx_vehicleshop:buyVehicle', function(source, cb, model, plate)
|
|
local xPlayer = ESX.Player(source)
|
|
local modelPrice = getVehicleFromModel(model).price
|
|
|
|
if modelPrice and xPlayer.getMoney() >= modelPrice then
|
|
xPlayer.removeMoney(modelPrice, "Vehicle Purchase")
|
|
|
|
MySQL.insert('INSERT INTO owned_vehicles (owner, plate, vehicle) VALUES (?, ?, ?)', {xPlayer.getIdentifier(), plate, json.encode({model = joaat(model), plate = plate})
|
|
}, function(rowsChanged)
|
|
xPlayer.showNotification(TranslateCap('vehicle_belongs', plate))
|
|
ESX.OneSync.SpawnVehicle(joaat(model), Config.Zones.ShopOutside.Pos, Config.Zones.ShopOutside.Heading,{plate = plate}, function(vehicle)
|
|
Wait(100)
|
|
local vehicle = NetworkGetEntityFromNetworkId(vehicle)
|
|
Wait(300)
|
|
TaskWarpPedIntoVehicle(GetPlayerPed(source), vehicle, -1)
|
|
end)
|
|
cb(true)
|
|
end)
|
|
else
|
|
cb(false)
|
|
end
|
|
end)
|
|
|
|
ESX.RegisterServerCallback('esx_vehicleshop:getCommercialVehicles', function(source, cb)
|
|
MySQL.query('SELECT price, vehicle FROM cardealer_vehicles ORDER BY vehicle ASC', function(result)
|
|
cb(result)
|
|
end)
|
|
end)
|
|
|
|
ESX.RegisterServerCallback('esx_vehicleshop:buyCarDealerVehicle', function(source, cb, model)
|
|
local xPlayer = ESX.Player(source)
|
|
|
|
if xPlayer.getJob().name ~= 'cardealer' then
|
|
return cb(false)
|
|
end
|
|
local modelPrice = getVehicleFromModel(model).price
|
|
|
|
if not modelPrice then
|
|
return cb(false)
|
|
end
|
|
TriggerEvent('esx_addonaccount:getSharedAccount', 'society_cardealer', function(account)
|
|
if account.money < modelPrice then
|
|
return cb(false)
|
|
end
|
|
|
|
account.removeMoney(modelPrice)
|
|
|
|
MySQL.insert('INSERT INTO cardealer_vehicles (vehicle, price) VALUES (?, ?)', {model, modelPrice},
|
|
function(rowsChanged)
|
|
cb(true)
|
|
end)
|
|
end)
|
|
end)
|
|
|
|
RegisterNetEvent('esx_vehicleshop:returnProvider')
|
|
AddEventHandler('esx_vehicleshop:returnProvider', function(vehicleModel)
|
|
local xPlayer = ESX.Player(source)
|
|
|
|
if xPlayer.getJob().name ~= 'cardealer' then
|
|
return
|
|
end
|
|
MySQL.single('SELECT id, price FROM cardealer_vehicles WHERE vehicle = ?', {vehicleModel},
|
|
function(result)
|
|
if not result then
|
|
return print(('[^3WARNING^7] Player ^5%s^7 Attempted To Sell Invalid Vehicle - ^5%s^7!'):format(source, vehicleModel))
|
|
end
|
|
|
|
local id = result.id
|
|
|
|
MySQL.update('DELETE FROM cardealer_vehicles WHERE id = ?', {id},
|
|
function(rowsChanged)
|
|
if rowsChanged ~= 1 then
|
|
return
|
|
end
|
|
TriggerEvent('esx_addonaccount:getSharedAccount', 'society_cardealer', function(account)
|
|
local price = ESX.Math.Round(result.price * 0.75)
|
|
local vehicleLabel = getVehicleFromModel(vehicleModel).name
|
|
|
|
account.addMoney(price)
|
|
xPlayer.showNotification(TranslateCap('vehicle_sold_for', vehicleLabel, ESX.Math.GroupDigits(price)))
|
|
end)
|
|
end)
|
|
end)
|
|
end)
|
|
|
|
ESX.RegisterServerCallback('esx_vehicleshop:getRentedVehicles', function(source, cb)
|
|
MySQL.query('SELECT * FROM rented_vehicles ORDER BY player_name ASC', function(result)
|
|
local vehicles = {}
|
|
|
|
for i = 1, #result do
|
|
local vehicle = result[i]
|
|
vehicles[#vehicles + 1] = {
|
|
name = vehicle.vehicle,
|
|
plate = vehicle.plate,
|
|
playerName = vehicle.player_name
|
|
}
|
|
end
|
|
|
|
cb(vehicles)
|
|
end)
|
|
end)
|
|
|
|
ESX.RegisterServerCallback('esx_vehicleshop:giveBackVehicle', function(source, cb, plate)
|
|
MySQL.single('SELECT base_price, vehicle FROM rented_vehicles WHERE plate = ?', {plate},
|
|
function(result)
|
|
if not result then
|
|
return cb(false)
|
|
end
|
|
|
|
MySQL.update('DELETE FROM rented_vehicles WHERE plate = ?', {plate},
|
|
function()
|
|
MySQL.insert('INSERT INTO cardealer_vehicles (vehicle, price) VALUES (?, ?)', {result.vehicle, result.base_price})
|
|
|
|
RemoveOwnedVehicle(plate)
|
|
cb(true)
|
|
end)
|
|
end)
|
|
end)
|
|
|
|
ESX.RegisterServerCallback('esx_vehicleshop:resellVehicle', function(source, cb, plate, model)
|
|
local xPlayer, resellPrice = ESX.Player(source)
|
|
|
|
if xPlayer.getJob().name == 'cardealer' or not Config.EnablePlayerManagement then
|
|
-- calculate the resell price
|
|
for i=1, #vehicles, 1 do
|
|
if joaat(vehicles[i].model) == model then
|
|
resellPrice = ESX.Math.Round(vehicles[i].price / 100 * Config.ResellPercentage)
|
|
break
|
|
end
|
|
end
|
|
|
|
if not resellPrice then
|
|
print(('[^3WARNING^7] Player ^5%s^7 Attempted To Resell Invalid Vehicle - ^5%s^7!'):format(source, model))
|
|
return cb(false)
|
|
end
|
|
MySQL.single('SELECT * FROM rented_vehicles WHERE plate = ?', {plate},
|
|
function(result)
|
|
if result then -- is it a rented vehicle?
|
|
return cb(false) -- it is, don't let the player sell it since he doesn't own it
|
|
end
|
|
MySQL.single('SELECT * FROM owned_vehicles WHERE owner = ? AND plate = ?', {xPlayer.getIdentifier(), plate},
|
|
function(result)
|
|
if not result then -- does the owner match?
|
|
return
|
|
end
|
|
local vehicle = json.decode(result.vehicle)
|
|
|
|
if vehicle.model ~= model then
|
|
print(('[^3WARNING^7] Player ^5%s^7 Attempted To Resell Vehicle With Invalid Model - ^5%s^7!'):format(source, model))
|
|
return cb(false)
|
|
end
|
|
if vehicle.plate ~= plate then
|
|
print(('[^3WARNING^7] Player ^5%s^7 Attempted To Resell Vehicle With Invalid Plate - ^5%s^7!'):format(source, plate))
|
|
return cb(false)
|
|
end
|
|
|
|
xPlayer.addMoney(resellPrice, "Sold Vehicle")
|
|
RemoveOwnedVehicle(plate)
|
|
cb(true)
|
|
end)
|
|
end)
|
|
end
|
|
end)
|
|
|
|
ESX.RegisterServerCallback('esx_vehicleshop:getStockItems', function(source, cb)
|
|
TriggerEvent('esx_addoninventory:getSharedInventory', 'society_cardealer', function(inventory)
|
|
cb(inventory.items)
|
|
end)
|
|
end)
|
|
|
|
ESX.RegisterServerCallback('esx_vehicleshop:getPlayerInventory', function(source, cb)
|
|
local xPlayer = ESX.Player(source)
|
|
local items = xPlayer.getInventory(true)
|
|
|
|
cb({items = items})
|
|
end)
|
|
|
|
ESX.RegisterServerCallback('esx_vehicleshop:isPlateTaken', function(source, cb, plate)
|
|
MySQL.scalar('SELECT plate FROM owned_vehicles WHERE plate = ?', {plate},
|
|
function(result)
|
|
cb(result ~= nil)
|
|
end)
|
|
end)
|
|
|
|
ESX.RegisterServerCallback('esx_vehicleshop:retrieveJobVehicles', function(source, cb, type)
|
|
local xPlayer = ESX.Player(source)
|
|
|
|
MySQL.query('SELECT * FROM owned_vehicles WHERE owner = ? AND type = ? AND job = ?', {xPlayer.getIdentifier(), type, xPlayer.getJob().name},
|
|
function(result)
|
|
cb(result)
|
|
end)
|
|
end)
|
|
|
|
RegisterNetEvent('esx_vehicleshop:setJobVehicleState')
|
|
AddEventHandler('esx_vehicleshop:setJobVehicleState', function(plate, state)
|
|
local xPlayer = ESX.Player(source)
|
|
|
|
MySQL.update('UPDATE owned_vehicles SET `stored` = ? WHERE plate = ? AND job = ?', {state, plate, xPlayer.getJob().name},
|
|
function(rowsChanged)
|
|
if rowsChanged == 0 then
|
|
print(('[^3WARNING^7] Player ^5%s^7 Attempted To Exploit the Garage!'):format(source, plate))
|
|
end
|
|
end)
|
|
end)
|
|
|
|
function PayRent()
|
|
local timeStart = os.clock()
|
|
print('[^2INFO^7] ^5Rent Payments^7 Initiated')
|
|
|
|
MySQL.query('SELECT rented_vehicles.owner, rented_vehicles.rent_price, rented_vehicles.plate, users.accounts FROM rented_vehicles LEFT JOIN users ON rented_vehicles.owner = users.identifier', {},
|
|
function(rentals)
|
|
local owners = {}
|
|
for i = 1, #rentals do
|
|
local rental = rentals[i]
|
|
if not owners[rental.owner] then
|
|
owners[rental.owner] = {rental}
|
|
else
|
|
owners[rental.owner][#owners[rental.owner] + 1] = rental
|
|
end
|
|
end
|
|
|
|
local total = 0
|
|
local unrentals = {}
|
|
local users = {}
|
|
for k, v in pairs(owners) do
|
|
local sum = 0
|
|
for i = 1, #v do
|
|
sum = sum + v[i].rent_price
|
|
end
|
|
local xPlayer = ESX.Player(k)
|
|
|
|
if xPlayer then
|
|
local bank = xPlayer.getAccount('bank').money
|
|
|
|
if bank >= sum and #v > 1 then
|
|
total = total + sum
|
|
xPlayer.removeAccountMoney('bank', sum, "Vehicle Rental")
|
|
xPlayer.showNotification(('You have paid $%s for all of your rentals'):format(ESX.Math.GroupDigits(sum)))
|
|
else
|
|
for i = 1, #v do
|
|
local rental = v[i]
|
|
if xPlayer.getAccount('bank').money >= rental.rent_price then
|
|
total = total + rental.rent_price
|
|
xPlayer.removeAccountMoney('bank', rental.rent_price, "Vehicle Rental")
|
|
xPlayer.showNotification(TranslateCap('paid_rental', ESX.Math.GroupDigits(rental.rent_price), rental.plate))
|
|
else
|
|
xPlayer.showNotification(TranslateCap('paid_rental_evicted', ESX.Math.GroupDigits(rental.rent_price), rental.plate))
|
|
unrentals[#unrentals + 1] = {rental.owner, rental.plate}
|
|
end
|
|
end
|
|
end
|
|
else
|
|
local accounts = json.decode(v[1].accounts)
|
|
if accounts.bank < sum then
|
|
sum = 0
|
|
local limit = false
|
|
for i = 1, #v do
|
|
local rental = v[i]
|
|
if not limit then
|
|
sum = sum + rental.rent_price
|
|
if sum > accounts.bank then
|
|
sum = sum - rental.rent_price
|
|
limit = true
|
|
end
|
|
else
|
|
unrentals[#unrentals + 1] = {rental.owner, rental.plate}
|
|
end
|
|
end
|
|
end
|
|
if sum > 0 then
|
|
total = total + sum
|
|
accounts.bank = accounts.bank - sum
|
|
users[#users + 1] = {json.encode(accounts), k}
|
|
end
|
|
end
|
|
end
|
|
|
|
if total > 0 then
|
|
TriggerEvent('esx_addonaccount:getSharedAccount', 'society_cardealer', function(account)
|
|
account.addMoney(total)
|
|
end)
|
|
end
|
|
|
|
if next(users) then
|
|
MySQL.prepare.await('UPDATE users SET accounts = ? WHERE identifier = ?', users)
|
|
end
|
|
|
|
if next(unrentals) then
|
|
MySQL.prepare.await('DELETE FROM rented_vehicles WHERE owner = ? AND plate = ?', unrentals)
|
|
end
|
|
|
|
print(('[^2INFO^7] ^5Rent Payments^7 took ^5%s^7 ms to execute'):format(ESX.Math.Round((os.time() - timeStart) / 1000000, 2)))
|
|
end)
|
|
end
|
|
|
|
TriggerEvent('cron:runAt', 22, 00, PayRent)
|