466 lines
13 KiB
Lua
466 lines
13 KiB
Lua
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)
|