2025-04-07 01:41:12 +00:00

428 lines
15 KiB
Lua

local config = require 'config.client'
local sharedConfig = require 'config.shared'
local currentDealer = nil
local dealerIsHome = false
local waitingDelivery = nil
local activeDelivery = nil
local deliveryTimeout = 0
local waitingKeyPress = false
local dealerCombo = false
local drugDeliveryZone
---@diagnostic disable-next-line: param-type-mismatch
AddStateBagChangeHandler('isLoggedIn', nil, function(_, _, value)
if value then
sharedConfig.dealers = lib.callback.await('qb-drugs:server:RequestConfig', false)
InitZones()
else
if not config.useTarget and dealerCombo then dealerCombo:destroy() end
end
end)
local function getClosestDealer()
local pCoords = GetEntityCoords(cache.ped)
for k, v in pairs(sharedConfig.dealers) do
local dealerCoords = vector3(v.coords.x, v.coords.y, v.coords.z)
if #(pCoords - dealerCoords) < 2 then
currentDealer = k
break
end
end
end
---@todo Move to ox_inventory Shop
local function openDealerShop()
getClosestDealer()
local repItems = {}
repItems.label = sharedConfig.dealers[currentDealer].name
repItems.items = {}
repItems.slots = 30
for k, _ in pairs(sharedConfig.dealers[currentDealer].products) do
if QBX.PlayerData.metadata.dealerrep >= sharedConfig.dealers[currentDealer].products[k].minrep then
repItems.items[k] = sharedConfig.dealers[currentDealer].products[k]
end
end
TriggerServerEvent('inventory:server:OpenInventory', 'shop', 'Dealer_'..sharedConfig.dealers[currentDealer].name, repItems)
end
local function knockDoorAnim(home)
local knockAnimLib = 'timetable@jimmy@doorknock@'
local knockAnim = 'knockdoor_idle'
if home then
TriggerServerEvent('InteractSound_SV:PlayOnSource', 'knock_door', 0.2)
Wait(100)
lib.playAnim(cache.ped, knockAnimLib, knockAnim, 3.0, 3.0, -1, 1, 0, false, false, false )
Wait(3500)
lib.playAnim(cache.ped, knockAnimLib, 'exit', 3.0, 3.0, -1, 1, 0, false, false, false)
Wait(1000)
dealerIsHome = true
TriggerEvent('chat:addMessage', {
color = { 255, 0, 0 },
multiline = true,
args = {
locale('info.dealer_name', sharedConfig.dealers[currentDealer].name),
locale('info.fred_knock_message', QBX.PlayerData.charinfo.firstname)
}
})
lib.showTextUI(locale('info.other_dealers_button'), { position = 'left-center' })
AwaitingInput()
else
TriggerServerEvent('InteractSound_SV:PlayOnSource', 'knock_door', 0.2)
Wait(100)
lib.playAnim(cache.ped, knockAnimLib, knockAnim, 3.0, 3.0, -1, 1, 0, false, false, false )
Wait(3500)
lib.playAnim(cache.ped, knockAnimLib, 'exit', 3.0, 3.0, -1, 1, 0, false, false, false)
Wait(1000)
exports.qbx_core:Notify(locale('info.no_one_home'), 'error')
end
end
local function knockDealerDoor()
getClosestDealer()
local hours = GetClockHours()
local min = sharedConfig.dealers[currentDealer].time.min
local max = sharedConfig.dealers[currentDealer].time.max
if max < min then
if hours <= max then
knockDoorAnim(true)
elseif hours >= min then
knockDoorAnim(true)
else
knockDoorAnim(false)
end
else
if hours >= min and hours <= max then
knockDoorAnim(true)
else
knockDoorAnim(false)
end
end
end
local function randomDeliveryItemOnRep()
local myRep = QBX.PlayerData.metadata.dealerrep
local availableItems = {}
for k in pairs(sharedConfig.deliveryItems) do
if sharedConfig.deliveryItems[k].minrep <= myRep then
availableItems[#availableItems+1] = k
end
end
return availableItems[math.random(1, #availableItems)]
end
local function requestDelivery()
if not waitingDelivery then
getClosestDealer()
local location = math.random(1, #config.deliveryLocations)
local amount = math.random(1, 3)
local item = randomDeliveryItemOnRep()
waitingDelivery = {
coords = config.deliveryLocations[location].coords,
locationLabel = config.deliveryLocations[location].label,
amount = amount,
dealer = currentDealer,
itemData = sharedConfig.deliveryItems[item],
item = item
}
exports.qbx_core:Notify(locale('info.sending_delivery_email'), 'success')
TriggerServerEvent('qb-drugs:server:giveDeliveryItems', waitingDelivery)
SetTimeout(2000, function()
TriggerServerEvent('qb-phone:server:sendNewMail', {
sender = sharedConfig.dealers[currentDealer].name,
subject = 'Delivery Location',
message = locale('info.delivery_info_email', amount, exports.ox_inventory:Items()[waitingDelivery.itemData.item].label),
button = {
enabled = true,
buttonEvent = 'qb-drugs:client:setLocation',
buttonData = waitingDelivery
}
})
end)
else
exports.qbx_core:Notify(locale('error.pending_delivery'), 'error')
end
end
local function deliveryTimer()
CreateThread(function()
while deliveryTimeout - 1 > 0 do
deliveryTimeout -= 1
Wait(1000)
end
deliveryTimeout = 0
end)
end
local function deliverStuff()
if deliveryTimeout > 0 then
Wait(500)
TriggerEvent('animations:client:EmoteCommandStart', {'bumbin'})
TriggerServerEvent('qb-drugs:server:randomPoliceAlert')
if lib.progressCircle({
label = locale('info.delivering_products'),
duration = 3500,
position = 'bottom',
useWhileDead = false,
canCancel = true,
disable = { car = true, move = true, combat = true }
}) then
TriggerServerEvent('qb-drugs:server:successDelivery', activeDelivery, true)
activeDelivery = nil
if config.useTarget then
exports.ox_target:removeZone('drugDeliveryZone')
else
drugDeliveryZone:destroy()
end
else
ClearPedTasks(cache.ped)
end
else
TriggerServerEvent('qb-drugs:server:successDelivery', activeDelivery, false)
end
deliveryTimeout = 0
end
local function setMapBlip(x, y)
SetNewWaypoint(x, y)
exports.qbx_core:Notify(locale('success.route_has_been_set'), 'success');
end
-- PolyZone specific functions
function AwaitingInput()
CreateThread(function()
waitingKeyPress = true
while waitingKeyPress do
if not dealerIsHome then
if IsControlPressed(0, 38) then
knockDealerDoor()
end
elseif dealerIsHome then
if IsControlJustPressed(0, 38) then
openDealerShop()
waitingKeyPress = false
end
if IsControlJustPressed(0, 47) then
if waitingDelivery then
waitingKeyPress = false
end
requestDelivery()
dealerIsHome = false
waitingKeyPress = false
end
end
Wait(0)
end
end)
end
function InitZones()
if config.useTarget then
for k, v in pairs(sharedConfig.dealers) do
---@todo Move to ox_target
exports['qb-target']:AddBoxZone('dealer_'..k, vector3(v.coords.x, v.coords.y, v.coords.z), 1.5, 1.5, {
name = 'dealer_'..k,
heading = v.heading,
minZ = v.coords.z - 1,
maxZ = v.coords.z + 1,
debugPoly = false,
}, {
options = {
{
icon = 'fas fa-user-secret',
label = locale('info.target_request'),
action = function()
requestDelivery()
end,
canInteract = function()
getClosestDealer()
local hours = GetClockHours()
local min = sharedConfig.dealers[currentDealer].time.min
local max = sharedConfig.dealers[currentDealer].time.max
if max < min then
if hours <= max then
if not waitingDelivery then
return true
end
elseif hours >= min then
if not waitingDelivery then
return true
end
end
else
if hours >= min and hours <= max then
if not waitingDelivery then
return true
end
end
end
end
},
{
icon = 'fas fa-user-secret',
label = locale('info.target_openshop'),
action = function()
openDealerShop()
end,
canInteract = function()
getClosestDealer()
local hours = GetClockHours()
local min = sharedConfig.dealers[currentDealer].time.min
local max = sharedConfig.dealers[currentDealer].time.max
if max < min then
if hours <= max then
return true
elseif hours >= min then
return true
end
else
if hours >= min and hours <= max then
return true
end
end
end
}
},
distance = 1.5
})
end
else
---@TODO Move to ox_lib Zoning
--[[ local dealerPoly = {}
for k, v in pairs(sharedConfig.dealers) do
dealerPoly[#dealerPoly+1] = BoxZone:Create(vector3(v.coords.x, v.coords.y, v.coords.z), 1.5, 1.5, {
heading = -20,
name='dealer_'..k,
debugPoly = false,
minZ = v.coords.z - 1,
maxZ = v.coords.z + 1,
})
end
if table.type(dealerPoly) == 'empty' then return end
dealerCombo = ComboZone:Create(dealerPoly, {name = 'dealerPoly'})
dealerCombo:onPlayerInOut(function(isPointInside)
if isPointInside then
if not dealerIsHome then
lib.showTextUI(locale('info.knock_button'), { position = 'left-center' })
AwaitingInput()
elseif dealerIsHome then
lib.showTextUI(locale('info.other_dealers_button'), { position = 'left-center' })
AwaitingInput()
end
else
waitingKeyPress = false
lib.hideTextUI()
end
end) ]]--
return
end
end
-- Events
RegisterNetEvent('qb-drugs:client:RefreshDealers', function(DealerData)
if not config.useTarget and dealerCombo then dealerCombo:destroy() end
sharedConfig.dealers = DealerData
Wait(1000)
InitZones()
end)
RegisterNetEvent('qb-drugs:client:updateDealerItems', function(itemData, amount)
TriggerServerEvent('qb-drugs:server:updateDealerItems', itemData, amount, currentDealer)
end)
RegisterNetEvent('qb-drugs:client:setDealerItems', function(itemData, amount, dealer)
sharedConfig.dealers[dealer].products[itemData.slot].amount = sharedConfig.dealers[dealer].products[itemData.slot].amount - amount
end)
RegisterNetEvent('qb-drugs:client:setLocation', function(locationData)
if activeDelivery then
setMapBlip(activeDelivery.coords.x, activeDelivery.coords.y)
exports.qbx_core:Notify(locale('error.pending_delivery'), 'error')
return
end
activeDelivery = locationData
deliveryTimeout = 300
deliveryTimer()
setMapBlip(activeDelivery.coords.x, activeDelivery.coords.y)
if config.useTarget then
exports.ox_target:addBoxZone({
name = 'drugDeliveryZone',
coords = vec3(activeDelivery.coords.x, activeDelivery.coords.y, activeDelivery.coords.z),
size = vec3(1.5, 1.5, 2.0),
rotation = 0.0,
debug = true,
options = {
{
icon = 'fas fa-user-secret',
label = locale('info.target_deliver'),
onSelect = function()
deliverStuff()
waitingDelivery = nil
end,
canInteract = function(_, distance)
return waitingDelivery and distance <= 2.5
end
}
}
})
else
local inDeliveryZone = false
drugDeliveryZone = lib.zones.box({
coords = vec3(activeDelivery.coords.xyz),
size = vec3(1.5, 1.5, 2.0),
rotation = 0.0,
debug = false,
onEnter = function()
inDeliveryZone = true
lib.showTextUI(locale('info.deliver_items_button', activeDelivery.amount, exports.ox_inventory:Items()[activeDelivery.itemData.item].label), {
position = 'left-center'
})
CreateThread(function()
while inDeliveryZone do
if IsControlJustPressed(0, 38) then
deliverStuff()
waitingDelivery = nil
break
end
Wait(0)
end
end)
end,
onExit = function()
inDeliveryZone = false
lib.hideTextUI()
end
})
end
end)
RegisterNetEvent('qb-drugs:client:sendDeliveryMail', function(type, deliveryData)
if type == 'perfect' then
TriggerServerEvent('qb-phone:server:sendNewMail', {
sender = sharedConfig.dealers[deliveryData.dealer].name,
subject = 'Delivery',
message = locale('info.perfect_delivery', sharedConfig.dealers[deliveryData.dealer].name)
})
elseif type == 'bad' then
TriggerServerEvent('qb-phone:server:sendNewMail', {
sender = sharedConfig.dealers[deliveryData.dealer].name,
subject = 'Delivery',
message = locale('info.bad_delivery')
})
elseif type == 'late' then
TriggerServerEvent('qb-phone:server:sendNewMail', {
sender = sharedConfig.dealers[deliveryData.dealer].name,
subject = 'Delivery',
message = locale('info.late_delivery')
})
end
end)