699 lines
25 KiB
Lua
699 lines
25 KiB
Lua
|
|
-- Variables
|
||
|
|
local config = require 'config.client'
|
||
|
|
local sharedConfig = require 'config.shared'
|
||
|
|
local isLoggedIn = LocalPlayer.state.isLoggedIn
|
||
|
|
local meterIsOpen = false
|
||
|
|
local meterActive = false
|
||
|
|
local lastLocation = nil
|
||
|
|
local mouseActive = false
|
||
|
|
local garageZone, taxiParkingZone = nil, nil
|
||
|
|
|
||
|
|
-- used for polyzones
|
||
|
|
local isInsidePickupZone = false
|
||
|
|
local isInsideDropZone = false
|
||
|
|
|
||
|
|
local meterData = {
|
||
|
|
fareAmount = 6,
|
||
|
|
currentFare = 0,
|
||
|
|
distanceTraveled = 0
|
||
|
|
}
|
||
|
|
|
||
|
|
local NpcData = {
|
||
|
|
Active = false,
|
||
|
|
CurrentNpc = nil,
|
||
|
|
LastNpc = nil,
|
||
|
|
CurrentDeliver = nil,
|
||
|
|
LastDeliver = nil,
|
||
|
|
Npc = nil,
|
||
|
|
NpcBlip = nil,
|
||
|
|
DeliveryBlip = nil,
|
||
|
|
NpcTaken = false,
|
||
|
|
NpcDelivered = false,
|
||
|
|
CountDown = 180
|
||
|
|
}
|
||
|
|
|
||
|
|
local taxiPed = nil
|
||
|
|
|
||
|
|
local function resetNpcTask()
|
||
|
|
NpcData = {
|
||
|
|
Active = false,
|
||
|
|
CurrentNpc = nil,
|
||
|
|
LastNpc = nil,
|
||
|
|
CurrentDeliver = nil,
|
||
|
|
LastDeliver = nil,
|
||
|
|
Npc = nil,
|
||
|
|
NpcBlip = nil,
|
||
|
|
DeliveryBlip = nil,
|
||
|
|
NpcTaken = false,
|
||
|
|
NpcDelivered = false
|
||
|
|
}
|
||
|
|
end
|
||
|
|
|
||
|
|
local function resetMeter()
|
||
|
|
meterData = {
|
||
|
|
fareAmount = 6,
|
||
|
|
currentFare = 0,
|
||
|
|
distanceTraveled = 0
|
||
|
|
}
|
||
|
|
end
|
||
|
|
|
||
|
|
local function whitelistedVehicle()
|
||
|
|
local veh = GetEntityModel(cache.vehicle)
|
||
|
|
local retval = false
|
||
|
|
|
||
|
|
for i = 1, #config.allowedVehicles, 1 do
|
||
|
|
if veh == joaat(config.allowedVehicles[i].model) then
|
||
|
|
retval = true
|
||
|
|
end
|
||
|
|
end
|
||
|
|
|
||
|
|
if veh == `dynasty` then
|
||
|
|
retval = true
|
||
|
|
end
|
||
|
|
|
||
|
|
return retval
|
||
|
|
end
|
||
|
|
|
||
|
|
local function isDriver()
|
||
|
|
return cache.seat == -1
|
||
|
|
end
|
||
|
|
|
||
|
|
local zone
|
||
|
|
local delieveryZone
|
||
|
|
|
||
|
|
local function getDeliveryLocation()
|
||
|
|
NpcData.CurrentDeliver = math.random(1, #sharedConfig.npcLocations.deliverLocations)
|
||
|
|
if NpcData.LastDeliver then
|
||
|
|
while NpcData.LastDeliver ~= NpcData.CurrentDeliver do
|
||
|
|
NpcData.CurrentDeliver = math.random(1, #sharedConfig.npcLocations.deliverLocations)
|
||
|
|
end
|
||
|
|
end
|
||
|
|
|
||
|
|
if NpcData.DeliveryBlip then
|
||
|
|
RemoveBlip(NpcData.DeliveryBlip)
|
||
|
|
end
|
||
|
|
NpcData.DeliveryBlip = AddBlipForCoord(sharedConfig.npcLocations.deliverLocations[NpcData.CurrentDeliver].x, sharedConfig.npcLocations.deliverLocations[NpcData.CurrentDeliver].y, sharedConfig.npcLocations.deliverLocations[NpcData.CurrentDeliver].z)
|
||
|
|
SetBlipColour(NpcData.DeliveryBlip, 3)
|
||
|
|
SetBlipRoute(NpcData.DeliveryBlip, true)
|
||
|
|
SetBlipRouteColour(NpcData.DeliveryBlip, 3)
|
||
|
|
NpcData.LastDeliver = NpcData.CurrentDeliver
|
||
|
|
if not config.useTarget then -- added checks to disable distance checking if polyzone option is used
|
||
|
|
CreateThread(function()
|
||
|
|
while true do
|
||
|
|
local pos = GetEntityCoords(cache.ped)
|
||
|
|
local dist = #(pos - vec3(sharedConfig.npcLocations.deliverLocations[NpcData.CurrentDeliver].x, sharedConfig.npcLocations.deliverLocations[NpcData.CurrentDeliver].y, sharedConfig.npcLocations.deliverLocations[NpcData.CurrentDeliver].z))
|
||
|
|
if dist < 20 then
|
||
|
|
DrawMarker(2, sharedConfig.npcLocations.deliverLocations[NpcData.CurrentDeliver].x, sharedConfig.npcLocations.deliverLocations[NpcData.CurrentDeliver].y, sharedConfig.npcLocations.deliverLocations[NpcData.CurrentDeliver].z, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.3, 0.3, 0.3, 255, 255, 255, 255, false, false, 0, true, nil, nil, false)
|
||
|
|
if dist < 5 then
|
||
|
|
qbx.drawText3d({text = locale('info.drop_off_npc'), coords = sharedConfig.npcLocations.deliverLocations[NpcData.CurrentDeliver].xyz})
|
||
|
|
if IsControlJustPressed(0, 38) then
|
||
|
|
TaskLeaveVehicle(NpcData.Npc, cache.vehicle, 0)
|
||
|
|
SetEntityAsMissionEntity(NpcData.Npc, false, true)
|
||
|
|
SetEntityAsNoLongerNeeded(NpcData.Npc)
|
||
|
|
local targetCoords = sharedConfig.npcLocations.takeLocations[NpcData.LastNpc]
|
||
|
|
TaskGoStraightToCoord(NpcData.Npc, targetCoords.x, targetCoords.y, targetCoords.z, 1.0, -1, 0.0, 0.0)
|
||
|
|
SendNUIMessage({
|
||
|
|
action = 'toggleMeter'
|
||
|
|
})
|
||
|
|
TriggerServerEvent('qb-taxi:server:NpcPay', meterData.currentFare)
|
||
|
|
meterActive = false
|
||
|
|
SendNUIMessage({
|
||
|
|
action = 'resetMeter'
|
||
|
|
})
|
||
|
|
exports.qbx_core:Notify(locale('info.person_was_dropped_off'), 'success')
|
||
|
|
if NpcData.DeliveryBlip then
|
||
|
|
RemoveBlip(NpcData.DeliveryBlip)
|
||
|
|
end
|
||
|
|
local RemovePed = function(p)
|
||
|
|
SetTimeout(60000, function()
|
||
|
|
DeletePed(p)
|
||
|
|
end)
|
||
|
|
end
|
||
|
|
RemovePed(NpcData.Npc)
|
||
|
|
resetNpcTask()
|
||
|
|
break
|
||
|
|
end
|
||
|
|
end
|
||
|
|
end
|
||
|
|
Wait(0)
|
||
|
|
end
|
||
|
|
end)
|
||
|
|
end
|
||
|
|
end
|
||
|
|
|
||
|
|
local function callNpcPoly()
|
||
|
|
CreateThread(function()
|
||
|
|
while not NpcData.NpcTaken do
|
||
|
|
if isInsidePickupZone then
|
||
|
|
if IsControlJustPressed(0, 38) then
|
||
|
|
lib.hideTextUI()
|
||
|
|
local veh = cache.vehicle
|
||
|
|
local maxSeats, freeSeat = GetVehicleMaxNumberOfPassengers(veh), 0
|
||
|
|
|
||
|
|
for i= maxSeats - 1, 0, -1 do
|
||
|
|
if IsVehicleSeatFree(veh, i) then
|
||
|
|
freeSeat = i
|
||
|
|
break
|
||
|
|
end
|
||
|
|
end
|
||
|
|
|
||
|
|
meterIsOpen = true
|
||
|
|
meterActive = true
|
||
|
|
lastLocation = GetEntityCoords(cache.ped)
|
||
|
|
SendNUIMessage({
|
||
|
|
action = 'openMeter',
|
||
|
|
toggle = true,
|
||
|
|
meterData = config.meter
|
||
|
|
})
|
||
|
|
SendNUIMessage({
|
||
|
|
action = 'toggleMeter'
|
||
|
|
})
|
||
|
|
ClearPedTasksImmediately(NpcData.Npc)
|
||
|
|
FreezeEntityPosition(NpcData.Npc, false)
|
||
|
|
TaskEnterVehicle(NpcData.Npc, veh, -1, freeSeat, 1.0, 0)
|
||
|
|
exports.qbx_core:Notify(locale('info.go_to_location'), 'inform')
|
||
|
|
if NpcData.NpcBlip then
|
||
|
|
RemoveBlip(NpcData.NpcBlip)
|
||
|
|
end
|
||
|
|
getDeliveryLocation()
|
||
|
|
NpcData.NpcTaken = true
|
||
|
|
createNpcDelieveryLocation()
|
||
|
|
zone:remove()
|
||
|
|
lib.hideTextUI()
|
||
|
|
end
|
||
|
|
end
|
||
|
|
Wait(0)
|
||
|
|
end
|
||
|
|
end)
|
||
|
|
end
|
||
|
|
|
||
|
|
local function onEnterCallZone()
|
||
|
|
if whitelistedVehicle() and not isInsidePickupZone and not NpcData.NpcTaken then
|
||
|
|
isInsidePickupZone = true
|
||
|
|
lib.showTextUI(locale('info.call_npc'), {position = 'left-center'})
|
||
|
|
callNpcPoly()
|
||
|
|
end
|
||
|
|
end
|
||
|
|
|
||
|
|
local function onExitCallZone()
|
||
|
|
lib.hideTextUI()
|
||
|
|
isInsidePickupZone = false
|
||
|
|
end
|
||
|
|
|
||
|
|
local function createNpcPickUpLocation()
|
||
|
|
zone = lib.zones.box({
|
||
|
|
coords = config.pzLocations.takeLocations[NpcData.CurrentNpc].coord,
|
||
|
|
size = vec3(config.pzLocations.takeLocations[NpcData.CurrentNpc].height, config.pzLocations.takeLocations[NpcData.CurrentNpc].width, (config.pzLocations.takeLocations[NpcData.CurrentNpc].maxZ - config.pzLocations.takeLocations[NpcData.CurrentNpc].minZ)),
|
||
|
|
rotation = config.pzLocations.takeLocations[NpcData.CurrentNpc].heading,
|
||
|
|
debug = config.debugPoly,
|
||
|
|
onEnter = onEnterCallZone,
|
||
|
|
onExit = onExitCallZone
|
||
|
|
})
|
||
|
|
end
|
||
|
|
|
||
|
|
|
||
|
|
|
||
|
|
local function enumerateEntitiesWithinDistance(entities, isPlayerEntities, coords, maxDistance)
|
||
|
|
local nearbyEntities = {}
|
||
|
|
if coords then
|
||
|
|
coords = vec3(coords.x, coords.y, coords.z)
|
||
|
|
else
|
||
|
|
coords = GetEntityCoords(cache.ped)
|
||
|
|
end
|
||
|
|
for k, entity in pairs(entities) do
|
||
|
|
local distance = #(coords - GetEntityCoords(entity))
|
||
|
|
if distance <= maxDistance then
|
||
|
|
nearbyEntities[#nearbyEntities + 1] = isPlayerEntities and k or entity
|
||
|
|
end
|
||
|
|
end
|
||
|
|
return nearbyEntities
|
||
|
|
end
|
||
|
|
|
||
|
|
local function getVehiclesInArea(coords, maxDistance) -- Vehicle inspection in designated area
|
||
|
|
return enumerateEntitiesWithinDistance(GetGamePool('CVehicle'), false, coords, maxDistance)
|
||
|
|
end
|
||
|
|
|
||
|
|
local function isSpawnPointClear(coords, maxDistance) -- Check the spawn point to see if it's empty or not:
|
||
|
|
return #getVehiclesInArea(coords, maxDistance) == 0
|
||
|
|
end
|
||
|
|
|
||
|
|
local function getVehicleSpawnPoint()
|
||
|
|
local near = nil
|
||
|
|
local distance = 10000
|
||
|
|
for k, v in pairs(config.cabSpawns) do
|
||
|
|
if isSpawnPointClear(vec3(v.x, v.y, v.z), 2.5) then
|
||
|
|
local pos = GetEntityCoords(cache.ped)
|
||
|
|
local cur_distance = #(pos - vec3(v.x, v.y, v.z))
|
||
|
|
if cur_distance < distance then
|
||
|
|
distance = cur_distance
|
||
|
|
near = k
|
||
|
|
end
|
||
|
|
end
|
||
|
|
end
|
||
|
|
return near
|
||
|
|
end
|
||
|
|
|
||
|
|
local function calculateFareAmount()
|
||
|
|
if meterIsOpen and meterActive then
|
||
|
|
local startPos = lastLocation
|
||
|
|
local newPos = GetEntityCoords(cache.ped)
|
||
|
|
if startPos ~= newPos then
|
||
|
|
local newDistance = #(startPos - newPos)
|
||
|
|
lastLocation = newPos
|
||
|
|
|
||
|
|
meterData['distanceTraveled'] += (newDistance / 1609)
|
||
|
|
|
||
|
|
local fareAmount = ((meterData['distanceTraveled']) * config.meter.defaultPrice) + config.meter.startingPrice
|
||
|
|
meterData['currentFare'] = math.floor(fareAmount)
|
||
|
|
|
||
|
|
SendNUIMessage({
|
||
|
|
action = 'updateMeter',
|
||
|
|
meterData = meterData
|
||
|
|
})
|
||
|
|
end
|
||
|
|
end
|
||
|
|
end
|
||
|
|
|
||
|
|
local function onEnterDropZone()
|
||
|
|
if whitelistedVehicle() and not isInsideDropZone and NpcData.NpcTaken then
|
||
|
|
isInsideDropZone = true
|
||
|
|
lib.showTextUI(locale('info.drop_off_npc'), {position = 'left-center'})
|
||
|
|
dropNpcPoly()
|
||
|
|
end
|
||
|
|
end
|
||
|
|
|
||
|
|
local function onExitDropZone()
|
||
|
|
lib.hideTextUI()
|
||
|
|
isInsideDropZone = false
|
||
|
|
|
||
|
|
end
|
||
|
|
|
||
|
|
function createNpcDelieveryLocation()
|
||
|
|
delieveryZone = lib.zones.box({
|
||
|
|
coords = config.pzLocations.dropLocations[NpcData.CurrentDeliver].coord,
|
||
|
|
size = vec3(config.pzLocations.dropLocations[NpcData.CurrentDeliver].height, config.pzLocations.dropLocations[NpcData.CurrentDeliver].width, (config.pzLocations.dropLocations[NpcData.CurrentDeliver].maxZ - config.pzLocations.dropLocations[NpcData.CurrentDeliver].minZ)),
|
||
|
|
rotation = config.pzLocations.dropLocations[NpcData.CurrentDeliver].heading,
|
||
|
|
debug = config.debugPoly,
|
||
|
|
onEnter = onEnterDropZone,
|
||
|
|
onExit = onExitDropZone
|
||
|
|
})
|
||
|
|
end
|
||
|
|
|
||
|
|
function dropNpcPoly()
|
||
|
|
CreateThread(function()
|
||
|
|
while NpcData.NpcTaken do
|
||
|
|
if isInsideDropZone then
|
||
|
|
if IsControlJustPressed(0, 38) then
|
||
|
|
lib.hideTextUI()
|
||
|
|
local veh = cache.vehicle
|
||
|
|
TaskLeaveVehicle(NpcData.Npc, veh, 0)
|
||
|
|
Wait(1000)
|
||
|
|
SetVehicleDoorShut(veh, 3, false)
|
||
|
|
SetEntityAsMissionEntity(NpcData.Npc, false, true)
|
||
|
|
SetEntityAsNoLongerNeeded(NpcData.Npc)
|
||
|
|
local targetCoords = sharedConfig.npcLocations.takeLocations[NpcData.LastNpc]
|
||
|
|
TaskGoStraightToCoord(NpcData.Npc, targetCoords.x, targetCoords.y, targetCoords.z, 1.0, -1, 0.0, 0.0)
|
||
|
|
SendNUIMessage({
|
||
|
|
action = 'toggleMeter'
|
||
|
|
})
|
||
|
|
TriggerServerEvent('qb-taxi:server:NpcPay', meterData.currentFare)
|
||
|
|
meterActive = false
|
||
|
|
SendNUIMessage({
|
||
|
|
action = 'resetMeter'
|
||
|
|
})
|
||
|
|
exports.qbx_core:Notify(locale('info.person_was_dropped_off'), 'success')
|
||
|
|
if NpcData.DeliveryBlip ~= nil then
|
||
|
|
RemoveBlip(NpcData.DeliveryBlip)
|
||
|
|
end
|
||
|
|
local RemovePed = function(p)
|
||
|
|
SetTimeout(60000, function()
|
||
|
|
DeletePed(p)
|
||
|
|
end)
|
||
|
|
end
|
||
|
|
RemovePed(NpcData.Npc)
|
||
|
|
resetNpcTask()
|
||
|
|
delieveryZone:remove()
|
||
|
|
lib.hideTextUI()
|
||
|
|
break
|
||
|
|
end
|
||
|
|
end
|
||
|
|
Wait(0)
|
||
|
|
end
|
||
|
|
end)
|
||
|
|
end
|
||
|
|
|
||
|
|
local function setLocationsBlip()
|
||
|
|
if not config.useBlips then return end
|
||
|
|
local taxiBlip = AddBlipForCoord(config.locations.main.coords.x, config.locations.main.coords.y, config.locations.main.coords.z)
|
||
|
|
SetBlipSprite(taxiBlip, 198)
|
||
|
|
SetBlipDisplay(taxiBlip, 4)
|
||
|
|
SetBlipScale(taxiBlip, 0.6)
|
||
|
|
SetBlipAsShortRange(taxiBlip, true)
|
||
|
|
SetBlipColour(taxiBlip, 5)
|
||
|
|
BeginTextCommandSetBlipName('STRING')
|
||
|
|
AddTextComponentSubstringPlayerName(locale('info.blip_name'))
|
||
|
|
EndTextCommandSetBlipName(taxiBlip)
|
||
|
|
end
|
||
|
|
|
||
|
|
local function taxiGarage()
|
||
|
|
local registeredMenu = {
|
||
|
|
id = 'garages_depotlist',
|
||
|
|
title = locale('menu.taxi_menu_header'),
|
||
|
|
options = {}
|
||
|
|
}
|
||
|
|
local options = {}
|
||
|
|
for _, v in pairs(config.allowedVehicles) do
|
||
|
|
|
||
|
|
options[#options + 1] = {
|
||
|
|
title = v.label,
|
||
|
|
event = 'qb-taxi:client:TakeVehicle',
|
||
|
|
args = {model = v.model},
|
||
|
|
icon = 'fa-solid fa-taxi'
|
||
|
|
}
|
||
|
|
end
|
||
|
|
|
||
|
|
registeredMenu['options'] = options
|
||
|
|
lib.registerContext(registeredMenu)
|
||
|
|
lib.showContext('garages_depotlist')
|
||
|
|
end
|
||
|
|
|
||
|
|
local function setupGarageZone()
|
||
|
|
if config.useTarget then
|
||
|
|
lib.requestModel(`a_m_m_indian_01`)
|
||
|
|
taxiPed = CreatePed(3, `a_m_m_indian_01`, 894.93, -179.12, 74.7 - 1.0, 237.09, false, true)
|
||
|
|
SetModelAsNoLongerNeeded(`a_m_m_indian_01`)
|
||
|
|
SetBlockingOfNonTemporaryEvents(taxiPed, true)
|
||
|
|
FreezeEntityPosition(taxiPed, true)
|
||
|
|
SetEntityInvincible(taxiPed, true)
|
||
|
|
exports.ox_target:addLocalEntity(taxiPed, {
|
||
|
|
{
|
||
|
|
type = 'client',
|
||
|
|
event = 'qb-taxijob:client:requestcab',
|
||
|
|
icon = 'fa-solid fa-taxi',
|
||
|
|
label = locale('info.request_taxi_target'),
|
||
|
|
job = 'taxi',
|
||
|
|
}
|
||
|
|
})
|
||
|
|
else
|
||
|
|
local function onEnter()
|
||
|
|
if not cache.vehicle then
|
||
|
|
lib.showTextUI(locale('info.request_taxi'))
|
||
|
|
end
|
||
|
|
end
|
||
|
|
|
||
|
|
local function onExit()
|
||
|
|
lib.hideTextUI()
|
||
|
|
end
|
||
|
|
|
||
|
|
local function inside()
|
||
|
|
if IsControlJustPressed(0, 38) then
|
||
|
|
lib.hideTextUI()
|
||
|
|
taxiGarage()
|
||
|
|
return
|
||
|
|
end
|
||
|
|
end
|
||
|
|
|
||
|
|
garageZone = lib.zones.box({
|
||
|
|
coords = config.locations.garage.coords,
|
||
|
|
size = vec3(1.6, 4.0, 2.8),
|
||
|
|
rotation = 328.5,
|
||
|
|
debug = config.debugPoly,
|
||
|
|
inside = inside,
|
||
|
|
onEnter = onEnter,
|
||
|
|
onExit = onExit
|
||
|
|
})
|
||
|
|
end
|
||
|
|
end
|
||
|
|
|
||
|
|
local function destroyGarageZone()
|
||
|
|
if not garageZone then return end
|
||
|
|
|
||
|
|
garageZone:remove()
|
||
|
|
garageZone = nil
|
||
|
|
end
|
||
|
|
|
||
|
|
function setupTaxiParkingZone()
|
||
|
|
taxiParkingZone = lib.zones.box({
|
||
|
|
coords = vec3(config.locations.main.coords.x, config.locations.main.coords.y, config.locations.main.coords.z),
|
||
|
|
size = vec3(4.0, 4.0, 4.0),
|
||
|
|
rotation = 55,
|
||
|
|
debug = config.debugPoly,
|
||
|
|
inside = function()
|
||
|
|
if QBX.PlayerData.job.name ~= 'taxi' then return end
|
||
|
|
if IsControlJustPressed(0, 38) then
|
||
|
|
if whitelistedVehicle() then
|
||
|
|
if meterIsOpen then
|
||
|
|
TriggerEvent('qb-taxi:client:toggleMeter')
|
||
|
|
meterActive = false
|
||
|
|
end
|
||
|
|
DeleteVehicle(cache.vehicle)
|
||
|
|
exports.qbx_core:Notify(locale('info.taxi_returned'), 'success')
|
||
|
|
end
|
||
|
|
end
|
||
|
|
end,
|
||
|
|
onEnter = function()
|
||
|
|
lib.showTextUI(locale('info.vehicle_parking'))
|
||
|
|
end,
|
||
|
|
onExit = function()
|
||
|
|
lib.hideTextUI()
|
||
|
|
end
|
||
|
|
})
|
||
|
|
end
|
||
|
|
|
||
|
|
local function destroyTaxiParkingZone()
|
||
|
|
if not taxiParkingZone then return end
|
||
|
|
|
||
|
|
taxiParkingZone:remove()
|
||
|
|
taxiParkingZone = nil
|
||
|
|
end
|
||
|
|
|
||
|
|
RegisterNetEvent('qb-taxi:client:TakeVehicle', function(data)
|
||
|
|
local SpawnPoint = getVehicleSpawnPoint()
|
||
|
|
if SpawnPoint then
|
||
|
|
local coords = config.cabSpawns[SpawnPoint]
|
||
|
|
local CanSpawn = isSpawnPointClear(coords, 2.0)
|
||
|
|
if CanSpawn then
|
||
|
|
local netId = lib.callback.await('qb-taxi:server:spawnTaxi', false, data.model, coords)
|
||
|
|
local veh = NetToVeh(netId)
|
||
|
|
SetVehicleFuelLevel(veh, 100.0)
|
||
|
|
SetVehicleEngineOn(veh, true, true, false)
|
||
|
|
else
|
||
|
|
exports.qbx_core:Notify(locale('info.no_spawn_point'), 'error')
|
||
|
|
end
|
||
|
|
else
|
||
|
|
exports.qbx_core:Notify(locale('info.no_spawn_point'), 'error')
|
||
|
|
return
|
||
|
|
end
|
||
|
|
end)
|
||
|
|
|
||
|
|
-- Events
|
||
|
|
RegisterNetEvent('qb-taxi:client:DoTaxiNpc', function()
|
||
|
|
if whitelistedVehicle() then
|
||
|
|
if not NpcData.Active then
|
||
|
|
NpcData.CurrentNpc = math.random(1, #sharedConfig.npcLocations.takeLocations)
|
||
|
|
if NpcData.LastNpc ~= nil then
|
||
|
|
while NpcData.LastNpc ~= NpcData.CurrentNpc do
|
||
|
|
NpcData.CurrentNpc = math.random(1, #sharedConfig.npcLocations.takeLocations)
|
||
|
|
end
|
||
|
|
end
|
||
|
|
|
||
|
|
local Gender = math.random(1, #config.npcSkins)
|
||
|
|
local PedSkin = math.random(1, #config.npcSkins[Gender])
|
||
|
|
local model = GetHashKey(config.npcSkins[Gender][PedSkin])
|
||
|
|
lib.requestModel(model)
|
||
|
|
NpcData.Npc = CreatePed(3, model, sharedConfig.npcLocations.takeLocations[NpcData.CurrentNpc].x, sharedConfig.npcLocations.takeLocations[NpcData.CurrentNpc].y, sharedConfig.npcLocations.takeLocations[NpcData.CurrentNpc].z - 0.98, sharedConfig.npcLocations.takeLocations[NpcData.CurrentNpc].w, true, true)
|
||
|
|
SetModelAsNoLongerNeeded(model)
|
||
|
|
PlaceObjectOnGroundProperly(NpcData.Npc)
|
||
|
|
FreezeEntityPosition(NpcData.Npc, true)
|
||
|
|
if NpcData.NpcBlip ~= nil then
|
||
|
|
RemoveBlip(NpcData.NpcBlip)
|
||
|
|
end
|
||
|
|
exports.qbx_core:Notify(locale('info.npc_on_gps'), 'success')
|
||
|
|
|
||
|
|
-- added checks to disable distance checking if polyzone option is used
|
||
|
|
if config.useTarget then
|
||
|
|
createNpcPickUpLocation()
|
||
|
|
end
|
||
|
|
|
||
|
|
NpcData.NpcBlip = AddBlipForCoord(sharedConfig.npcLocations.takeLocations[NpcData.CurrentNpc].x, sharedConfig.npcLocations.takeLocations[NpcData.CurrentNpc].y, sharedConfig.npcLocations.takeLocations[NpcData.CurrentNpc].z)
|
||
|
|
SetBlipColour(NpcData.NpcBlip, 3)
|
||
|
|
SetBlipRoute(NpcData.NpcBlip, true)
|
||
|
|
SetBlipRouteColour(NpcData.NpcBlip, 3)
|
||
|
|
NpcData.LastNpc = NpcData.CurrentNpc
|
||
|
|
NpcData.Active = true
|
||
|
|
|
||
|
|
-- added checks to disable distance checking if polyzone option is used
|
||
|
|
if not config.useTarget then
|
||
|
|
CreateThread(function()
|
||
|
|
while not NpcData.NpcTaken do
|
||
|
|
|
||
|
|
local pos = GetEntityCoords(cache.ped)
|
||
|
|
local dist = #(pos - vec3(sharedConfig.npcLocations.takeLocations[NpcData.CurrentNpc].x, sharedConfig.npcLocations.takeLocations[NpcData.CurrentNpc].y, sharedConfig.npcLocations.takeLocations[NpcData.CurrentNpc].z))
|
||
|
|
|
||
|
|
if dist < 20 then
|
||
|
|
DrawMarker(2, sharedConfig.npcLocations.takeLocations[NpcData.CurrentNpc].x, sharedConfig.npcLocations.takeLocations[NpcData.CurrentNpc].y, sharedConfig.npcLocations.takeLocations[NpcData.CurrentNpc].z, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.3, 0.3, 0.3, 255, 255, 255, 255, false, false, 0, true, nil, nil, false)
|
||
|
|
|
||
|
|
if dist < 5 then
|
||
|
|
qbx.drawText3d({text = locale('info.call_npc'), coords = sharedConfig.npcLocations.takeLocations[NpcData.CurrentNpc].xyz})
|
||
|
|
if IsControlJustPressed(0, 38) then
|
||
|
|
local maxSeats, freeSeat = GetVehicleMaxNumberOfPassengers(cache.vehicle), 0
|
||
|
|
|
||
|
|
for i=maxSeats - 1, 0, -1 do
|
||
|
|
if IsVehicleSeatFree(cache.vehicle, i) then
|
||
|
|
freeSeat = i
|
||
|
|
break
|
||
|
|
end
|
||
|
|
end
|
||
|
|
|
||
|
|
meterIsOpen = true
|
||
|
|
meterActive = true
|
||
|
|
lastLocation = GetEntityCoords(cache.ped)
|
||
|
|
SendNUIMessage({
|
||
|
|
action = 'openMeter',
|
||
|
|
toggle = true,
|
||
|
|
meterData = config.meter
|
||
|
|
})
|
||
|
|
SendNUIMessage({
|
||
|
|
action = 'toggleMeter'
|
||
|
|
})
|
||
|
|
ClearPedTasksImmediately(NpcData.Npc)
|
||
|
|
FreezeEntityPosition(NpcData.Npc, false)
|
||
|
|
TaskEnterVehicle(NpcData.Npc, cache.vehicle, -1, freeSeat, 1.0, 0)
|
||
|
|
exports.qbx_core:Notify(locale('info.go_to_location'), 'inform')
|
||
|
|
if NpcData.NpcBlip ~= nil then
|
||
|
|
RemoveBlip(NpcData.NpcBlip)
|
||
|
|
end
|
||
|
|
getDeliveryLocation()
|
||
|
|
NpcData.NpcTaken = true
|
||
|
|
end
|
||
|
|
end
|
||
|
|
end
|
||
|
|
|
||
|
|
Wait(0)
|
||
|
|
end
|
||
|
|
end)
|
||
|
|
end
|
||
|
|
else
|
||
|
|
exports.qbx_core:Notify(locale('error.already_mission'), 'error')
|
||
|
|
end
|
||
|
|
else
|
||
|
|
exports.qbx_core:Notify(locale('error.not_in_taxi'), 'error')
|
||
|
|
end
|
||
|
|
end)
|
||
|
|
|
||
|
|
RegisterNetEvent('qb-taxi:client:toggleMeter', function()
|
||
|
|
if cache.vehicle then
|
||
|
|
if whitelistedVehicle() then
|
||
|
|
if not meterIsOpen and isDriver() then
|
||
|
|
SendNUIMessage({
|
||
|
|
action = 'openMeter',
|
||
|
|
toggle = true,
|
||
|
|
meterData = config.meter
|
||
|
|
})
|
||
|
|
meterIsOpen = true
|
||
|
|
else
|
||
|
|
SendNUIMessage({
|
||
|
|
action = 'openMeter',
|
||
|
|
toggle = false
|
||
|
|
})
|
||
|
|
meterIsOpen = false
|
||
|
|
end
|
||
|
|
else
|
||
|
|
exports.qbx_core:Notify(locale('error.missing_meter'), 'error')
|
||
|
|
end
|
||
|
|
else
|
||
|
|
exports.qbx_core:Notify(locale('error.no_vehicle'), 'error')
|
||
|
|
end
|
||
|
|
end)
|
||
|
|
|
||
|
|
RegisterNetEvent('qb-taxi:client:enableMeter', function()
|
||
|
|
if meterIsOpen then
|
||
|
|
SendNUIMessage({
|
||
|
|
action = 'toggleMeter'
|
||
|
|
})
|
||
|
|
else
|
||
|
|
exports.qbx_core:Notify(locale('error.not_active_meter'), 'error')
|
||
|
|
end
|
||
|
|
end)
|
||
|
|
|
||
|
|
RegisterNetEvent('qb-taxi:client:toggleMuis', function()
|
||
|
|
Wait(400)
|
||
|
|
if meterIsOpen then
|
||
|
|
if not mouseActive then
|
||
|
|
SetNuiFocus(true, true)
|
||
|
|
mouseActive = true
|
||
|
|
end
|
||
|
|
else
|
||
|
|
exports.qbx_core:Notify(locale('error.no_meter_sight'), 'error')
|
||
|
|
end
|
||
|
|
end)
|
||
|
|
|
||
|
|
RegisterNetEvent('qb-taxijob:client:requestcab', function()
|
||
|
|
taxiGarage()
|
||
|
|
end)
|
||
|
|
|
||
|
|
-- NUI Callbacks
|
||
|
|
|
||
|
|
RegisterNUICallback('enableMeter', function(data, cb)
|
||
|
|
meterActive = data.enabled
|
||
|
|
if not meterActive then resetMeter() end
|
||
|
|
lastLocation = GetEntityCoords(cache.ped)
|
||
|
|
cb('ok')
|
||
|
|
end)
|
||
|
|
|
||
|
|
RegisterNUICallback('hideMouse', function(_, cb)
|
||
|
|
SetNuiFocus(false, false)
|
||
|
|
mouseActive = false
|
||
|
|
cb('ok')
|
||
|
|
end)
|
||
|
|
|
||
|
|
-- Threads
|
||
|
|
CreateThread(function()
|
||
|
|
while true do
|
||
|
|
Wait(2000)
|
||
|
|
calculateFareAmount()
|
||
|
|
end
|
||
|
|
end)
|
||
|
|
|
||
|
|
CreateThread(function()
|
||
|
|
while true do
|
||
|
|
if not cache.vehicle then
|
||
|
|
if meterIsOpen then
|
||
|
|
SendNUIMessage({
|
||
|
|
action = 'openMeter',
|
||
|
|
toggle = false
|
||
|
|
})
|
||
|
|
meterIsOpen = false
|
||
|
|
end
|
||
|
|
end
|
||
|
|
Wait(200)
|
||
|
|
end
|
||
|
|
end)
|
||
|
|
|
||
|
|
local function init()
|
||
|
|
if QBX.PlayerData.job.name == 'taxi' then
|
||
|
|
setupGarageZone()
|
||
|
|
setupTaxiParkingZone()
|
||
|
|
setLocationsBlip()
|
||
|
|
end
|
||
|
|
end
|
||
|
|
|
||
|
|
RegisterNetEvent('QBCore:Client:OnJobUpdate', function()
|
||
|
|
destroyGarageZone()
|
||
|
|
destroyTaxiParkingZone()
|
||
|
|
init()
|
||
|
|
end)
|
||
|
|
|
||
|
|
RegisterNetEvent('QBCore:Client:OnPlayerLoaded', function()
|
||
|
|
isLoggedIn = true
|
||
|
|
init()
|
||
|
|
end)
|
||
|
|
|
||
|
|
RegisterNetEvent('QBCore:Client:OnPlayerUnload', function()
|
||
|
|
isLoggedIn = false
|
||
|
|
end)
|
||
|
|
|
||
|
|
CreateThread(function()
|
||
|
|
if not isLoggedIn then return end
|
||
|
|
init()
|
||
|
|
end)
|