diff --git a/__resource.lua b/__resource.lua
index 76528017..ebabdf34 100644
--- a/__resource.lua
+++ b/__resource.lua
@@ -2,7 +2,7 @@ resource_manifest_version '44febabe-d386-4d18-afbe-5e627f4af937'
description 'ESX Shops'
-version '1.1.0'
+version '1.2.0'
client_scripts {
'@es_extended/locale.lua',
diff --git a/client/main.lua b/client/main.lua
index e9392bd1..e9c5bfd2 100644
--- a/client/main.lua
+++ b/client/main.lua
@@ -4,15 +4,17 @@ local LastZone = nil
local CurrentAction = nil
local CurrentActionMsg = ''
local CurrentActionData = {}
+local PlayerData = {}
Citizen.CreateThread(function()
while ESX == nil do
TriggerEvent('esx:getSharedObject', function(obj) ESX = obj end)
Citizen.Wait(0)
end
-
+
Citizen.Wait(5000)
-
+ PlayerData = ESX.GetPlayerData()
+
ESX.TriggerServerCallback('esx_shops:requestDBItems', function(ShopItems)
for k,v in pairs(ShopItems) do
Config.Zones[k].Items = v
@@ -20,38 +22,55 @@ Citizen.CreateThread(function()
end)
end)
-
function OpenShopMenu(zone)
+ PlayerData = ESX.GetPlayerData()
+
local elements = {}
for i=1, #Config.Zones[zone].Items, 1 do
-
local item = Config.Zones[zone].Items[i]
+
table.insert(elements, {
- label = item.label .. ' - $' .. item.price .. '',
- realLabel = item.label,
- value = item.name,
- price = item.price
+ label = item.label .. ' - $' .. item.price .. '',
+ label_real = item.label,
+ item = item.item,
+ price = item.price,
+
+ -- menu properties
+ value = 1,
+ type = 'slider',
+ min = 1,
+ max = item.limit
})
end
ESX.UI.Menu.CloseAll()
- ESX.UI.Menu.Open(
- 'default', GetCurrentResourceName(), 'shop',
- {
- title = _U('shop'),
+ ESX.UI.Menu.Open('default', GetCurrentResourceName(), 'shop', {
+ title = _U('shop'),
+ align = 'bottom-right',
+ elements = elements
+ }, function(data, menu)
+ ESX.UI.Menu.Open('default', GetCurrentResourceName(), 'shop_confirm', {
+ title = _U('shop_confirm', data.current.value, data.current.label_real, data.current.price * data.current.value),
align = 'bottom-right',
- elements = elements
- },
- function(data, menu)
- TriggerServerEvent('esx_shops:buyItem', data.current.value, data.current.price)
- end,
- function(data, menu)
- menu.close()
- CurrentAction = 'shop_menu'
- CurrentActionMsg = _U('press_menu')
- CurrentActionData = {zone = zone}
- end
- )
+ elements = {
+ {label = _U('no'), value = 'no'},
+ {label = _U('yes'), value = 'yes'}
+ }
+ }, function(data2, menu2)
+ if data2.current.value == 'yes' then
+ TriggerServerEvent('esx_shops:buyItem', data.current.item, data.current.value, zone)
+ end
+
+ menu2.close()
+ end, function(data2, menu2)
+ menu2.close()
+ end)
+ end, function(data, menu)
+ menu.close()
+ CurrentAction = 'shop_menu'
+ CurrentActionMsg = _U('press_menu')
+ CurrentActionData = {zone = zone}
+ end)
end
AddEventHandler('esx_shops:hasEnteredMarker', function(zone)
diff --git a/esx_shops.sql b/esx_shops.sql
index b9f72161..0952742d 100644
--- a/esx_shops.sql
+++ b/esx_shops.sql
@@ -1,16 +1,15 @@
USE `essentialmode`;
CREATE TABLE `shops` (
-
- `id` int(11) NOT NULL AUTO_INCREMENT,
- `name` varchar(255) NOT NULL,
- `item` varchar(255) NOT NULL,
- `price` int(11) NOT NULL,
-
- PRIMARY KEY (`id`)
+ `id` int(11) NOT NULL AUTO_INCREMENT,
+ `store` varchar(100) NOT NULL,
+ `item` varchar(100) NOT NULL,
+ `price` int(11) NOT NULL,
+
+ PRIMARY KEY (`id`)
);
-INSERT INTO `shops` (name, item, price) VALUES
+INSERT INTO `shops` (store, item, price) VALUES
('TwentyFourSeven','bread',30),
('TwentyFourSeven','water',15),
('RobsLiquor','bread',30),
diff --git a/locales/br.lua b/locales/br.lua
index 2d529545..03d5486a 100644
--- a/locales/br.lua
+++ b/locales/br.lua
@@ -1,8 +1,11 @@
Locales['br'] = {
- ['shop'] = 'Comprar',
- ['shops'] = 'Lojas',
- ['press_menu'] = 'Pressione ~INPUT_CONTEXT~ para acessar a loja.',
- ['bought'] = 'você comprou ~b~1x ',
- ['not_enough'] = 'você não tem ~r~dinheiro suficiente~s~.',
- ['player_cannot_hold'] = 'Você ~r~não~s~ tem bastante ~y~espaço livre~s~ no seu inventário!',
+ ['shop'] = 'comprar',
+ ['shops'] = 'lojas',
+ ['press_menu'] = 'pressione ~INPUT_CONTEXT~ para acessar a loja.',
+ ['bought'] = 'you just bought ~y~%sx~s~ ~b~%s~s~ for ~r~$%s~s~',
+ ['not_enough'] = 'você não tem ~r~dinheiro suficiente~s~: %s',
+ ['player_cannot_hold'] = 'você ~r~não~s~ tem bastante ~y~espaço livre~s~ no seu inventário!',
+ ['shop_confirm'] = 'buy %sx %s for $%s?',
+ ['no'] = 'no',
+ ['yes'] = 'yes',
}
diff --git a/locales/de.lua b/locales/de.lua
index c34fd81c..beba2424 100644
--- a/locales/de.lua
+++ b/locales/de.lua
@@ -1,9 +1,11 @@
Locales['de'] = {
-
- ['shop'] = 'Geschäft',
- ['shops'] = 'Geschäfte',
- ['press_menu'] = 'Drücke ~INPUT_CONTEXT~ um auf das Geschäft zuzugreifen.',
- ['bought'] = 'du kaufst ~b~1x ',
- ['not_enough'] = 'du ~r~hast nicht~s~ genug Geld.'
-
+ ['shop'] = 'geschäft',
+ ['shops'] = 'geschäfte',
+ ['press_menu'] = 'drücke ~INPUT_CONTEXT~ um auf das Geschäft zuzugreifen.',
+ ['bought'] = 'you just bought ~y~%sx~s~ ~b~%s~s~ for ~r~$%s~s~',
+ ['not_enough'] = 'du ~r~hast nicht~s~ genug geld: %s',
+ ['player_cannot_hold'] = 'you do ~r~not~s~ have enough ~y~free space~s~ in your inventory!',
+ ['shop_confirm'] = 'buy %sx %s for $%s?',
+ ['no'] = 'no',
+ ['yes'] = 'yes',
}
diff --git a/locales/en.lua b/locales/en.lua
index f88753a4..1b02063a 100644
--- a/locales/en.lua
+++ b/locales/en.lua
@@ -2,7 +2,10 @@ Locales['en'] = {
['shop'] = 'shop',
['shops'] = 'shops',
['press_menu'] = 'press ~INPUT_CONTEXT~ to access the ~y~store~s~.',
- ['bought'] = 'you just bought ~y~1x~s~ ~b~%s~s~ for ~r~$%s~s~',
+ ['bought'] = 'you just bought ~y~%sx~s~ ~b~%s~s~ for ~r~$%s~s~',
['not_enough'] = 'you do not have ~r~enough~s~ money, you\'re ~y~missing~s~ ~r~$%s~s~!',
['player_cannot_hold'] = 'you do ~r~not~s~ have enough ~y~free space~s~ in your inventory!',
+ ['shop_confirm'] = 'buy %sx %s for $%s?',
+ ['no'] = 'no',
+ ['yes'] = 'yes',
}
\ No newline at end of file
diff --git a/locales/es.lua b/locales/es.lua
index d25088fd..cbabfc9a 100644
--- a/locales/es.lua
+++ b/locales/es.lua
@@ -1,9 +1,11 @@
Locales['es'] = {
-
- ['shop'] = 'Tienda',
- ['shops'] = 'Tiendas',
- ['press_menu'] = 'Presiona ~INPUT_CONTEXT~ para acceder a la tienda.',
- ['bought'] = 'Has comprado ~b~1 ',
- ['not_enough'] = 'No tienes ~r~suficiente ~s~ dinero.',
-
+ ['shop'] = 'tienda',
+ ['shops'] = 'tiendas',
+ ['press_menu'] = 'presiona ~INPUT_CONTEXT~ para acceder a la tienda.',
+ ['bought'] = 'you just bought ~y~%sx~s~ ~b~%s~s~ for ~r~$%s~s~',
+ ['not_enough'] = 'no tienes ~r~suficiente ~s~ dinero: %s',
+ ['player_cannot_hold'] = 'you do ~r~not~s~ have enough ~y~free space~s~ in your inventory!',
+ ['shop_confirm'] = 'buy %sx %s for $%s?',
+ ['no'] = 'no',
+ ['yes'] = 'yes',
}
diff --git a/locales/fr.lua b/locales/fr.lua
index 14e9ca67..96513258 100644
--- a/locales/fr.lua
+++ b/locales/fr.lua
@@ -1,9 +1,11 @@
Locales['fr'] = {
-
['shop'] = 'magasin',
['shops'] = 'magasins',
['press_menu'] = 'appuyez sur ~INPUT_CONTEXT~ pour accéder au magasin.',
- ['bought'] = 'vous avez acheté ~b~1x ',
- ['not_enough'] = 'vous n\'avez ~r~pas assez~s~ d\'argent.',
-
+ ['bought'] = 'you just bought ~y~%sx~s~ ~b~%s~s~ for ~r~$%s~s~',
+ ['not_enough'] = 'vous n\'avez ~r~pas assez~s~ d\'argent: %s',
+ ['player_cannot_hold'] = 'you do ~r~not~s~ have enough ~y~free space~s~ in your inventory!',
+ ['shop_confirm'] = 'buy %sx %s for $%s?',
+ ['no'] = 'no',
+ ['yes'] = 'yes',
}
diff --git a/locales/sv.lua b/locales/sv.lua
index 5dfbf64b..294fb21e 100644
--- a/locales/sv.lua
+++ b/locales/sv.lua
@@ -1,8 +1,11 @@
Locales['sv'] = {
['shop'] = 'affär',
['shops'] = 'affärer',
- ['press_menu'] = 'tryck ~INPUT_CONTEXT~ för att ~y~handla prylar~w~.',
- ['bought'] = 'du har köpt ~y~1x~w~ ~b~%s~w~ för ~r~$%s~w~',
- ['not_enough'] = 'du har inte ~r~tillräckligt~s~ med pengar, det ~y~saknas~w~ ~r~$%s~w~!',
- ['player_cannot_hold'] = 'du har ~r~inte~w~ tillräckligt med ~y~utrymme~w~ för att hålla det!',
+ ['press_menu'] = 'tryck ~INPUT_CONTEXT~ för att ~y~handla prylar~s~.',
+ ['bought'] = 'du har köpt ~y~%sx~s~ ~b~%s~s~ för ~r~$%s~s~',
+ ['not_enough'] = 'du har inte ~r~tillräckligt~s~ med pengar, det ~y~saknas~s~ ~r~$%s~s~!',
+ ['player_cannot_hold'] = 'du har ~r~inte~s~ tillräckligt med ~y~utrymme~s~ för att hålla det!',
+ ['shop_confirm'] = 'köpa %sx %s för $%s?',
+ ['no'] = 'nej',
+ ['yes'] = 'ja',
}
\ No newline at end of file
diff --git a/server/main.lua b/server/main.lua
index 310a7b1c..f7099870 100644
--- a/server/main.lua
+++ b/server/main.lua
@@ -1,70 +1,97 @@
-ESX = nil
-local ItemsLabels = {}
+ESX = nil
+local ShopItems = {}
+local hasSqlRun = false
TriggerEvent('esx:getSharedObject', function(obj) ESX = obj end)
--- Load item labels
-Citizen.CreateThread(function()
- Citizen.Wait(5000)
-
- MySQL.Async.fetchAll(
- 'SELECT * FROM items',
- {},
- function(result)
- for i=1, #result, 1 do
- ItemsLabels[result[i].name] = result[i].label
- end
- end)
+-- Load items
+AddEventHandler('onMySQLReady', function()
+ hasSqlRun = true
+ LoadShop()
end)
-ESX.RegisterServerCallback('esx_shops:requestDBItems', function(source, cb)
+-- extremely useful when restarting script mid-game
+Citizen.CreateThread(function()
+ Citizen.Wait(20000) -- hopefully enough for connection to the SQL server
- MySQL.Async.fetchAll(
- 'SELECT * FROM shops',
- {},
- function(result)
- local shopItems = {}
- for i=1, #result, 1 do
- if shopItems[result[i].name] == nil then
- shopItems[result[i].name] = {}
- end
-
- table.insert(shopItems[result[i].name], {
- name = result[i].item,
- price = result[i].price,
- label = ItemsLabels[result[i].item]
- })
+ if not hasSqlRun then
+ LoadShop()
+ hasSqlRun = true
+ end
+end)
+
+function LoadShop()
+ local itemResult = MySQL.Sync.fetchAll('SELECT * FROM items')
+ local shopResult = MySQL.Sync.fetchAll('SELECT * FROM shops')
+
+ local itemInformation = {}
+ for i=1, #itemResult, 1 do
+ if itemInformation[itemResult[i].name] == nil then
+ itemInformation[itemResult[i].name] = {}
end
- cb(shopItems)
- end)
+
+ itemInformation[itemResult[i].name].label = itemResult[i].label
+ itemInformation[itemResult[i].name].limit = itemResult[i].limit
+ end
+
+ for i=1, #shopResult, 1 do
+ if ShopItems[shopResult[i].store] == nil then
+ ShopItems[shopResult[i].store] = {}
+ end
+
+ table.insert(ShopItems[shopResult[i].store], {
+ label = itemInformation[shopResult[i].item].label,
+ item = shopResult[i].item,
+ price = shopResult[i].price,
+ limit = itemInformation[shopResult[i].item].limit
+ })
+ end
+end
+
+ESX.RegisterServerCallback('esx_shops:requestDBItems', function(source, cb)
+ if not hasSqlRun then
+ TriggerClientEvent('esx:showNotification', source, 'The shop database has not been loaded yet, try again in a few moments.')
+ end
+
+ cb(ShopItems)
end)
RegisterServerEvent('esx_shops:buyItem')
-AddEventHandler('esx_shops:buyItem', function(itemName, price)
+AddEventHandler('esx_shops:buyItem', function(itemName, amount, zone)
local _source = source
local xPlayer = ESX.GetPlayerFromId(_source)
local sourceItem = xPlayer.getInventoryItem(itemName)
-
- -- is the player trying to cheat?
- if price < 0 then
- print('esx_shops: ' .. xPlayer.identifier .. ' attempted to cheat money!')
+
+ -- is the player trying to exploit?
+ if amount < 0 then
+ print('esx_shops: ' .. xPlayer.identifier .. ' attempted to exploit the shop!')
return
end
+ -- get price
+ local price = 0
+ local itemLabel = ''
+ for i=1, #ShopItems[zone], 1 do
+ if ShopItems[zone][i].item == itemName then
+ price = ShopItems[zone][i].price
+ itemLabel = ShopItems[zone][i].label
+ break
+ end
+ end
+ price = price * amount
+
-- can the player afford this item?
if xPlayer.getMoney() >= price then
-
-- can the player carry the said amount of x item?
- if sourceItem.limit ~= -1 and (sourceItem.count + 1) > sourceItem.limit then
+ if sourceItem.limit ~= -1 and (sourceItem.count + amount) > sourceItem.limit then
TriggerClientEvent('esx:showNotification', _source, _U('player_cannot_hold'))
else
xPlayer.removeMoney(price)
- xPlayer.addInventoryItem(itemName, 1)
- TriggerClientEvent('esx:showNotification', _source, _U('bought', ItemsLabels[itemName], price))
+ xPlayer.addInventoryItem(itemName, amount)
+ TriggerClientEvent('esx:showNotification', _source, _U('bought', amount, itemLabel, price))
end
else
local missingMoney = price - xPlayer.getMoney()
TriggerClientEvent('esx:showNotification', _source, _U('not_enough', missingMoney))
end
-
end)
\ No newline at end of file