552 lines
23 KiB
Lua
552 lines
23 KiB
Lua
local QBCore = exports['qb-core']:GetCoreObject()
|
|
local garbageVehicle = nil
|
|
local hasBag = false
|
|
local currentStop = 0
|
|
local deliveryBlip = nil
|
|
local amountOfBags = 0
|
|
local garbageObject = nil
|
|
local endBlip = nil
|
|
local garbageBlip = nil
|
|
local canTakeBag = true
|
|
local currentStopNum = 0
|
|
local PZone = nil
|
|
local listen = false
|
|
local finished = false
|
|
local continueworking = false
|
|
local playerJob = {}
|
|
-- Handlers
|
|
|
|
-- Functions
|
|
|
|
local function setupClient()
|
|
garbageVehicle = nil
|
|
hasBag = false
|
|
currentStop = 0
|
|
deliveryBlip = nil
|
|
amountOfBags = 0
|
|
garbageObject = nil
|
|
endBlip = nil
|
|
currentStopNum = 0
|
|
if playerJob.name == Config.Jobname then
|
|
garbageBlip = AddBlipForCoord(Config.Locations["main"].coords.x, Config.Locations["main"].coords.y, Config.Locations["main"].coords.z)
|
|
SetBlipSprite(garbageBlip, 318)
|
|
SetBlipDisplay(garbageBlip, 4)
|
|
SetBlipScale(garbageBlip, 1.0)
|
|
SetBlipAsShortRange(garbageBlip, true)
|
|
SetBlipColour(garbageBlip, 39)
|
|
BeginTextCommandSetBlipName("STRING")
|
|
AddTextComponentSubstringPlayerName(Config.Locations["main"].label)
|
|
EndTextCommandSetBlipName(garbageBlip)
|
|
end
|
|
end
|
|
|
|
|
|
|
|
local function LoadAnimation(dict)
|
|
RequestAnimDict(dict)
|
|
while not HasAnimDictLoaded(dict) do Wait(10) end
|
|
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()
|
|
listen = false
|
|
PZone:destroy()
|
|
end
|
|
|
|
local function SetRouteBack()
|
|
local depot = Config.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(Config.Locations["vehicle"].label)
|
|
EndTextCommandSetBlipName(endBlip)
|
|
SetBlipRoute(endBlip, true)
|
|
DeleteZone()
|
|
finished = true
|
|
end
|
|
|
|
local function AnimCheck()
|
|
CreateThread(function()
|
|
local ped = PlayerPedId()
|
|
while hasBag and not IsEntityPlayingAnim(ped, 'missfbi4prepp1', '_bag_throw_garbage_man',3) do
|
|
if not IsEntityPlayingAnim(ped, 'missfbi4prepp1', '_bag_walk_garbage_man', 3) then
|
|
ClearPedTasksImmediately(ped)
|
|
LoadAnimation('missfbi4prepp1')
|
|
TaskPlayAnim(ped, 'missfbi4prepp1', '_bag_walk_garbage_man', 6.0, -6.0, -1, 49, 0, 0, 0, 0)
|
|
end
|
|
Wait(1000)
|
|
end
|
|
end)
|
|
end
|
|
|
|
local function DeliverAnim()
|
|
local ped = PlayerPedId()
|
|
LoadAnimation('missfbi4prepp1')
|
|
TaskPlayAnim(ped, 'missfbi4prepp1', '_bag_throw_garbage_man', 8.0, 8.0, 1100, 48, 0.0, 0, 0, 0)
|
|
FreezeEntityPosition(ped, true)
|
|
SetEntityHeading(ped, GetEntityHeading(garbageVehicle))
|
|
canTakeBag = false
|
|
SetTimeout(1250, function()
|
|
DetachEntity(garbageObject, 1, false)
|
|
DeleteObject(garbageObject)
|
|
TaskPlayAnim(ped, 'missfbi4prepp1', 'exit', 8.0, 8.0, 1100, 48, 0.0, 0, 0, 0)
|
|
FreezeEntityPosition(ped, false)
|
|
garbageObject = nil
|
|
canTakeBag = true
|
|
end)
|
|
if Config.UseTarget and hasBag then
|
|
local CL = Config.Locations["trashcan"][currentStop]
|
|
hasBag = false
|
|
local pos = GetEntityCoords(ped)
|
|
exports['qb-target']:RemoveTargetEntity(garbageVehicle)
|
|
if (amountOfBags - 1) <= 0 then
|
|
QBCore.Functions.TriggerCallback('garbagejob:server:NextStop', function(hasMoreStops, nextStop, newBagAmount)
|
|
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()
|
|
QBCore.Functions.Notify(Lang:t("info.all_bags"))
|
|
SetVehicleDoorShut(garbageVehicle, 5, false)
|
|
else
|
|
if hasMoreStops and nextStop == currentStop then
|
|
QBCore.Functions.Notify(Lang:t("info.depot_issue"))
|
|
amountOfBags = 0
|
|
else
|
|
-- You are done with work here.
|
|
QBCore.Functions.Notify(Lang:t("info.done_working"))
|
|
SetVehicleDoorShut(garbageVehicle, 5, false)
|
|
RemoveBlip(deliveryBlip)
|
|
SetRouteBack()
|
|
amountOfBags = 0
|
|
end
|
|
end
|
|
end, currentStop, currentStopNum, pos)
|
|
else
|
|
-- You haven't delivered all bags here
|
|
amountOfBags = amountOfBags - 1
|
|
if amountOfBags > 1 then
|
|
QBCore.Functions.Notify(Lang:t("info.bags_left", { value = amountOfBags }))
|
|
else
|
|
QBCore.Functions.Notify(Lang:t("info.bags_still", { value = amountOfBags }))
|
|
end
|
|
exports['qb-target']:AddCircleZone('garbagebin', vector3(CL.coords.x, CL.coords.y, CL.coords.z), 2.0,{
|
|
name = 'garbagebin', debugPoly = false, useZ=true}, {
|
|
options = {{label = Lang:t("target.grab_garbage"),icon = 'fa-solid fa-trash', action = function() TakeAnim() end}},
|
|
distance = 2.0
|
|
})
|
|
end
|
|
end
|
|
end
|
|
|
|
function TakeAnim()
|
|
local ped = PlayerPedId()
|
|
QBCore.Functions.Progressbar("bag_pickup", Lang:t("info.picking_bag"), math.random(3000, 5000), false, true, {
|
|
disableMovement = true,
|
|
disableCarMovement = true,
|
|
disableMouse = false,
|
|
disableCombat = true,
|
|
}, {
|
|
animDict = "anim@amb@clubhouse@tutorial@bkr_tut_ig3@",
|
|
anim = "machinic_loop_mechandplayer",
|
|
flags = 16,
|
|
}, {}, {}, function()
|
|
LoadAnimation('missfbi4prepp1')
|
|
TaskPlayAnim(ped, 'missfbi4prepp1', '_bag_walk_garbage_man', 6.0, -6.0, -1, 49, 0, 0, 0, 0)
|
|
garbageObject = CreateObject(`prop_cs_rub_binbag_01`, 0, 0, 0, true, true, true)
|
|
AttachEntityToEntity(garbageObject, ped, GetPedBoneIndex(ped, 57005), 0.12, 0.0, -0.05, 220.0, 120.0, 0.0, true, true, false, true, 1, true)
|
|
StopAnimTask(PlayerPedId(), "anim@amb@clubhouse@tutorial@bkr_tut_ig3@", "machinic_loop_mechandplayer", 1.0)
|
|
AnimCheck()
|
|
if Config.UseTarget and not hasBag then
|
|
hasBag = true
|
|
exports['qb-target']:RemoveZone("garbagebin")
|
|
exports['qb-target']:AddTargetEntity(garbageVehicle, {
|
|
options = {
|
|
{label = Lang:t("target.dispose_garbage"),icon = 'fa-solid fa-truck',action = function() DeliverAnim() end,canInteract = function() if hasBag then return true end return false end, }
|
|
},
|
|
distance = 2.0
|
|
})
|
|
end
|
|
end, function()
|
|
StopAnimTask(PlayerPedId(), "anim@amb@clubhouse@tutorial@bkr_tut_ig3@", "machinic_loop_mechandplayer", 1.0)
|
|
QBCore.Functions.Notify(Lang:t("error.cancled"), "error")
|
|
end)
|
|
end
|
|
|
|
local function RunWorkLoop()
|
|
CreateThread(function()
|
|
local GarbText = false
|
|
while listen do
|
|
local ped = PlayerPedId()
|
|
local pos = GetEntityCoords(ped)
|
|
local DeliveryData = Config.Locations["trashcan"][currentStop]
|
|
local Distance = #(pos - vector3(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
|
|
exports['qb-core']:DrawText(Lang:t("info.grab_garbage"), 'top')
|
|
end
|
|
if IsControlJustPressed(0, 51) then
|
|
hasBag = true
|
|
exports['qb-core']:HideText()
|
|
TakeAnim()
|
|
end
|
|
elseif Distance < 10 then
|
|
if GarbText then
|
|
GarbText = false
|
|
exports['qb-core']:HideText()
|
|
end
|
|
end
|
|
else
|
|
if DoesEntityExist(garbageVehicle) then
|
|
local Coords = GetOffsetFromEntityInWorldCoords(garbageVehicle, 0.0, -4.5, 0.0)
|
|
local TruckDist = #(pos - Coords)
|
|
local TrucText = false
|
|
|
|
if TruckDist < 2 then
|
|
if not TrucText then
|
|
TrucText = true
|
|
exports['qb-core']:DrawText(Lang:t("info.dispose_garbage"), 'top')
|
|
end
|
|
if IsControlJustPressed(0, 51) and hasBag then
|
|
StopAnimTask(PlayerPedId(), 'missfbi4prepp1', '_bag_walk_garbage_man', 1.0)
|
|
DeliverAnim()
|
|
QBCore.Functions.Progressbar("deliverbag", Lang:t("info.progressbar"), 2000, false, true, {
|
|
disableMovement = true,
|
|
disableCarMovement = true,
|
|
disableMouse = false,
|
|
disableCombat = true,
|
|
}, {}, {}, {}, function() -- Done
|
|
hasBag = false
|
|
canTakeBag = false
|
|
DetachEntity(garbageObject, 1, false)
|
|
DeleteObject(garbageObject)
|
|
FreezeEntityPosition(ped, false)
|
|
garbageObject = nil
|
|
canTakeBag = true
|
|
-- Looks if you have delivered all bags
|
|
if (amountOfBags - 1) <= 0 then
|
|
QBCore.Functions.TriggerCallback('garbagejob:server:NextStop', function(hasMoreStops, nextStop, newBagAmount)
|
|
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()
|
|
QBCore.Functions.Notify(Lang:t("info.all_bags"))
|
|
listen = false
|
|
SetVehicleDoorShut(garbageVehicle, 5, false)
|
|
else
|
|
if hasMoreStops and nextStop == currentStop then
|
|
QBCore.Functions.Notify(Lang:t("info.depot_issue"))
|
|
amountOfBags = 0
|
|
else
|
|
-- You are done with work here.
|
|
QBCore.Functions.Notify(Lang:t("info.done_working"))
|
|
SetVehicleDoorShut(garbageVehicle, 5, false)
|
|
RemoveBlip(deliveryBlip)
|
|
SetRouteBack()
|
|
amountOfBags = 0
|
|
listen = false
|
|
end
|
|
end
|
|
end, currentStop, currentStopNum, pos)
|
|
hasBag = false
|
|
else
|
|
-- You haven't delivered all bags here
|
|
amountOfBags = amountOfBags - 1
|
|
if amountOfBags > 1 then
|
|
QBCore.Functions.Notify(Lang:t("info.bags_left", { value = amountOfBags }))
|
|
else
|
|
QBCore.Functions.Notify(Lang:t("info.bags_still", { value = amountOfBags }))
|
|
end
|
|
hasBag = false
|
|
end
|
|
|
|
Wait(1500)
|
|
if TrucText then
|
|
exports['qb-core']:HideText()
|
|
TrucText = false
|
|
end
|
|
end, function() -- Cancel
|
|
QBCore.Functions.Notify(Lang:t("error.cancled"), "error")
|
|
end)
|
|
|
|
end
|
|
end
|
|
else
|
|
QBCore.Functions.Notify(Lang:t("error.no_truck"), "error")
|
|
hasBag = false
|
|
end
|
|
end
|
|
end
|
|
Wait(1)
|
|
end
|
|
end)
|
|
end
|
|
|
|
local function CreateZone(x, y, z)
|
|
CreateThread(function()
|
|
PZone = CircleZone:Create(vector3(x, y, z), 15.0, {
|
|
name = "NewRouteWhoDis",
|
|
debugPoly = false,
|
|
})
|
|
|
|
PZone:onPlayerInOut(function(isPointInside)
|
|
if isPointInside then
|
|
if not Config.UseTarget then
|
|
listen = true
|
|
RunWorkLoop()
|
|
end
|
|
SetVehicleDoorOpen(garbageVehicle,5,false,false)
|
|
else
|
|
if not Config.UseTarget then
|
|
exports['qb-core']:HideText()
|
|
listen = false
|
|
end
|
|
SetVehicleDoorShut(garbageVehicle, 5, false)
|
|
end
|
|
end)
|
|
end)
|
|
end
|
|
|
|
function SetGarbageRoute()
|
|
local CL = Config.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(Config.Locations["trashcan"][currentStop].name)
|
|
EndTextCommandSetBlipName(deliveryBlip)
|
|
SetBlipRoute(deliveryBlip, true)
|
|
finished = false
|
|
if Config.UseTarget and not hasBag then
|
|
exports['qb-target']:AddCircleZone('garbagebin', vector3(CL.coords.x, CL.coords.y, CL.coords.z), 2.0,{
|
|
name = 'garbagebin', debugPoly = false, useZ=true }, {
|
|
options = {{label = Lang:t("target.grab_garbage"), icon = 'fa-solid fa-trash', action = function() TakeAnim() end }},
|
|
distance = 2.0
|
|
})
|
|
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 ControlListen = false
|
|
local function Listen4Control()
|
|
ControlListen = true
|
|
CreateThread(function()
|
|
while ControlListen do
|
|
if IsControlJustReleased(0, 38) then
|
|
TriggerEvent("qb-garbagejob:client:MainMenu")
|
|
end
|
|
Wait(1)
|
|
end
|
|
end)
|
|
end
|
|
|
|
local pedsSpawned = false
|
|
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 GetHashKey(current.model) or current.model
|
|
RequestModel(current.model)
|
|
while not HasModelLoaded(current.model) do
|
|
Wait(0)
|
|
end
|
|
local ped = CreatePed(0, current.model, current.coords, false, false)
|
|
FreezeEntityPosition(ped, true)
|
|
SetEntityInvincible(ped, true)
|
|
SetBlockingOfNonTemporaryEvents(ped, true)
|
|
current.pedHandle = ped
|
|
|
|
if Config.UseTarget then
|
|
exports['qb-target']:AddTargetEntity(ped, {
|
|
options = {{type = "client", event = "qb-garbagejob:client:MainMenu", label = Lang:t("target.talk"), icon = 'fa-solid fa-recycle', job = "garbage",}},
|
|
distance = 2.0
|
|
})
|
|
else
|
|
local options = current.zoneOptions
|
|
if options then
|
|
local zone = BoxZone:Create(current.coords.xyz, options.length, options.width, {
|
|
name = "zone_cityhall_" .. ped,
|
|
heading = current.coords.w,
|
|
debugPoly = false
|
|
})
|
|
zone:onPlayerInOut(function(inside)
|
|
if LocalPlayer.state.isLoggedIn then
|
|
if inside then
|
|
exports['qb-core']:DrawText(Lang:t("info.talk"), 'top')
|
|
Listen4Control()
|
|
else
|
|
ControlListen = false
|
|
exports['qb-core']:HideText()
|
|
end
|
|
end
|
|
end)
|
|
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
|
|
DeletePed(current.pedHandle)
|
|
end
|
|
end
|
|
end
|
|
|
|
-- Events
|
|
|
|
RegisterNetEvent('garbagejob:client:SetWaypointHome', function()
|
|
SetNewWaypoint(Config.Locations["main"].coords.x, Config.Locations["main"].coords.y)
|
|
end)
|
|
|
|
RegisterNetEvent('qb-garbagejob:client:RequestRoute', function()
|
|
if garbageVehicle then continueworking = true TriggerServerEvent('garbagejob:server:PayShift', continueworking) end
|
|
QBCore.Functions.TriggerCallback('garbagejob:server:NewShift', function(shouldContinue, firstStop, totalBags)
|
|
if shouldContinue then
|
|
if not garbageVehicle then
|
|
local occupied = false
|
|
for _,v in pairs(Config.Locations["vehicle"].coords) do
|
|
if not IsAnyVehicleNearPoint(vector3(v.x,v.y,v.z), 2.5) then
|
|
QBCore.Functions.TriggerCallback('QBCore:Server:SpawnVehicle', function(netId)
|
|
local veh = NetToVeh(netId)
|
|
SetVehicleEngineOn(veh, false, true)
|
|
garbageVehicle = veh
|
|
SetVehicleNumberPlateText(veh, "QB-" .. tostring(math.random(1000, 9999)))
|
|
SetEntityHeading(veh, v.w)
|
|
exports['qb-fuel']:SetFuel(veh, 100.0)
|
|
SetVehicleFixed(veh)
|
|
SetEntityAsMissionEntity(veh, true, true)
|
|
SetVehicleDoorsLocked(veh, 2)
|
|
currentStop = firstStop
|
|
currentStopNum = 1
|
|
amountOfBags = totalBags
|
|
SetGarbageRoute()
|
|
TriggerEvent("vehiclekeys:client:SetOwner", QBCore.Functions.GetPlate(veh))
|
|
QBCore.Functions.Notify(Lang:t("info.deposit_paid", { value = Config.TruckPrice }))
|
|
QBCore.Functions.Notify(Lang:t("info.started"))
|
|
TriggerServerEvent("qb-garbagejob:server:payDeposit")
|
|
end, Config.Vehicle, v, false)
|
|
return
|
|
else
|
|
occupied = true
|
|
end
|
|
end
|
|
if occupied then
|
|
QBCore.Functions.Notify(Lang:t("error.all_occupied"))
|
|
end
|
|
end
|
|
currentStop = firstStop
|
|
currentStopNum = 1
|
|
amountOfBags = totalBags
|
|
SetGarbageRoute()
|
|
else
|
|
QBCore.Functions.Notify(Lang:t("info.not_enough", { value = Config.TruckPrice }))
|
|
end
|
|
end, continueworking)
|
|
end)
|
|
|
|
RegisterNetEvent('qb-garbagejob:client:RequestPaycheck', function()
|
|
if garbageVehicle then
|
|
BringBackCar()
|
|
QBCore.Functions.Notify(Lang:t("info.truck_returned"))
|
|
end
|
|
TriggerServerEvent('garbagejob:server:PayShift')
|
|
end)
|
|
|
|
RegisterNetEvent('qb-garbagejob:client:MainMenu', function()
|
|
if playerJob.name == Config.Jobname then
|
|
local MainMenu = {}
|
|
MainMenu[#MainMenu+1] = {isMenuHeader = true,header = Lang:t("menu.header")}
|
|
MainMenu[#MainMenu+1] = { header = Lang:t("menu.collect"),txt = Lang:t("menu.return_collect"),params = { event = 'qb-garbagejob:client:RequestPaycheck',}}
|
|
if not garbageVehicle or finished then
|
|
MainMenu[#MainMenu+1] = { header = Lang:t("menu.route"), txt = Lang:t("menu.request_route"), params = { event = 'qb-garbagejob:client:RequestRoute',}}
|
|
end
|
|
exports['qb-menu']:openMenu(MainMenu)
|
|
else
|
|
QBCore.Functions.Notify(Lang:t("error.job"))
|
|
end
|
|
end)
|
|
|
|
RegisterNetEvent('QBCore:Client:OnPlayerLoaded', function()
|
|
playerJob = QBCore.Functions.GetPlayerData().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 = QBCore.Functions.GetPlayerData().job
|
|
setupClient()
|
|
spawnPeds()
|
|
end
|
|
end) |