local config = require 'config.client' local sharedConfig = require 'config.shared' local currentZones = {} local currentLocation = {} local currentBlip = 0 local hasBox = false local truckVehBlip = 0 local truckerBlip = 0 local returningToStation = false local currentPlate -- Functions local function returnToStation() SetBlipRoute(truckVehBlip, true) returningToStation = true end local function isTruckerVehicle(vehicle) return config.vehicles[GetEntityModel(vehicle)] end local function removeElements() ClearAllBlipRoutes() if DoesBlipExist(truckVehBlip) then RemoveBlip(truckVehBlip) truckVehBlip = 0 end if DoesBlipExist(truckerBlip) then RemoveBlip(truckerBlip) truckerBlip = 0 end if DoesBlipExist(currentBlip) then RemoveBlip(currentBlip) currentBlip = 0 end for _, zone in ipairs(currentZones) do zone:remove() end currentZones = {} end local function getPaid() TriggerServerEvent('qbx_truckerjob:server:getPaid') if DoesBlipExist(currentBlip) then RemoveBlip(currentBlip) ClearAllBlipRoutes() currentBlip = 0 end end local function returnVehicle() if cache.seat ~= -1 then return exports.qbx_core:Notify(locale('error.no_driver'), 'error') end if not isTruckerVehicle(cache.vehicle) then return exports.qbx_core:Notify(locale('error.vehicle_not_correct'), 'error') end DeleteVehicle(cache.vehicle) TriggerServerEvent('qbx_truckerjob:server:returnVehicle') if DoesBlipExist(currentBlip) then RemoveBlip(currentBlip) ClearAllBlipRoutes() currentBlip = 0 end if not returningToStation and not next(currentLocation) then return end ClearAllBlipRoutes() returningToStation = false exports.qbx_core:Notify(locale('mission.job_completed'), 'success') end local function openMenuGarage() local truckMenu = {} for k in pairs(config.vehicles) do truckMenu[#truckMenu + 1] = { title = config.vehicles[k], serverEvent = 'qbx_truckerjob:server:doBail', args = k } end lib.registerContext({ id = 'trucker_veh_menu', title = locale('menu.header'), options = truckMenu }) lib.showContext('trucker_veh_menu') end local function createMainTarget() local location = sharedConfig.locations.main; currentZones[#currentZones + 1] = exports.ox_target:addBoxZone({ coords = location.coords, size = location.size, rotation = location.rotation, debug = debug, options = { { name = location.label, onSelect = function() getPaid() end, icon = location.icon, label = location.label, distance = 2, canInteract = function() return QBX.PlayerData.job.name == 'trucker' end } } }) end local function createMainZone() local location = sharedConfig.locations.main; local zone = lib.zones.sphere({ coords = location.coords, radius = location.markerRadius, debug = location.debug }) local innerZone = lib.zones.sphere({ coords = location.coords, radius = location.interactionsRadius, debug = location.debug }) local marker = lib.marker.new({ coords = location.coords, type = location.markerType, height = 0.2, width = 0.3 }) function zone:inside() marker:draw() end function innerZone:onEnter() if not lib.isTextUIOpen() then lib.showTextUI(locale('info.pickup_paycheck')) end end function innerZone:inside() if IsControlJustPressed(0, 38) then getPaid() end end function innerZone:onExit() local isOpen, currentText = lib.isTextUIOpen() if isOpen and currentText == locale('info.pickup_paycheck') then lib.hideTextUI() end end currentZones[#currentZones + 1] = zone currentZones[#currentZones + 1] = innerZone end local createMain = config.useTarget and createMainTarget or createMainZone local function createVehicleZone() local location = sharedConfig.locations.vehicle; local zone = lib.zones.sphere({ coords = location.coords, radius = location.markerRadius, debug = location.debug }) local innerZone = lib.zones.sphere({ coords = location.coords, radius = location.interactionsRadius, debug = location.debug }) local marker = lib.marker.new({ coords = location.coords, type = location.markerType, height = 0.2, width = 0.3 }) local function hideTextUI() local isOpen, currentText = lib.isTextUIOpen() if isOpen and (currentText == locale('info.store_vehicle') or currentText == locale('info.vehicles')) then lib.hideTextUI() end end function zone:inside() marker:draw() end function innerZone:onEnter() if not lib.isTextUIOpen() then lib.showTextUI(locale(cache.vehicle and 'info.store_vehicle' or 'info.vehicles')) end end local isChangeTextAllowed = false function innerZone:inside() ---This section updates the textui when the client uses the garage. if isChangeTextAllowed then local _, currentText = lib.isTextUIOpen() local expectedText = locale(cache.vehicle and 'info.store_vehicle' or 'info.vehicles') if currentText ~= expectedText and not lib.getOpenContextMenu() then isChangeTextAllowed = false CreateThread(function() Wait(1000) lib.showTextUI(locale(cache.vehicle and 'info.store_vehicle' or 'info.vehicles')) end) end end --- if IsControlJustPressed(0, 38) then if cache.vehicle then returnVehicle() else openMenuGarage() end hideTextUI() isChangeTextAllowed = true end end function innerZone:onExit() hideTextUI() end currentZones[#currentZones + 1] = zone currentZones[#currentZones + 1] = innerZone end local function areBackDoorsOpen(vehicle) -- This is hardcoded for the rumpo currently return GetVehicleDoorAngleRatio(vehicle, 5) > 0.0 or GetVehicleDoorAngleRatio(vehicle, 2) > 0.0 and GetVehicleDoorAngleRatio(vehicle, 3) > 0.0 end local function getInTrunk() if cache.vehicle then return exports.qbx_core:Notify(locale('error.get_out_vehicle'), 'error') end local vehicle = GetVehiclePedIsIn(cache.ped, true) if not isTruckerVehicle(vehicle) or currentPlate ~= qbx.getVehiclePlate(vehicle) then return exports.qbx_core:Notify(locale('error.vehicle_not_correct'), 'error') end if not areBackDoorsOpen(vehicle) then return exports.qbx_core:Notify(locale('error.backdoors_not_open'), 'error') end local pedCoords = GetEntityCoords(cache.ped, true) local trunkCoords = GetOffsetFromEntityInWorldCoords(vehicle, 0, -2.5, 0) if #(pedCoords - trunkCoords) > 1.5 then return exports.qbx_core:Notify(locale('error.too_far_from_trunk'), 'error') end if lib.progressCircle({ duration = 2000, position = 'bottom', useWhileDead = false, canCancel = true, disable = { car = true, mouse = false, combat = true, move = true, }, anim = { dict = 'anim@gangops@facility@servers@', clip = 'hotwire' }, }) then exports.scully_emotemenu:playEmoteByCommand('box') hasBox = true exports.qbx_core:Notify(locale('info.deliver_to_store'), 'info') else exports.qbx_core:Notify(locale('error.cancelled'), 'error') end end local function deliver() if lib.progressCircle({ duration = 3000, position = 'bottom', useWhileDead = false, canCancel = true, disable = { car = true, mouse = false, combat = true, move = true, }, anim = { dict = 'anim@gangops@facility@servers@', clip = 'hotwire' }, }) then exports.scully_emotemenu:cancelEmote() ClearPedTasks(cache.ped) hasBox = false currentLocation.currentCount += 1 lib.print.debug('count:', currentLocation.currentCount, '/', currentLocation.dropCount) if currentLocation.currentCount == currentLocation.dropCount then if DoesBlipExist(currentBlip) then RemoveBlip(currentBlip) ClearAllBlipRoutes() currentBlip = 0 end currentLocation.zoneCombo:remove() currentLocation = {} return true else exports.qbx_core:Notify(locale('mission.another_box'), 'info') end else ClearPedTasks(cache.ped) exports.scully_emotemenu:cancelEmote() exports.qbx_core:Notify(locale('error.cancelled'), 'error') end end local function getNewLocation(locationIndex, drop) local location = sharedConfig.locations.stores[locationIndex] currentLocation = { dropCount = drop, currentCount = 0 } local marker = lib.marker.new({ coords = location.coords, type = location.markerType or 2, height = 0.2, width = 0.3 }) currentLocation.zoneCombo = lib.zones.box({ name = location.label, coords = location.coords, size = location.size, rotation = location.rotation, debug = location.debug, onEnter = function() exports.qbx_core:Notify(locale('mission.store_reached'), 'info') end, inside = function () marker:draw() if IsControlJustReleased(0, 38) then if cache.vehicle then return exports.qbx_core:Notify(locale('error.get_out_vehicle'), 'error') elseif not hasBox then getInTrunk() elseif #(GetEntityCoords(cache.ped) - location.coords) < 5 then if deliver() then local newLocation, newDrop = lib.callback.await('qbx_truckerjob:server:getNewTask', false) if not newLocation or QBX.PlayerData.job.name ~= 'trucker' then return elseif newLocation == 0 then exports.qbx_core:Notify(locale('mission.return_to_station'), 'info') returnToStation() else exports.qbx_core:Notify(locale('mission.goto_next_point'), 'info') getNewLocation(newLocation, newDrop) end end else exports.qbx_core:Notify(locale('error.too_far_from_delivery'), 'error') end end end, }) currentBlip = AddBlipForCoord(location.coords.x, location.coords.y, location.coords.z) SetBlipColour(currentBlip, 3) SetBlipRoute(currentBlip, true) SetBlipRouteColour(currentBlip, 3) end local function createElement(location, sprinteId) local element = AddBlipForCoord(location.coords.x, location.coords.y, location.coords.z) SetBlipSprite(element, sprinteId) SetBlipDisplay(element, 4) SetBlipScale(element, 0.6) SetBlipAsShortRange(element, true) SetBlipColour(element, 5) BeginTextCommandSetBlipName('STRING') AddTextComponentSubstringPlayerName(location.label) EndTextCommandSetBlipName(element) return element end local function createElements() if QBX.PlayerData.job.name ~= 'trucker' then return end truckVehBlip = createElement(sharedConfig.locations.vehicle, 326) truckerBlip = createElement(sharedConfig.locations.main, 479) createMain() createVehicleZone() end -- Events local function setInitState() removeElements() currentLocation = {} currentBlip = 0 hasBox = false end AddEventHandler('onResourceStart', function(resource) if resource ~= GetCurrentResourceName() then return end setInitState() createElements() end) RegisterNetEvent('QBCore:Client:OnPlayerLoaded', function() setInitState() createElements() end) RegisterNetEvent('QBCore:Client:OnPlayerUnload', function() setInitState() end) RegisterNetEvent('QBCore:Client:OnJobUpdate', function() removeElements() if next(currentLocation) and currentLocation.zoneCombo then currentLocation.zoneCombo:remove() end createElements() end) RegisterNetEvent('qbx_truckerjob:client:spawnVehicle', function(veh) local netId, plate = lib.callback.await('qbx_truckerjob:server:spawnVehicle', false, veh) if not netId then return end currentPlate = plate local vehicle = NetToVeh(netId) SetVehicleEngineOn(vehicle, true, true, false) local location, drop = lib.callback.await('qbx_truckerjob:server:getNewTask', false, true) if not location then return end getNewLocation(location, drop) end)