570 lines
21 KiB
Lua
Raw Normal View History

2025-04-07 01:41:12 +00:00
local config = require 'config.client'
local sharedConfig = require 'config.shared'
local playerJob
local garbageVehicle
local hasBag = false
local currentStop = 0
local deliveryBlip
local amountOfBags = 0
local garbageObject
local endBlip
local garbageBlip
local canTakeBag = true
local currentStopNum = 0
local pZone
local garbageBinZone
local finished = false
local continueWorking = false
local garbText = false
local trucText = false
local pedsSpawned = false
local function setupClient()
garbageVehicle = nil
hasBag = false
currentStop = 0
deliveryBlip = nil
amountOfBags = 0
garbageObject = nil
endBlip = nil
currentStopNum = 0
if playerJob.name == 'garbage' then
garbageBlip = AddBlipForCoord(sharedConfig.locations.main.coords.x, sharedConfig.locations.main.coords.y, sharedConfig.locations.main.coords.z)
SetBlipSprite(garbageBlip, 318)
SetBlipDisplay(garbageBlip, 4)
SetBlipScale(garbageBlip, 1.0)
SetBlipAsShortRange(garbageBlip, true)
SetBlipColour(garbageBlip, 39)
BeginTextCommandSetBlipName('STRING')
AddTextComponentSubstringPlayerName(sharedConfig.locations.main.label)
EndTextCommandSetBlipName(garbageBlip)
end
end
local function garbageMenu()
local options = {}
options[#options + 1] = {
title = locale('menu.collect'),
description = locale('menu.return_collect'),
event = 'qb-garbagejob:client:RequestPaycheck'
}
if not garbageVehicle or finished then
options[#options + 1] = {
title = locale('menu.route'),
description = locale('menu.request_route'),
event = 'qb-garbagejob:client:RequestRoute'
}
end
lib.registerContext({
id = 'qb_gargabejob_mainMenu',
title = locale('menu.header'),
options = options
})
lib.showContext('qb_gargabejob_mainMenu')
end
local function BringBackCar()
DeleteVehicle(garbageVehicle)
if endBlip then
RemoveBlip(endBlip)
end
if deliveryBlip then
RemoveBlip(deliveryBlip)
end
garbageVehicle = nil
hasBag = false
currentStop = 0
deliveryBlip = nil
amountOfBags = 0
garbageObject = nil
endBlip = nil
currentStopNum = 0
end
local function DeleteZone()
pZone:remove()
end
local function SetRouteBack()
local depot = sharedConfig.locations.main.coords
endBlip = AddBlipForCoord(depot.x, depot.y, depot.z)
SetBlipSprite(endBlip, 1)
SetBlipDisplay(endBlip, 2)
SetBlipScale(endBlip, 1.0)
SetBlipAsShortRange(endBlip, false)
SetBlipColour(endBlip, 3)
BeginTextCommandSetBlipName('STRING')
AddTextComponentSubstringPlayerName(sharedConfig.locations.vehicle.label)
EndTextCommandSetBlipName(endBlip)
SetBlipRoute(endBlip, true)
DeleteZone()
finished = true
end
local function AnimCheck()
CreateThread(function()
while hasBag and not IsEntityPlayingAnim(cache.ped, 'missfbi4prepp1', '_bag_throw_garbage_man',3) do
if not IsEntityPlayingAnim(cache.ped, 'missfbi4prepp1', '_bag_walk_garbage_man', 3) then
ClearPedTasksImmediately(cache.ped)
lib.playAnim(cache.ped, 'missfbi4prepp1', '_bag_walk_garbage_man', 6.0, -6.0, -1, 49, 0, false, false, false)
end
Wait(1000)
end
end)
end
local function DeliverAnim()
lib.playAnim(cache.ped, 'missfbi4prepp1', '_bag_throw_garbage_man', 8.0, 8.0, 1100, 48, 0.0, false, false, false)
FreezeEntityPosition(cache.ped, true)
SetEntityHeading(cache.ped, GetEntityHeading(garbageVehicle))
canTakeBag = false
SetTimeout(1250, function()
DetachEntity(garbageObject, true, false)
DeleteObject(garbageObject)
lib.playAnim(cache.ped, 'missfbi4prepp1', 'exit', 8.0, 8.0, 1100, 48, 0.0, false, false, false)
FreezeEntityPosition(cache.ped, false)
garbageObject = nil
canTakeBag = true
end)
if config.useTarget and hasBag then
local CL = sharedConfig.locations.trashcan[currentStop]
hasBag = false
local pos = GetEntityCoords(cache.ped)
exports.ox_target:removeEntity(NetworkGetNetworkIdFromEntity(garbageVehicle), 'garbage_deliver')
if (amountOfBags - 1) <= 0 then
local hasMoreStops, nextStop, newBagAmount = lib.callback.await('garbagejob:server:nextStop', false, currentStop, currentStopNum, pos)
if hasMoreStops and nextStop ~= 0 then
-- Here he puts your next location and you are not finished working yet.
currentStop = nextStop
currentStopNum = currentStopNum + 1
amountOfBags = newBagAmount
SetGarbageRoute()
exports.qbx_core:Notify(locale('info.all_bags'))
SetVehicleDoorShut(garbageVehicle, 5, false)
else
if hasMoreStops and nextStop == currentStop then
exports.qbx_core:Notify(locale('info.depot_issue'))
amountOfBags = 0
else
-- You are done with work here.
exports.qbx_core:Notify(locale('info.done_working'))
SetVehicleDoorShut(garbageVehicle, 5, false)
RemoveBlip(deliveryBlip)
SetRouteBack()
amountOfBags = 0
end
end
else
-- You haven't delivered all bags here
amountOfBags = amountOfBags - 1
if amountOfBags > 1 then
exports.qbx_core:Notify(locale('info.bags_left', amountOfBags))
else
exports.qbx_core:Notify(locale('info.bags_still', amountOfBags))
end
garbageBinZone = exports.ox_target:addSphereZone({
coords = vec3(CL.coords.x, CL.coords.y, CL.coords.z),
radius = 2.0,
debug = config.debugPoly,
options = {
{
label = locale('target.grab_garbage'),
icon = 'fa-solid fa-trash',
onSelect = TakeAnim,
distance = 2.0,
canInteract = function()
return not hasBag
end,
},
},
})
end
end
end
function TakeAnim()
if lib.progressBar({
duration = math.random(3000, 5000),
label = locale('info.picking_bag'),
useWhileDead = false,
canCancel = true,
disable = {
car = true,
move = true,
combat = true,
mouse = false
},
anim = {
dict = 'anim@amb@clubhouse@tutorial@bkr_tut_ig3@',
clip = 'machinic_loop_mechandplayer'
}
}) then
lib.playAnim(cache.ped, 'missfbi4prepp1', '_bag_walk_garbage_man', 6.0, -6.0, -1, 49, 0, false, false, false)
lib.requestModel(`prop_cs_rub_binbag_01`, 10000)
garbageObject = CreateObject(`prop_cs_rub_binbag_01`, 0, 0, 0, true, true, true)
SetModelAsNoLongerNeeded(`prop_cs_rub_binbag_01`)
AttachEntityToEntity(garbageObject, cache.ped, GetPedBoneIndex(cache.ped, 57005), 0.12, 0.0, -0.05, 220.0, 120.0, 0.0, true, true, false, true, 1, true)
StopAnimTask(cache.ped, 'anim@amb@clubhouse@tutorial@bkr_tut_ig3@', 'machinic_loop_mechandplayer', 1.0)
AnimCheck()
if config.useTarget and not hasBag then
hasBag = true
if garbageBinZone then
exports.ox_target:removeZone(garbageBinZone)
garbageBinZone = nil
end
local options = {
{
name = 'garbage_deliver',
label = locale('target.dispose_garbage'),
icon = 'fa-solid fa-truck',
onSelect = DeliverAnim,
canInteract = function()
return hasBag
end,
},
}
exports.ox_target:addEntity(NetworkGetNetworkIdFromEntity(garbageVehicle), options)
end
else
StopAnimTask(cache.ped, 'anim@amb@clubhouse@tutorial@bkr_tut_ig3@', 'machinic_loop_mechandplayer', 1.0)
exports.qbx_core:Notify(locale('error.cancel'), 'error')
end
end
local function runWorkLoop()
local pos = GetEntityCoords(cache.ped)
local DeliveryData = sharedConfig.locations.trashcan[currentStop]
local Distance = #(pos - vec3(DeliveryData.coords.x, DeliveryData.coords.y, DeliveryData.coords.z))
if Distance < 15 or hasBag then
if not hasBag and canTakeBag then
if Distance < 1.5 then
if not garbText then
garbText = true
lib.showTextUI(locale('info.grab_garbage'))
end
if IsControlJustPressed(0, 51) then
hasBag = true
lib.hideTextUI()
TakeAnim()
end
elseif Distance < 10 then
if garbText then
garbText = false
lib.hideTextUI()
end
end
else
if DoesEntityExist(garbageVehicle) then
local Coords = GetOffsetFromEntityInWorldCoords(garbageVehicle, 0.0, -4.5, 0.0)
local TruckDist = #(pos - Coords)
if TruckDist < 2 then
if not trucText then
trucText = true
lib.showTextUI(locale('info.dispose_garbage'))
end
if IsControlJustPressed(0, 51) and hasBag then
StopAnimTask(cache.ped, 'missfbi4prepp1', '_bag_walk_garbage_man', 1.0)
DeliverAnim()
if lib.progressBar({
duration = 2000,
label = locale('info.progressbar'),
useWhileDead = false,
canCancel = true,
disable = {
car = true,
move = true,
combat = true,
mouse = false
}
}) then
hasBag = false
canTakeBag = false
DetachEntity(garbageObject, true, false)
DeleteObject(garbageObject)
FreezeEntityPosition(cache.ped, false)
garbageObject = nil
canTakeBag = true
-- Looks if you have delivered all bags
if (amountOfBags - 1) <= 0 then
local hasMoreStops, nextStop, newBagAmount = lib.callback.await(
'garbagejob:server:nextStop', false, currentStop, currentStopNum, pos)
if hasMoreStops and nextStop ~= 0 then
-- Here he puts your next location and you are not finished working yet.
currentStop = nextStop
currentStopNum = currentStopNum + 1
amountOfBags = newBagAmount
SetGarbageRoute()
exports.qbx_core:Notify(locale('info.all_bags'))
SetVehicleDoorShut(garbageVehicle, 5, false)
else
if hasMoreStops and nextStop == currentStop then
exports.qbx_core:Notify(locale('info.depot_issue'))
amountOfBags = 0
else
-- You are done with work here.
exports.qbx_core:Notify(locale('info.done_working'))
SetVehicleDoorShut(garbageVehicle, 5, false)
RemoveBlip(deliveryBlip)
SetRouteBack()
amountOfBags = 0
end
end
hasBag = false
else
-- You haven't delivered all bags here
amountOfBags = amountOfBags - 1
if amountOfBags > 1 then
exports.qbx_core:Notify(locale('info.bags_left', amountOfBags))
else
exports.qbx_core:Notify(locale('info.bags_still', amountOfBags))
end
hasBag = false
end
Wait(1500)
if trucText then
lib.hideTextUI()
trucText = false
end
else
exports.qbx_core:Notify(locale('error.cancel'), 'error')
end
end
end
else
exports.qbx_core:Notify(locale('error.no_truck'), 'error')
hasBag = false
end
end
end
end
local function CreateZone(x, y, z)
pZone = lib.zones.sphere({
coords = vec3(x, y, z),
radius = 15,
debug = config.debugPoly,
onEnter = function()
SetVehicleDoorOpen(garbageVehicle,5,false,false)
end,
inside = function()
if not config.useTarget then
runWorkLoop()
end
end,
onExit = function()
if not config.useTarget then
lib.hideTextUI()
end
SetVehicleDoorShut(garbageVehicle, 5, false)
end,
})
end
function SetGarbageRoute()
local CL = sharedConfig.locations.trashcan[currentStop]
if deliveryBlip then
RemoveBlip(deliveryBlip)
end
deliveryBlip = AddBlipForCoord(CL.coords.x, CL.coords.y, CL.coords.z)
SetBlipSprite(deliveryBlip, 1)
SetBlipDisplay(deliveryBlip, 2)
SetBlipScale(deliveryBlip, 1.0)
SetBlipAsShortRange(deliveryBlip, false)
SetBlipColour(deliveryBlip, 27)
BeginTextCommandSetBlipName('STRING')
AddTextComponentSubstringPlayerName(sharedConfig.locations.trashcan[currentStop].name)
EndTextCommandSetBlipName(deliveryBlip)
SetBlipRoute(deliveryBlip, true)
finished = false
if config.useTarget then
if not hasBag then
garbageBinZone = exports.ox_target:addSphereZone({
coords = vec3(CL.coords.x, CL.coords.y, CL.coords.z),
radius = 2.0,
debug = config.debugPoly,
options = {
{
label = locale('target.grab_garbage'),
icon = 'fa-solid fa-trash',
onSelect = TakeAnim,
canInteract = function()
return not hasBag
end,
distance = 2.0,
},
},
})
end
end
if pZone then
DeleteZone()
Wait(500)
CreateZone(CL.coords.x, CL.coords.y, CL.coords.z)
else
CreateZone(CL.coords.x, CL.coords.y, CL.coords.z)
end
end
local function spawnPeds()
if not config.peds or not next(config.peds) or pedsSpawned then return end
for i = 1, #config.peds do
local current = config.peds[i]
current.model = type(current.model) == 'string' and joaat(current.model) or current.model
lib.requestModel(current.model, 20000)
local ped = CreatePed(0, current.model, current.coords.x, current.coords.y, current.coords.z, current.coords.w, false, false)
SetModelAsNoLongerNeeded(current.model)
FreezeEntityPosition(ped, true)
SetEntityInvincible(ped, true)
SetBlockingOfNonTemporaryEvents(ped, true)
SetModelAsNoLongerNeeded(current.model)
current.pedHandle = ped
if config.useTarget then
exports.ox_target:addLocalEntity(ped, {
{
name = 'garbage_ped',
label = locale('target.talk'),
icon = 'fa-solid fa-recycle',
groups = 'garbage',
onSelect = garbageMenu,
}
})
else
lib.zones.box({
coords = vec3(current.coords.x, current.coords.y, current.coords.z+0.5),
size = vec3(3.0, 3.0, 2.0),
rotation = current.coords.w,
debug = config.debugPoly,
inside = function()
if IsControlJustPressed(0, 38) then
garbageMenu()
end
end,
onEnter = function()
lib.showTextUI(locale('info.talk'))
end,
onExit = function()
lib.hideTextUI()
end,
})
end
end
pedsSpawned = true
end
local function deletePeds()
if not config.peds or not next(config.peds) or not pedsSpawned then return end
for i = 1, #config.peds do
local current = config.peds[i]
if current.pedHandle then
if config.useTarget then
exports.ox_target:removeLocalEntity(current.pedHandle, 'garbage_ped')
end
DeletePed(current.pedHandle)
end
end
end
AddEventHandler('qb-garbagejob:client:RequestRoute', function()
if garbageVehicle then
continueWorking = true
TriggerServerEvent('garbagejob:server:payShift', continueWorking)
end
local shouldContinue, firstStop, totalBags = lib.callback.await('garbagejob:server:newShift', false, continueWorking)
if shouldContinue then
if not garbageVehicle then
local occupied = false
for _, v in pairs(sharedConfig.locations.vehicle.coords) do
if not IsAnyVehicleNearPoint(v.x,v.y,v.z, 2.5) then
local netId = lib.callback.await('garbagejob:server:spawnVehicle', false, v)
local veh = lib.waitFor(function()
if NetworkDoesEntityExistWithNetworkId(netId) then
return NetToVeh(netId)
end
end, 'Failed to spawn truck', 3000)
if veh == 0 then
lib.notify({ description = 'Failed to spawn truck', type = 'error' })
return
end
garbageVehicle = veh
SetVehicleFuelLevel(veh, 100.0)
SetVehicleFixed(veh)
currentStop = firstStop
currentStopNum = 1
amountOfBags = totalBags
SetGarbageRoute()
exports.qbx_core:Notify(locale('info.started'))
return
else
occupied = true
end
end
if occupied then
exports.qbx_core:Notify(locale('error.all_occupied'))
end
end
currentStop = firstStop
currentStopNum = 1
amountOfBags = totalBags
SetGarbageRoute()
else
exports.qbx_core:Notify(locale('info.not_enough', sharedConfig.truckPrice))
end
end)
AddEventHandler('qb-garbagejob:client:RequestPaycheck', function()
if garbageVehicle then
BringBackCar()
exports.qbx_core:Notify(locale('info.truck_returned'))
end
TriggerServerEvent('garbagejob:server:payShift')
end)
RegisterNetEvent('QBCore:Client:OnPlayerLoaded', function()
playerJob = QBX.PlayerData.job
setupClient()
spawnPeds()
end)
RegisterNetEvent('QBCore:Client:OnJobUpdate', function(JobInfo)
playerJob = JobInfo
if garbageBlip then
RemoveBlip(garbageBlip)
end
if endBlip then
RemoveBlip(endBlip)
end
if deliveryBlip then
RemoveBlip(deliveryBlip)
end
endBlip = nil
deliveryBlip = nil
setupClient()
spawnPeds()
end)
AddEventHandler('onResourceStop', function(resource)
if GetCurrentResourceName() == resource then
if garbageObject then
DeleteEntity(garbageObject)
garbageObject = nil
end
deletePeds()
end
end)
AddEventHandler('onResourceStart', function(resource)
if GetCurrentResourceName() == resource then
playerJob = QBX.PlayerData.job
setupClient()
spawnPeds()
end
end)