460 lines
15 KiB
Lua
460 lines
15 KiB
Lua
|
local QBCore = exports['qb-core']:GetCoreObject()
|
||
|
local marketItems = {}
|
||
|
local pendingOrders = {}
|
||
|
local availableLocations = {}
|
||
|
|
||
|
local function getMarketItems()
|
||
|
if not Config.randomItems then
|
||
|
for i=1, #Config.items do
|
||
|
local randomStock = math.random(Config.items[i].minStock, Config.items[i].maxStock)
|
||
|
marketItems[i] = Config.items[i]
|
||
|
marketItems[i].stock = randomStock
|
||
|
end
|
||
|
TriggerClientEvent("qb-blackmarket_cl:updateMarketItems", -1, marketItems)
|
||
|
SetTimeout(Config.reset * 60000, getMarketItems)
|
||
|
return
|
||
|
end
|
||
|
|
||
|
local copyTable = {}
|
||
|
for i=1, #Config.items do
|
||
|
copyTable[i] = Config.items[i]
|
||
|
end
|
||
|
|
||
|
local newLen = #copyTable
|
||
|
local chosenItems = {}
|
||
|
for i=1, Config.randomItems do
|
||
|
local randomIndex = math.random(newLen)
|
||
|
local randomStock = math.random(copyTable[randomIndex].minStock, copyTable[randomIndex].maxStock)
|
||
|
chosenItems[i] = copyTable[randomIndex]
|
||
|
chosenItems[i].stock = randomStock
|
||
|
table.remove(copyTable, randomIndex)
|
||
|
newLen -= 1
|
||
|
end
|
||
|
|
||
|
marketItems = chosenItems
|
||
|
|
||
|
TriggerClientEvent("qb-blackmarket_cl:updateMarketItems", -1, marketItems)
|
||
|
SetTimeout(Config.reset * 60000, getMarketItems)
|
||
|
end
|
||
|
|
||
|
local function isMarketItem(item)
|
||
|
local inMarket = false
|
||
|
for i=1, #marketItems do
|
||
|
if marketItems[i].item == item then
|
||
|
inMarket = true
|
||
|
break
|
||
|
end
|
||
|
end
|
||
|
|
||
|
return inMarket
|
||
|
end
|
||
|
|
||
|
local function checkStock(item, quantity)
|
||
|
local hasStock = false
|
||
|
for i=1, #marketItems do
|
||
|
if marketItems[i].item == item then
|
||
|
if marketItems[i].stock >= quantity then
|
||
|
hasStock = true
|
||
|
end
|
||
|
break
|
||
|
end
|
||
|
end
|
||
|
return hasStock
|
||
|
end
|
||
|
|
||
|
local function getItemPrice(item)
|
||
|
local price = 0
|
||
|
for i=1, #marketItems do
|
||
|
if marketItems[i].item == item then
|
||
|
price = marketItems[i].price
|
||
|
break
|
||
|
end
|
||
|
end
|
||
|
return price
|
||
|
end
|
||
|
|
||
|
local function updateMarketStock(item, quantity)
|
||
|
for i=1, #marketItems do
|
||
|
if marketItems[i].item == item then
|
||
|
marketItems[i].stock -= quantity
|
||
|
break
|
||
|
end
|
||
|
end
|
||
|
end
|
||
|
|
||
|
local function generateStashId()
|
||
|
local id = "GBM_"
|
||
|
for i=1, 6 do
|
||
|
id = id .. tostring(math.random(0,9))
|
||
|
end
|
||
|
return id
|
||
|
end
|
||
|
|
||
|
local function saveOrderStash(stashId, items, cb)
|
||
|
if not stashId or not items then return end
|
||
|
|
||
|
for _, item in pairs(items) do
|
||
|
item.description = nil
|
||
|
end
|
||
|
|
||
|
MySQL.insert('INSERT INTO stashitems (stash, items) VALUES (:stash, :items) ON DUPLICATE KEY UPDATE items = :items', {
|
||
|
['stash'] = stashId,
|
||
|
['items'] = json.encode(items)
|
||
|
}, function(id)
|
||
|
cb(id)
|
||
|
end)
|
||
|
end
|
||
|
|
||
|
local function deleteStash(stashId)
|
||
|
MySQL.query("DELETE FROM stashitems WHERE stash = ?", {stashId})
|
||
|
end
|
||
|
|
||
|
local function setupAvailableLocations()
|
||
|
for i=1, #Config.deliveryLocations do
|
||
|
availableLocations[#availableLocations + 1] = i
|
||
|
end
|
||
|
end
|
||
|
|
||
|
local function getRandomAvailLocation()
|
||
|
local chosenIndex = math.random(#availableLocations)
|
||
|
local locationIndex = availableLocations[chosenIndex]
|
||
|
table.remove(availableLocations, chosenIndex)
|
||
|
|
||
|
return locationIndex
|
||
|
end
|
||
|
|
||
|
local function orderComplete(index, stashId)
|
||
|
if not pendingOrders[index] or not pendingOrders[index].stashId == stashId then return end
|
||
|
|
||
|
if pendingOrders[index].props then
|
||
|
for _, v in pairs(pendingOrders[index].props) do
|
||
|
local entity = NetworkGetEntityFromNetworkId(v)
|
||
|
if DoesEntityExist(entity) then
|
||
|
DeleteEntity(entity)
|
||
|
end
|
||
|
end
|
||
|
end
|
||
|
|
||
|
if pendingOrders[index].isOpen then
|
||
|
TriggerClientEvent("qb-blackmarket_cl:removeLootTarget", -1, index)
|
||
|
else
|
||
|
TriggerClientEvent("qb-blackmarket_cl:removeLockTarget", -1, index)
|
||
|
end
|
||
|
|
||
|
deleteStash(pendingOrders[index].stashId)
|
||
|
|
||
|
|
||
|
if pendingOrders[index].src then
|
||
|
local Player = QBCore.Functions.GetPlayer(pendingOrders[index].src)
|
||
|
if Player.PlayerData.citizenid == pendingOrders[index].cid then
|
||
|
TriggerClientEvent("qb-blackmarket_cl:orderComplete", pendingOrders[index].src)
|
||
|
end
|
||
|
end
|
||
|
|
||
|
availableLocations[#availableLocations + 1] = index
|
||
|
pendingOrders[index] = nil
|
||
|
end
|
||
|
|
||
|
local function orderReady(index, stashId)
|
||
|
if pendingOrders[index].src then
|
||
|
local Player = QBCore.Functions.GetPlayer(pendingOrders[index].src)
|
||
|
if Player.PlayerData.citizenid == pendingOrders[index].cid then
|
||
|
TriggerClientEvent("qb-blackmarket_cl:orderReady", pendingOrders[index].src, index, Config.deliveryLocations[index])
|
||
|
end
|
||
|
end
|
||
|
|
||
|
SetTimeout(Config.orderTimeout * 60000, function()
|
||
|
orderComplete(index, stashId)
|
||
|
end)
|
||
|
end
|
||
|
|
||
|
local function cleanUpProps()
|
||
|
for _, v in pairs(pendingOrders) do
|
||
|
if v.props then
|
||
|
for _, prop in pairs(v.props) do
|
||
|
local entity = NetworkGetEntityFromNetworkId(prop)
|
||
|
if DoesEntityExist(entity) then
|
||
|
DeleteEntity(entity)
|
||
|
end
|
||
|
end
|
||
|
end
|
||
|
end
|
||
|
end
|
||
|
|
||
|
local function cleanUpStashes()
|
||
|
for _, v in pairs(pendingOrders) do
|
||
|
deleteStash(v.stashId)
|
||
|
end
|
||
|
end
|
||
|
|
||
|
QBCore.Functions.CreateUseableItem(Config.useItem, function(source)
|
||
|
local Player = QBCore.Functions.GetPlayer(source)
|
||
|
if not Player or not Player.Functions.GetItemByName(Config.useItem) then return end
|
||
|
TriggerClientEvent("qb-blackmarket_cl:openUI", source)
|
||
|
end)
|
||
|
|
||
|
QBCore.Functions.CreateCallback("qb-blackmarket_sv:getMarketItems", function(src, cb)
|
||
|
cb(marketItems)
|
||
|
end)
|
||
|
|
||
|
QBCore.Functions.CreateCallback("qb-blackmarket_sv:attemptOrder", function(src, cb, order)
|
||
|
if not order or #order == 0 then return end
|
||
|
local cost = 0
|
||
|
local Player = QBCore.Functions.GetPlayer(src)
|
||
|
if not Player or not Player.Functions.GetItemByName(Config.useItem) then return end
|
||
|
|
||
|
local numOfOrders = 0
|
||
|
for _, v in pairs(pendingOrders) do
|
||
|
if v.src == src or v.cid == cid then
|
||
|
cb({success = false, notif = "Ordre fejlet", error = "Spilleren har allerede en ordre"})
|
||
|
return
|
||
|
end
|
||
|
numOfOrders += 1
|
||
|
end
|
||
|
|
||
|
if numOfOrders >= Config.maxOrderQueue then
|
||
|
cb({success = false, notif = Config.notifText.maxOrder})
|
||
|
return
|
||
|
end
|
||
|
|
||
|
local playerOrder = {}
|
||
|
|
||
|
for i=1, #order do
|
||
|
local itemQuant = tonumber(order[i].quantity)
|
||
|
if not isMarketItem(order[i].item) then
|
||
|
cb({success = false, notif = "Ordre fejlet", error = "Ugyldig genstand fundet"})
|
||
|
return
|
||
|
end
|
||
|
|
||
|
if not checkStock(order[i].item, itemQuant) then
|
||
|
cb({success = false, notif = Config.notifText.insufficientStock})
|
||
|
return
|
||
|
end
|
||
|
|
||
|
if playerOrder[order[i].item] then
|
||
|
cb({success = false, notif = "Ordre fejlet", error = "Ordre har flere af samme genstand"})
|
||
|
return
|
||
|
end
|
||
|
|
||
|
playerOrder[order[i].item] = itemQuant
|
||
|
cost += getItemPrice(order[i].item) * itemQuant
|
||
|
end
|
||
|
|
||
|
if Player.Functions.RemoveMoney(Config.paymentType, cost) then
|
||
|
local locationIndex = getRandomAvailLocation()
|
||
|
local deliveryMins = math.random(Config.deliveryTime.min, Config.deliveryTime.max)
|
||
|
local deliveryTime = os.time() + (deliveryMins * 60)
|
||
|
local stashId = generateStashId()
|
||
|
|
||
|
pendingOrders[locationIndex] = {
|
||
|
src = src,
|
||
|
cid = Player.PlayerData.citizenid,
|
||
|
order = playerOrder,
|
||
|
deliveryTime = deliveryTime,
|
||
|
stashId = stashId,
|
||
|
lockInProgress = false,
|
||
|
lootInProgress = false,
|
||
|
isOpen = false,
|
||
|
isLooted = false,
|
||
|
}
|
||
|
|
||
|
for k,v in pairs(playerOrder) do
|
||
|
updateMarketStock(k, v)
|
||
|
end
|
||
|
|
||
|
SetTimeout(deliveryMins * 60000, function()
|
||
|
orderReady(locationIndex, stashId)
|
||
|
end)
|
||
|
|
||
|
TriggerClientEvent("qb-blackmarket_cl:updateStock", -1, marketItems, src)
|
||
|
cb({success = true, notif = Config.notifText.orderSuccess, epochTime = deliveryTime})
|
||
|
else
|
||
|
cb({success = false, notif = Config.notifText.cantAfford})
|
||
|
end
|
||
|
end)
|
||
|
|
||
|
RegisterNetEvent("qb-blackmarket_sv:propsSpawned", function(netIds, locationIndex)
|
||
|
if not pendingOrders[locationIndex] then return end
|
||
|
local lock = NetworkGetEntityFromNetworkId(netIds.lock)
|
||
|
local lockCoords = vec4(GetEntityCoords(lock), GetEntityHeading(lock))
|
||
|
pendingOrders[locationIndex].props = netIds
|
||
|
|
||
|
TriggerClientEvent("qb-blackmarket_cl:addLockTarget", -1, locationIndex, lockCoords)
|
||
|
end)
|
||
|
|
||
|
RegisterNetEvent("qb-blackmarket_sv:attemptContainer", function(index)
|
||
|
local src = source
|
||
|
if #(GetEntityCoords(GetPlayerPed(src)) - vec3(Config.deliveryLocations[index])) > 5 or not pendingOrders[index] then return end
|
||
|
|
||
|
if pendingOrders[index].lockInProgress then
|
||
|
TriggerClientEvent('QBCore:Notify', src, "Nogen er allerede igang med dette", "error")
|
||
|
return
|
||
|
end
|
||
|
|
||
|
if pendingOrders[index].isOpen then
|
||
|
TriggerClientEvent('QBCore:Notify', src, "Dette er allerede åbnet", "error")
|
||
|
return
|
||
|
end
|
||
|
|
||
|
pendingOrders[index].lockInProgress = true
|
||
|
TriggerClientEvent("qb-blackmarket_cl:openContainer", src, index, pendingOrders[index].props)
|
||
|
end)
|
||
|
|
||
|
RegisterNetEvent("qb-blackmarket_sv:openContainer", function(index)
|
||
|
local src = source
|
||
|
local crate = NetworkGetEntityFromNetworkId(pendingOrders[index].props.crate)
|
||
|
local crateCoords = vec4(GetEntityCoords(crate), GetEntityHeading(crate))
|
||
|
pendingOrders[index].lockInProgress = false
|
||
|
pendingOrders[index].isOpen = true
|
||
|
pendingOrders[index].props.lock = nil
|
||
|
|
||
|
TriggerClientEvent("qb-blackmarket_cl:updateOpenContainer", -1, index, pendingOrders[index].props.container, pendingOrders[index].props.collision, crateCoords, true)
|
||
|
end)
|
||
|
|
||
|
RegisterNetEvent("qb-blackmarket_sv:attemptLoot", function(index)
|
||
|
local src = source
|
||
|
if #(GetEntityCoords(GetPlayerPed(src)) - vec3(Config.deliveryLocations[index])) > 5 or not pendingOrders[index] then return end
|
||
|
|
||
|
if pendingOrders[index].lootInProgress then
|
||
|
TriggerClientEvent('QBCore:Notify', src, "Nogen er allerede igang med dette", "error")
|
||
|
return
|
||
|
end
|
||
|
|
||
|
if pendingOrders[index].isLooted then
|
||
|
TriggerClientEvent("inventory:client:SetCurrentStash", src, pendingOrders[index].stashId)
|
||
|
exports["ps-inventory"]:OpenInventory("stash", pendingOrders[index].stashId, nil, src)
|
||
|
return
|
||
|
end
|
||
|
|
||
|
pendingOrders[index].lootInProgress = true
|
||
|
TriggerClientEvent("qb-blackmarket_cl:lootContainer", src, index)
|
||
|
end)
|
||
|
|
||
|
RegisterNetEvent("qb-blackmarket_sv:finishLooting", function(index)
|
||
|
local src = source
|
||
|
if #(GetEntityCoords(GetPlayerPed(src)) - vec3(Config.deliveryLocations[index])) > 5 or not pendingOrders[index] or pendingOrders[index].isLooted then return end
|
||
|
|
||
|
local orderItems = {}
|
||
|
local stashId = pendingOrders[index].stashId
|
||
|
local slot = 1
|
||
|
for k, v in pairs(pendingOrders[index].order) do
|
||
|
local itemInfo = QBCore.Shared.Items[k:lower()]
|
||
|
if itemInfo then
|
||
|
itemInfo.info = {}
|
||
|
itemInfo.amount = v
|
||
|
itemInfo.slot = slot
|
||
|
-- If item has metedata add it here
|
||
|
if itemInfo.type == "weapon" then
|
||
|
itemInfo.info.serie = tostring(QBCore.Shared.RandomInt(2) .. QBCore.Shared.RandomStr(3) .. QBCore.Shared.RandomInt(1) .. QBCore.Shared.RandomStr(2) .. QBCore.Shared.RandomInt(3) .. QBCore.Shared.RandomStr(4))
|
||
|
itemInfo.info.quality = 100
|
||
|
end
|
||
|
orderItems[#orderItems + 1] = itemInfo
|
||
|
end
|
||
|
slot += 1
|
||
|
end
|
||
|
|
||
|
saveOrderStash(stashId, orderItems, function(id)
|
||
|
if id then
|
||
|
TriggerClientEvent("inventory:client:SetCurrentStash", src, stashId)
|
||
|
exports["ps-inventory"]:OpenInventory("stash", stashId, nil, src)
|
||
|
end
|
||
|
end)
|
||
|
|
||
|
pendingOrders[index].lootInProgress = false
|
||
|
pendingOrders[index].isLooted = true
|
||
|
|
||
|
SetTimeout(Config.lootTimeout * 60000, function()
|
||
|
orderComplete(index, stashId)
|
||
|
end)
|
||
|
end)
|
||
|
|
||
|
RegisterNetEvent("qb-blackmarket_sv:cancelLooting", function(index)
|
||
|
pendingOrders[index].lootInProgress = false
|
||
|
end)
|
||
|
|
||
|
RegisterNetEvent("qb-blackmarket_sv:initPendingOrders", function()
|
||
|
local src = source
|
||
|
local Player = QBCore.Functions.GetPlayer(src)
|
||
|
|
||
|
for k, v in pairs(pendingOrders) do
|
||
|
-- check if player has any pending orders
|
||
|
if v.cid == Player.PlayerData.citizenid then
|
||
|
v.src = src
|
||
|
TriggerClientEvent("qb-blackmarket_cl:hasPendingOrder", src, marketItems, v.order, v.deliveryTime)
|
||
|
-- create props if needed
|
||
|
local propDespawned = false
|
||
|
if v.props then
|
||
|
for prop, netId in pairs(v.props) do
|
||
|
local entity = NetworkGetEntityFromNetworkId(netId)
|
||
|
if not DoesEntityExist(entity) then
|
||
|
if not (v.isOpen and prop == "lock") then
|
||
|
propDespawned = true
|
||
|
end
|
||
|
end
|
||
|
end
|
||
|
end
|
||
|
|
||
|
if propDespawned then
|
||
|
for prop, netId in pairs(v.props) do
|
||
|
local entity = NetworkGetEntityFromNetworkId(netId)
|
||
|
if not DoesEntityExist(entity) then
|
||
|
DeleteEntity(entity)
|
||
|
end
|
||
|
end
|
||
|
v.props = nil
|
||
|
end
|
||
|
|
||
|
if os.time() - v.deliveryTime > 0 then
|
||
|
if not v.props then
|
||
|
-- removes targets since it gets recreated later
|
||
|
if v.isOpen then
|
||
|
TriggerClientEvent("qb-blackmarket_cl:removeLootTarget", -1, k)
|
||
|
v.isOpen = false
|
||
|
end
|
||
|
TriggerClientEvent("qb-blackmarket_cl:orderReady", src, k, Config.deliveryLocations[k])
|
||
|
else
|
||
|
TriggerClientEvent("qb-blackmarket_cl:enableLocateButton", src, k)
|
||
|
end
|
||
|
end
|
||
|
end
|
||
|
|
||
|
-- Create target zones for pending orders
|
||
|
if v.props then
|
||
|
if not v.isOpen then
|
||
|
local lock = NetworkGetEntityFromNetworkId(v.props.lock)
|
||
|
local lockCoords = vec4(GetEntityCoords(lock), GetEntityHeading(lock))
|
||
|
TriggerClientEvent("qb-blackmarket_cl:addLockTarget", src, k, lockCoords)
|
||
|
else
|
||
|
local crate = NetworkGetEntityFromNetworkId(v.props.crate)
|
||
|
local crateCoords = vec4(GetEntityCoords(crate), GetEntityHeading(crate))
|
||
|
|
||
|
TriggerClientEvent("qb-blackmarket_cl:updateOpenContainer", src, k, v.props.container, v.props.collision, crateCoords, false)
|
||
|
end
|
||
|
end
|
||
|
|
||
|
end
|
||
|
|
||
|
TriggerClientEvent("qb-blackmarket_cl:updateMarketItems", src, marketItems)
|
||
|
end)
|
||
|
|
||
|
|
||
|
AddEventHandler('playerDropped', function()
|
||
|
local src = source
|
||
|
for _, v in pairs(pendingOrders) do
|
||
|
if v.src == src then
|
||
|
v.src = nil
|
||
|
end
|
||
|
end
|
||
|
end)
|
||
|
|
||
|
AddEventHandler('onResourceStart', function(resource)
|
||
|
if resource ~= GetCurrentResourceName() then return end
|
||
|
getMarketItems()
|
||
|
setupAvailableLocations()
|
||
|
end)
|
||
|
|
||
|
AddEventHandler("onResourceStop", function(resource)
|
||
|
if resource ~= GetCurrentResourceName() then return end
|
||
|
cleanUpProps()
|
||
|
cleanUpStashes()
|
||
|
end)
|