Scripts/resources/[qb]/[qb_extras]/qb-npcservices/client/main.lua

1024 lines
46 KiB
Lua
Raw Normal View History

2024-12-29 20:07:50 +00:00
--[[ ===================================================== ]]--
--[[ MH NPC Services Script by MaDHouSe ]]--
--[[ ===================================================== ]]--
local QBCore = exports['qb-core']:GetCoreObject()
local stuckTimerCheck = Config.StuckTimerCheck
local stuckResetTimer = Config.StuckResetTimer
local company = {}
local count = 0
local phoneProp = 0
local waitTime = 60
local cooldownTime = Config.Cooldown
local jailTime = math.random(Config.MinJailTime, Config.MaxJailTime)
local isInJail = false
local followPedCamMode
local lastCoords = nil
local function DeletePhoneProp()
if phoneProp ~= 0 then
Citizen.InvokeNative(0xAE3CBE5BF394C9C9 , Citizen.PointerValueIntInitialized(phoneProp))
phoneProp = 0
end
end
local function CreatePhoneProp()
DeletePhoneProp()
RequestModel(Config.PhoneModel)
while not HasModelLoaded(Config.PhoneModel) do Citizen.Wait(1) end
phoneProp = CreateObject(Config.PhoneModel, 1.0, 1.0, 1.0, 1, 1, 0)
local bone = GetPedBoneIndex(PlayerPedId(), 28422)
AttachEntityToEntity(phoneProp, PlayerPedId(), bone, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 1, 1, 0, 0, 2, 1)
end
local function loadAnimDict(dict)
while (not HasAnimDictLoaded(dict)) do
RequestAnimDict(dict)
Wait(5)
end
end
local function loadModel(model)
RequestModel(model)
while not HasModelLoaded(model) do Wait(1) end
end
local function CallAnimation(job)
if not QBCore.Functions.GetPlayerData().metadata['isdead'] then
local dictionary = Config.CallAnimation.call.dictionary
local animation = Config.CallAnimation.call.animation
if not QBCore.Functions.GetPlayerData().job.name == "taxi" or not QBCore.Functions.GetPlayerData().job.name == "limousine" then
if QBCore.Functions.GetPlayerData().job.name == "police" or QBCore.Functions.GetPlayerData().job.name == "ambulance" or QBCore.Functions.GetPlayerData().job.name == "mechanic" then
dictionary = Config.CallAnimation.jobcall.dictionary
animation = Config.CallAnimation.jobcall.animation
end
end
loadAnimDict(dictionary)
CreatePhoneProp()
QBCore.Functions.Notify(Lang:t('notify.you_are_calling', {job = job}), "success")
TaskPlayAnim(PlayerPedId(), dictionary, animation, 1.5, 1.0, -1, 50, 2.0, 0, 0, 0)
Wait(8100)
ClearPedTasks(PlayerPedId())
DeletePhoneProp()
Wait(500)
if job == "mechanic" and IsPedInAnyVehicle(PlayerPedId(), false) then
local vehicle = GetVehiclePedIsIn(PlayerPedId())
SetVehicleDoorsLocked(vehicle, 0)
TaskLeaveVehicle(PlayerPedId(), vehicle, 1)
end
end
end
local function CalculateTaxiPrice(job, from, to)
local route = CalculateTravelDistanceBetweenPoints(from.x, from.y, from.z, to.x, to.y, to.z)
local price = math.floor((route / 1000) * Config.Service[job].price + 0.5)
return price
end
local function TempDisableControl()
DisableAllControlActions(0)
EnableControlAction(0, 1, true)
EnableControlAction(0, 2, true)
EnableControlAction(0, 245, true)
EnableControlAction(0, 38, true)
EnableControlAction(0, 322, true)
EnableControlAction(0, 249, true)
EnableControlAction(0, 46, true)
end
local function GetDistance(pos1, pos2)
return #(vector3(pos1.x, pos1.y, pos1.z) - vector3(pos2.x, pos2.y, pos2.z))
end
local function SetCompanyData(job)
company = {
name = Config.Service[job].name,
job = Config.Service[job].job,
ped = Config.JobPeds[job].models[math.random(1, #Config.JobPeds[job].models)],
plate = Config.Service[job].plate,
home = Config.Service[job].home,
color = Config.Service[job].color,
checkin = Config.Service[job].checkin,
vehicleDrop = Config.Service[job].vehicleDrop,
playerDrop = Config.Service[job].playerDrop,
driveStyle = Config.Service[job].driveStyle,
walkStyle = Config.Service[job].walkStyle,
speed = Config.Service[job].speed,
price = Config.Service[job].price,
truck_offset = Config.Service[job].truck_offset,
spawnRadius = Config.Service[job].spawnRadius,
spotRadius = Config.Service[job].spotRadius,
passengerSeat = Config.Service[job].passengerSeat,
isCalled = false,
isWaiting = false,
isReadyToGo = false,
driveToPlayer = false,
driveToCompany = false,
driveToLocation = false,
driveToMechanic = false,
driverIsInVehicle = false,
playerIsInVehicle = false,
driveAway = false,
isHandcuffed = false,
isDriving = false,
isEscorted = false,
damage_vehicle = nil,
coords = nil,
vehicle = nil,
driver = nil,
codriver = nil,
blip = nil,
}
count = 0
end
local function DriveToLocation(from, to)
if company.driver ~= nil and company.vehicle ~= nil then
company.coords = to
if GetDistance(from, to) < 500 then
TaskVehicleDriveToCoord(company.driver, company.vehicle, to.x, to.y, to.z, company.speed, 0, GetEntityModel(company.vehicle), company.driveStyle, 2.0, true)
else
TaskVehicleDriveToCoordLongrange(company.driver, company.vehicle, to.x, to.y, to.z, company.speed, company.driveStyle, 2.0)
end
SetPedKeepTask(company.driver, true)
if company.job == "police" then SetVehicleSiren(company.vehicle, true) end
if company.job == "ambulance" then SetVehicleSiren(company.vehicle, true) end
company.isDriving = true
end
end
local function DrawTxt(x, y, width, height, scale, text, r, g, b, a)
SetTextFont(4)
SetTextProportional(0)
SetTextScale(scale, scale)
SetTextColour(r, g, b, a)
SetTextDropShadow(0, 0, 0, 0,255)
SetTextEdge(2, 0, 0, 0, 255)
SetTextDropShadow()
SetTextOutline()
SetTextEntry("STRING")
AddTextComponentString(text)
DrawText(x - width/2, y - height/2 + 0.005)
end
local function Reset()
if company.vehicle ~= nil then DeleteEntity(company.vehicle) end
if company.driver ~= nil then DeleteEntity(company.driver) end
if company.codriver ~= nil then DeleteEntity(company.codriver) end
company = {}
company.isCalled = false
company.isWaiting = false
company.driveToPlayer = false
company.driveToCompany = false
company.driveToLocation = false
company.driveToMechanic = false
company.driverIsInVehicle = false
company.playerIsInVehicle = false
company.isHandcuffed = false
company.isDriving = false
company.isEscorted = false
if QBCore.Functions.GetPlayerData().metadata['isdead'] or QBCore.Functions.GetPlayerData().metadata['inlaststand'] then
company.sendNotify = true
else
company.sendNotify = false
end
lastCoords = nil
end
local function VehicleStuckCheck()
if company.driver ~= nil and company.vehicle ~= nil and lastCoords ~= nil then
if GetEntitySpeed(company.vehicle) < 0.9 then
stuckTimerCheck = stuckTimerCheck - 1
if stuckTimerCheck <= 0 then
if GetDistance(GetEntityCoords(company.vehicle), lastCoords) <= 1.0 then
local coords = GetEntityCoords(company.vehicle)
local haeding = GetEntityHeading(company.vehicle)
local _, spawnPosition, spawnHeading = GetClosestVehicleNodeWithHeading(coords.x + 5.0, coords.y, coords.z, 0, 3, 0)
ClearAreaOfVehicles(spawnPosition, 15000, false, false, false, false, false)
SetEntityCoords(company.vehicle, spawnPosition, false, false, false, true)
SetEntityHeading(company.vehicle, haeding)
DriveToLocation(coords, company.coords)
end
stuckTimerCheck = stuckResetTimer
end
end
lastCoords = nil
end
end
local function CreateServicesBlips(entity, label)
local blip = GetBlipFromEntity(entity)
if not DoesBlipExist(blip) then
blip = AddBlipForEntity(entity)
SetBlipSprite(blip, 161)
SetBlipScale(blip, 1.0)
SetBlipColour(blip, company.color)
SetBlipAsShortRange(blip, true)
BeginTextCommandSetBlipName('STRING')
AddTextComponentString(label)
EndTextCommandSetBlipName(blip)
end
if GetBlipFromEntity(PlayerPedId()) == blip then
RemoveBlip(blip)
end
return blip
end
local function LeaveTarget()
if company.driver ~= nil and company.vehicle ~= nil then
ClearPedTasks(company.driver)
SetPedKeepTask(company.driver, true)
company.coords = vector3(127.2708, 642.6805, 207.4947)
DriveToLocation(GetEntityCoords(company.vehicle), company.coords) -- From To
company.driveAway = true
SetTimeout(15000, function()
Reset()
end)
end
end
local function CheckIfCompanyPedIsDeath()
if company.vehile ~= nil or company.driver ~= nil or company.codriver ~= nil then
if DoesEntityExist(company.driver) then
if IsEntityDead(company.driver) then
if company.codriver ~= nil then DeleteEntity(company.codriver) end
DeleteEntity(company.driver)
DeleteEntity(company.vehile)
Reset()
end
end
end
end
local function GoToMechanicShop()
QBCore.Functions.TriggerCallback("qb-npcservices:server:CanIPayTheBill", function(isPaid)
if isPaid then
SetVehicleDoorOpen(company.damage_vehicle, 4, false, false)
TaskTurnPedToFaceCoord(company.driver, GetEntityCoords(company.damage_vehicle), -1)
TaskStartScenarioInPlace(company.driver, "PROP_HUMAN_BUM_BIN", 0, false)
QBCore.Functions.Progressbar("towtruck", company.job.." is helping...", 10000, false, false, {
disableMovement = false,
disableCarMovement = false,
disableMouse = false,
disableCombat = false,
}, {}, {}, {}, function() -- Done
ClearPedTasks(company.driver)
ClearPedTasks(PlayerPedId())
AttachEntityToEntity(company.damage_vehicle, company.vehicle, 20, company.truck_offset.x, company.truck_offset.y, company.truck_offset.z, 0.0, 0.0, 0.0, false, false, false, false, 20, true)
company.isWaiting = true
end)
else
QBCore.Functions.Notify(Lang:t('notify.cant_pay',{price = company.price}), "error")
end
end, company.job, company.price)
end
local function HelpOnLocation()
QBCore.Functions.TriggerCallback("qb-npcservices:server:CanIPayTheBill", function(isPaid)
if isPaid then
if company.job == "ambulance" then
local dictionary = "mini@cpr@char_a@cpr_str"
local animation = "cpr_pumpchest"
loadAnimDict(dictionary)
TaskTurnPedToFaceCoord(company.driver, GetEntityCoords(PlayerPedId()), -1)
TaskPlayAnim(company.driver, dictionary, animation, 1.0, 1.0, -1, 9, 1.0, 0, 0, 0)
end
if company.job == "mechanic" then
local animation = "PROP_HUMAN_BUM_BIN"
SetVehicleUndriveable(company.damage_vehicle, true)
SetVehicleDoorOpen(company.damage_vehicle, 4, false, false)
TaskTurnPedToFaceCoord(company.driver, GetEntityCoords(company.damage_vehicle), -1)
TaskStartScenarioInPlace(company.driver, animation, 0, false)
end
QBCore.Functions.Progressbar("jobstuff", company.job.." is helping", 10000, false, false, {
disableMovement = false,
disableCarMovement = false,
disableMouse = false,
disableCombat = true,
}, {}, {}, {}, function() -- Done
ClearPedTasks(company.driver)
if company.job == "ambulance" then
ClearPedTasks(company.codriver)
TaskWarpPedIntoVehicle(company.codriver, company.vehicle, 0)
TriggerEvent("hospital:client:Revive")
StopScreenEffect('DeathFailOut')
end
if company.job == "mechanic" then
SetVehicleDoorShut(company.damage_vehicle, 4, false, false)
Wait(1000)
SetVehicleFixed(company.damage_vehicle)
SetVehicleEngineHealth(company.damage_vehicle, 1000.0)
SetVehicleBodyHealth(company.damage_vehicle, 1000.0)
SetVehicleOnGroundProperly(company.damage_vehicle)
SetVehicleUndriveable(company.damage_vehicle, false)
end
company.coords = company.home
TriggerServerEvent('qb-npcservices:server:pay', company.job, company.price)
LeaveTarget()
end)
else
QBCore.Functions.Notify(Lang:t('notify.cant_pay',{price = company.price}), "error")
end
end, company.job, company.price)
end
local function GoToLocation()
if DoesBlipExist(GetFirstBlipInfoId(8)) and not company.driveToLocation and not company.isDriving then
SetBlockingOfNonTemporaryEvents(company.driver, true)
local x, y, z = table.unpack(Citizen.InvokeNative(0xFA7C7F0AADF25D09, GetFirstBlipInfoId(8), Citizen.ResultAsVector()))
PlayAmbientSpeech1(company.driver, "TAXID_BEGIN_JOURNEY", "SPEECH_PARAMS_FORCE_NORMAL")
company.coords = vector3(x, y, z)
DriveToLocation(GetEntityCoords(company.vehicle), company.coords)
company.driveToLocation = true
end
end
local function GoToCompany()
QBCore.Functions.TriggerCallback("qb-npcservices:server:canPay", function(canPay)
if canPay then
company.coords = company.home
if company.job == "police" or company.job == "ambulance" then
SetVehicleSiren(company.vehicle, true)
SetVehicleDoorsLocked(company.vehicle, 1)
TaskWarpPedIntoVehicle(company.codriver, company.vehicle, 1)
if company.job == "ambulance" then TaskWarpPedIntoVehicle(company.codriver, company.vehicle, 2) end
if company.job == "police" then TaskWarpPedIntoVehicle(company.codriver, company.vehicle, 0) end
end
if company.job == 'mechanic' then
PlayAmbientSpeech1(company.driver, "THANKS", "SPEECH_PARAMS_FORCE_NORMAL")
end
company.driveToCompany = true
DriveToLocation(GetEntityCoords(company.vehicle), company.home)
else
PlayAmbientSpeech1(company.driver, "TAXID_NO_MONEY", "SPEECH_PARAMS_FORCE_NORMAL")
QBCore.Functions.Notify(Lang:t('notify.cant_pay',{price = company.price}), "error")
end
end, company.job, company.price)
end
local function CreateServicesPed(coords, vehicle, seat)
local model = GetHashKey(company.ped)
loadModel(model)
local ped = CreatePed(4, model, coords.x, coords.y, coords.z, 0, true, true)
if company.job == 'police' then GiveWeaponToPed(ped, Config.Weapons[math.random(1, #Config.Weapons)], 999, false, true) end
SetPedIntoVehicle(ped, vehicle, seat)
SetEntityAsMissionEntity(ped, true, true)
SetModelAsNoLongerNeeded(model)
SetPedKeepTask(ped, true)
SetBlockingOfNonTemporaryEvents(ped, true)
SetPedSweat(ped, 100.0)
return ped
end
local function SelectVehicleModel()
local model = Config.Vehicles[company.job].models[math.random(1, #Config.Vehicles[company.job].models)]
loadModel(model)
if company.job == "mechanic" and company.damage_vehicle ~= nil then
if GetVehicleEngineHealth(company.damage_vehicle) < Config.MinDamageForFlatbed then
model = Config.Vehicles[company.job].models[1]
else
model = Config.Vehicles[company.job].models[2]
end
end
return model
end
local function CreateServicesVehicle(coords, heading)
ClearAreaOfVehicles(coords, 10000, false, false, false, false, false)
local model = SelectVehicleModel()
loadModel(model)
local vehicle = CreateVehicle(model, coords, heading, true, true)
SetEntityInvincible(vehicle, true)
NetworkSetEntityInvisibleToNetwork(vehicle, true)
SetEntityAsMissionEntity(vehicle, true, true)
SetVehicleDirtLevel(vehicle, 0)
SetVehicleBodyHealth(vehicle, 1000.0)
SetVehicleEngineHealth(vehicle, 1000.0)
SetVehicleFuelLevel(vehicle, 100.0)
SetVehicleDoorsLocked(vehicle, 1)
DecorSetFloat(vehicle, "_FUEL_LEVEL", GetVehicleFuelLevel(vehicle))
SetEntityHeading(vehicle, heading)
SetVehicleOnGroundProperly(vehicle)
SetVehicleHasUnbreakableLights(vehicle, true)
SetVehicleNumberPlateText(vehicle, company.plate)
SetVehicleEngineOn(vehicle, true, true, false)
SetVehicleLights(vehicle, 2)
SetModelAsNoLongerNeeded(model)
return vehicle
end
local function CallServices()
if isInJail then return end
if company.job == "taxi" or company.job == "limousine" then
local waypoint = GetFirstBlipInfoId(8)
if not DoesBlipExist(GetFirstBlipInfoId(8)) then
if company.job == 'taxi' then
return QBCore.Functions.Notify(Lang:t('job.taxi.missing_waypoint'), "error")
else
return QBCore.Functions.Notify(Lang:t('job.limousine.missing_waypoint'), "error")
end
end
end
local coords = GetEntityCoords(PlayerPedId())
if Config.ForceFirstperson then followPedCamMode = GetFollowPedCamViewMode() end
local _, spawnPosition, spawnHeading = GetClosestVehicleNodeWithHeading(coords.x + math.random(-company.spawnRadius, company.spawnRadius), coords.y + math.random(-company.spawnRadius, company.spawnRadius), coords.z, 0, 3, 0)
company.vehicle = CreateServicesVehicle(spawnPosition, spawnHeading)
company.driver = CreateServicesPed(spawnPosition, company.vehicle, -1)
SetEntityAsMissionEntity(company.vehicle, true, true)
SetEntityAsMissionEntity(company.driver, true, true)
if company.job == "ambulance" then
company.codriver = CreateServicesPed(spawnPosition, company.vehicle, 0)
elseif company.job == "police" then
company.codriver = CreateServicesPed(spawnPosition, company.vehicle, 0)
end
if company.driver ~= nil and company.vehicle ~= nil then
if company.job == "police" or company.job == "ambulance" then SetVehicleSiren(vehicle, true) end
company.blip = CreateServicesBlips(company.vehicle, company.name)
DriveToLocation(spawnPosition, coords) -- From To
company.driveToPlayer = true
company.driverIsInVehicle = true
if company.job == "police" then SetFakeWantedLevel(6) end
end
end
local function WalkToVehicle()
if isInJail then return end
if not company.isEscorted then
company.isEscorted = true
company.isHandcuffed = false
if company.job == "police" then
local heading = GetEntityHeading(PlayerPedId())
TriggerServerEvent("InteractSound_SV:PlayOnSource", "Cuff", 0.2)
loadAnimDict("mp_arrest_paired")
Wait(1000)
TaskPlayAnim(PlayerPedId(), "mp_arrest_paired", "crook_p2_back_right", 3.0, 3.0, -1, 32, 0, 0, 0, 0 ,true, true, true)
company.isHandcuffed = true
Wait(2500)
end
TaskGoToCoordAnyMeans(company.driver, GetEntityCoords(company.vehicle), 2.0, 0, 0, company.walkStyle, 0xbf800000)
AttachEntityToEntity(PlayerPedId(), company.driver, 11816, 0.0, -0.45, 0.0, 0.0, 0.0, 0.0, false, false, false, true, 2, true)
GoToCompany()
end
end
AddEventHandler('onResourceStart', function(resource)
if resource == GetCurrentResourceName() then
SetFakeWantedLevel(0)
company = {}
Reset()
lastCoords = nil
end
end)
RegisterNetEvent('qb-npcservices:client:sendService', function(callData)
if isInJail then return end
if #company == 0 and not company.isCalled then
CallAnimation(callData.job)
SetCompanyData(callData.job)
company.isCalled = true
company.price = callData.price
if callData.job == "mechanic" then
local vehicle, _ = QBCore.Functions.GetClosestVehicle(GetEntityCoords(PlayerPedId()))
local props = QBCore.Functions.GetVehicleProperties(vehicle)
QBCore.Functions.TriggerCallback('qb-npcservices:server:IsVehicleOwner', function(owned)
if owned then
company.coords = GetEntityCoords(vehicle)
company.damage_vehicle = vehicle
QBCore.Functions.Notify(Lang:t('notify.call_company', {company = company.name}), "success", 8000)
Wait(8500)
CallServices()
else
QBCore.Functions.Notify(Lang:t('error.not_the_owner'), "error")
end
end, props.plate)
else
QBCore.Functions.Notify(Lang:t('notify.call_company', {company = company.name}), "success", 8000)
Wait(8500)
CallServices()
end
end
end)
RegisterNetEvent('qb-npcservices:client:menu', function()
if isInJail then return end
local playerlist = {}
QBCore.Functions.TriggerCallback('qb-npcservices:server:GetOnlinePlayers', function(online)
for key, v in pairs(online) do
if v.source == GetPlayerServerId(PlayerId()) then
playerlist[#playerlist + 1] = {value = v.source, text = "(ID:"..v.source..") "..v.fullname}
end
local player, distance = QBCore.Functions.GetClosestPlayer()
if player ~= -1 and distance < 2.5 then
local playerId = GetPlayerServerId(player)
if v.source ~= GetPlayerServerId(PlayerId()) then
playerlist[#playerlist + 1] = {value = v.source, text = "(ID:"..v.source..") "..v.fullname}
end
end
end
if playerlist == nil then
return
else
QBCore.Functions.TriggerCallback("qb-npcservices:server:isEMSServices", function(isService)
local menuData = {}
if not IsPedInAnyVehicle(PlayerPedId()) then
if DoesBlipExist(GetFirstBlipInfoId(8)) then
menuData[#menuData + 1] = {value = "taxi", text = Lang:t('job.taxi.label') }
menuData[#menuData + 1] = {value = "limousine", text = Lang:t('job.limousine.label') }
end
end
if IsPedInAnyVehicle(PlayerPedId()) then
menuData[#menuData + 1] = {value = "mechanic", text = Lang:t('job.mechanic.label') }
end
menuData[#menuData + 1] = {value = "ambulance", text = Lang:t('job.ambulance.label') }
if Config.UsePoliceAssist and QBCore.Functions.GetPlayerData().job.name == "police" and isService then
menuData[#menuData + 1] = { value = "police", text = Lang:t('job.police.label')}
end
local menu = exports["qb-input"]:ShowInput({
header = Lang:t('menu.title'),
submitText = "",
inputs = {
{
text = Lang:t('menu.select_player'),
name = "id",
type = "select",
options = playerlist,
isRequired = true
},
{
text = Lang:t('menu.select_company'),
name = "company",
type = "select",
options = menuData,
isRequired = true
}
}
})
if menu then
if not menu.id or not menu.company then return end
local call_data = {}
call_data.job = tostring(menu.company)
call_data.callerId = GetPlayerServerId(PlayerId())
call_data.price = Config.Service[call_data.job].price
if tonumber(menu.id) == GetPlayerServerId(PlayerId()) then
call_data.targetId = GetPlayerServerId(PlayerId())
else
call_data.targetId = tonumber(menu.id)
end
if call_data.job == 'taxi' or call_data.job == 'limousine' then
if DoesBlipExist(GetFirstBlipInfoId(8)) then
local x, y, z = table.unpack(Citizen.InvokeNative(0xFA7C7F0AADF25D09, GetFirstBlipInfoId(8), Citizen.ResultAsVector()))
local from = GetEntityCoords(PlayerPedId())
local to = vector3(x, y, z)
call_data.price = CalculateTaxiPrice(call_data.job, from, to)
end
end
TriggerServerEvent('qb-npcservices:server:sendService', call_data)
end
end)
end
end)
end)
RegisterNetEvent('qb-radialmenu:client:onRadialmenuOpen', function()
if MenuItemId ~= nil then
exports['qb-radialmenu']:RemoveOption(MenuItemId)
MenuItemId = nil
end
MenuItemId = exports['qb-radialmenu']:AddOption(
{
id = 'callemsservices',
title = Lang:t('menu.title'),
icon = Config.RadialMenuIcone,
type = 'client',
event = 'qb-npcservices:client:menu',
shouldClose = true
},
MenuItemId)
end)
CreateThread(function()
while true do
Wait(1)
if company.isEscorted then
DisableAllControlActions(0)
EnableControlAction(0, 1, true)
EnableControlAction(0, 2, true)
EnableControlAction(0, 245, true)
EnableControlAction(0, 38, true)
EnableControlAction(0, 322, true)
EnableControlAction(0, 249, true)
EnableControlAction(0, 46, true)
end
if company.isHandcuffed then
DisableControlAction(0, 24, true) -- Attack
DisableControlAction(0, 257, true) -- Attack 2
DisableControlAction(0, 25, true) -- Aim
DisableControlAction(0, 263, true) -- Melee Attack 1
DisableControlAction(0, 45, true) -- Reload
DisableControlAction(0, 22, true) -- Jump
DisableControlAction(0, 44, true) -- Cover
DisableControlAction(0, 37, true) -- Select Weapon
DisableControlAction(0, 23, true) -- Also 'enter'?
DisableControlAction(0, 288, true) -- Disable phone
DisableControlAction(0, 289, true) -- Inventory
DisableControlAction(0, 170, true) -- Animations
DisableControlAction(0, 167, true) -- Job
DisableControlAction(0, 26, true) -- Disable looking behind
DisableControlAction(0, 73, true) -- Disable clearing animation
DisableControlAction(2, 199, true) -- Disable pause screen
DisableControlAction(0, 59, true) -- Disable steering in vehicle
DisableControlAction(0, 71, true) -- Disable driving forward in vehicle
DisableControlAction(0, 72, true) -- Disable reversing in vehicle
DisableControlAction(2, 36, true) -- Disable going stealth
DisableControlAction(0, 264, true) -- Disable melee
DisableControlAction(0, 257, true) -- Disable melee
DisableControlAction(0, 140, true) -- Disable melee
DisableControlAction(0, 141, true) -- Disable melee
DisableControlAction(0, 142, true) -- Disable melee
DisableControlAction(0, 143, true) -- Disable melee
DisableControlAction(0, 75, true) -- Disable exit vehicle
DisableControlAction(27, 75, true) -- Disable exit vehicle
EnableControlAction(0, 249, true) -- Added for talking while cuffed
EnableControlAction(0, 46, true) -- Added for talking while cuffed
end
if not company.isHandcuffed and not company.isEscorted then
Wait(2000)
end
end
end)
-- npc is driving (Taxi/Police/Ambulance/Mechanic/TowTruck)
CreateThread(function()
while true do
if LocalPlayer.state.isLoggedIn then
if company.driveToPlayer then
local coords = nil
if company.job == 'mechanic' then
coords = GetEntityCoords(company.damage_vehicle)
else
coords = GetEntityCoords(PlayerPedId())
end
local vdistance = GetDistance(coords, GetEntityCoords(company.vehicle))
local ddistance = GetDistance(coords, GetEntityCoords(company.driver))
if company.job == 'mechanic' or company.job == 'taxi' or company.job == 'limousine' then
if QBCore.Functions.GetPlayerData().metadata['isdead'] or QBCore.Functions.GetPlayerData().metadata['inlaststand'] then
company.driveToPlayer = false
company.isDriving = false
ClearPedTasks(company.driver)
RemoveBlip(company.blip)
LeaveTarget()
end
end
if vdistance < company.spotRadius then
company.driverIsInVehicle = false
if company.job == "mechanic" then
local engine = GetWorldPositionOfEntityBone(company.damage_vehicle, GetEntityBoneIndexByName(company.damage_vehicle, "engine"))
TaskGoToCoordAnyMeans(company.driver, engine, 1.0, 0, 0, company.walkStyle, 0xbf800000)
ddistance = GetDistance(vector3(engine.x, engine.y, engine.z), GetEntityCoords(company.driver))
else
if company.job == "police" or company.job == "ambulance" then
if company.job == "police" then FreezeEntityPosition(PlayerPedId(), true) end
TaskGoToCoordAnyMeans(company.driver, coords, 2.0, 0, 0, company.walkStyle, 0xbf800000)
else
TaskGoToCoordAnyMeans(company.driver, coords, 1.0, 0, 0, company.walkStyle, 0xbf800000)
end
end
if company.job == 'police' or company.job == 'ambulance' then SetVehicleSiren(company.vehicle, false) end
if ddistance < Config.InteractDiustance then
ClearPedTasks(company.driver)
RemoveBlip(company.blip)
company.driveToPlayer = false
company.isDriving = false
if company.job == 'police' then
SetFakeWantedLevel(0)
if not company.isEscorted then WalkToVehicle() end
elseif company.job == 'ambulance' then
if QBCore.Functions.GetPlayerData().metadata['isdead'] or QBCore.Functions.GetPlayerData().metadata['inlaststand'] then
if not company.isEscorted then WalkToVehicle() end
else
HelpOnLocation()
end
elseif company.job == 'mechanic' then
if GetVehicleEngineHealth(company.damage_vehicle) < Config.MinDamageForFlatbed then
GoToMechanicShop()
else
HelpOnLocation()
end
elseif company.job == 'taxi' then
company.isWaiting = true
elseif company.job == 'limousine' then
company.isWaiting = true
end
end
end
elseif company.isReadyToGo then
if not IsPedInVehicle(PlayerPedId(), company.vehicle, false) then TempDisableControl() end
SetVehicleDoorsLocked(company.vehicle, 0)
if IsPedInVehicle(company.driver, company.vehicle, false) and IsPedInVehicle(PlayerPedId(), company.vehicle, false) then
company.isReadyToGo = false
if company.job == 'taxi' or company.job == 'limousine' then GoToLocation() end
if company.job == 'mechanic' then
DriveToLocation(GetEntityCoords(company.vehicle), company.home)
company.driveToMechanic = true
end
end
elseif company.isEscorted then
local distance = GetDistance(GetEntityCoords(company.driver), GetEntityCoords(company.vehicle))
if company.job == "police" then
loadAnimDict("mp_arresting")
TaskPlayAnim(PlayerPedId(), "mp_arresting", "idle", 8.0, -8, -1, 16, 0, 0, 0, 0)
end
if distance <= 5 then
company.isEscorted = false
company.coords = company.home
DoScreenFadeOut(500)
Wait(700)
DetachEntity(PlayerPedId(), true, false)
TaskWarpPedIntoVehicle(PlayerPedId(), company.vehicle, company.passengerSeat)
TaskWarpPedIntoVehicle(company.driver, company.vehicle, -1)
Wait(1000)
DoScreenFadeIn(500)
company.driveToCompany = true
DriveToLocation(GetEntityCoords(company.vehicle), company.home)
end
elseif company.driveToCompany then
local distance = GetDistance(GetEntityCoords(company.vehicle), company.home)
lastCoords = GetEntityCoords(company.vehicle)
if Config.ForceFirstperson then SetFollowVehicleCamViewMode(4) end
if distance <= 5 then
company.driveToCompany = false
company.isDriving = false
BringVehicleToHalt(company.vehicle, 5.0, 1000, true)
Wait(1100)
ClearPedTasks(company.driver)
SetVehicleSiren(company.vehicle, false)
DoScreenFadeOut(500)
Wait(600)
if Config.ForceFirstperson then SetFollowVehicleCamViewMode(followPedCamMode) end
SetEntityCoords(PlayerPedId(), vector3(company.checkin.x, company.checkin.y, company.checkin.z), false, false, false, true)
if company.job == "police" then
if Config.UseAutoJail then
isInJail = true
jailTime = math.random(Config.MinJailTime, Config.MaxJailTime)
end
FreezeEntityPosition(PlayerPedId(), false)
company.isHandcuffed = false
end
if company.job == "ambulance" then FreezeEntityPosition(PlayerPedId(), false) end
Wait(1000)
DoScreenFadeIn(500)
Wait(500)
LeaveTarget()
end
elseif company.driveToMechanic then
local distance = GetDistance(GetEntityCoords(company.vehicle), company.home)
lastCoords = GetEntityCoords(company.vehicle)
if Config.ForceFirstperson then SetFollowVehicleCamViewMode(4) end
if distance <= 5 then
company.driveToMechanic = false
company.isDriving = false
BringVehicleToHalt(company.vehicle, 5.0, 1000, true)
ClearPedTasks(company.driver)
TaskLeaveVehicle(PlayerPedId(), company.vehicle, 1)
TriggerServerEvent('qb-npcservices:server:pay', company.job, company.price)
if Config.ForceFirstperson then SetFollowVehicleCamViewMode(followPedCamMode) end
Wait(3000)
DetachEntity(company.damage_vehicle, false, false)
Wait(100)
SetEntityCoords(company.damage_vehicle, vector3(company.vehicleDrop.x, company.vehicleDrop.y, company.vehicleDrop.z), false, false, false, true)
Wait(2000)
LeaveTarget()
end
elseif company.driveToLocation then
local distance = GetDistance(GetEntityCoords(company.vehicle), company.coords)
if Config.ForceFirstperson then SetFollowVehicleCamViewMode(4) end
lastCoords = GetEntityCoords(company.vehicle)
if distance <= 5 or not DoesBlipExist(GetFirstBlipInfoId(8)) then
company.driveToLocation = false
company.isDriving = false
BringVehicleToHalt(company.vehicle, 5.0, 1000, true)
Wait(1100)
ClearPedTasks(company.driver)
TriggerServerEvent('qb-npcservices:server:pay', company.job, company.price)
PlayAmbientSpeech1(company.driver, "TAXID_CLOSE_AS_POSS", "SPEECH_PARAMS_FORCE_NORMAL")
Wait(100)
if Config.ForceFirstperson then SetFollowVehicleCamViewMode(followPedCamMode) end
TriggerServerEvent('qb-npcservices:server:leavevehicle', company.vehicle)
Wait(3100)
LeaveTarget()
end
elseif company.driveAway then
lastCoords = GetEntityCoords(company.vehicle)
local distance = GetDistance(GetEntityCoords(company.vehicle), GetEntityCoords(PlayerPedId()))
if distance > 100 then
company.driveAway = false
Reset()
end
end
end
Wait(100)
end
end)
CreateThread(function()
while true do
if LocalPlayer.state.isLoggedIn then
if Config.UseUnlimitHealth then
if company.job ~= nil then
if company.vehicle ~= nil then
SetVehicleBodyHealth(company.vehicle, 1000.0)
SetVehicleEngineHealth(company.vehicle, 1000.0)
SetVehicleFuelLevel(company.vehicle, 100.0)
DecorSetFloat(company.vehicle, "_FUEL_LEVEL", GetVehicleFuelLevel(company.vehicle))
end
if company.driver ~= nil then SetEntityHealth(company.driver, 200) end
if company.codriver ~= nil then SetEntityHealth(company.codriver, 200) end
end
end
end
Wait(500)
end
end)
CreateThread(function()
while true do
if LocalPlayer.state.isLoggedIn then
if Config.AutoCallAmbulance and not company.sendNotify and not company.isCalled then
if QBCore.Functions.GetPlayerData().metadata['inlaststand'] then
if not company.sendNotify then
local call_data = {}
call_data.job = 'ambulance'
call_data.callerId = GetPlayerServerId(PlayerId())
call_data.targetId = GetPlayerServerId(PlayerId())
call_data.price = Config.Service['ambulance'].price
Wait(Config.AutoCallTimer)
CallAnimation(call_data.job)
TriggerServerEvent('qb-npcservices:server:sendService', call_data)
end
end
end
CheckIfCompanyPedIsDeath()
end
Wait(1000)
end
end)
CreateThread(function()
while true do
if LocalPlayer.state.isLoggedIn then
if company.job ~= nil then
if company.driveToCompany or company.driveToLocation or company.driveToMechanic or company.driveToPlayer or company.driveAway then
if company.driverIsInVehicle then VehicleStuckCheck() end
end
end
end
Wait(1000)
end
end)
CreateThread(function()
while true do
local sleep = 1000
if LocalPlayer.state.isLoggedIn then
if isInJail and Config.UseAutoJail then
jailTime = jailTime - 1
if jailTime <= 0 then
isInJail = false
SetEntityCoords(PlayerPedId(), vector3(Config.Service['police'].checkout.x, Config.Service['police'].checkout.y, Config.Service['police'].checkout.z), false, false, false, true)
SetEntityHeading(PlayerPedId(), Config.Service['police'].checkout.w)
Reset()
end
elseif company.isWaiting then
waitTime = waitTime - 1
if waitTime <= 0 then LeaveTarget() end
elseif company.cooldown then
cooldownTime = cooldownTime - 1
if cooldownTime <= 0 then company.cooldown = false end
end
end
Wait(sleep)
end
end)
CreateThread(function()
while true do
local sleep = 1000
if LocalPlayer.state.isLoggedIn then
if isInJail and Config.UseAutoJail then
sleep = 5
if jailTime > 0 then
GetEntityHealth(PlayerPedId(), 200.0)
DrawTxt(0.93, 1.44, 1.0, 1.0, 0.6, Lang:t('notify.jail_free_time', {freetime = math.ceil(jailTime)}), 255, 255, 255, 255)
end
elseif company.isWaiting then
sleep = 5
if waitTime > 0 then
DrawTxt(0.83, 1.44, 1.0, 1.0, 0.6, Lang:t('notify.press_e_to_enter',{waitTime = math.ceil(waitTime), job = company.job}), 255, 255, 255, 255)
if IsControlJustPressed(0, 38) then -- press E to get in the taxi
if not IsPedInVehicle(PlayerPedId(), company.vehicle, false) then
company.isWaiting = false
company.isReadyToGo = true
SetVehicleDoorsLocked(company.vehicle, 0)
TriggerServerEvent('qb-vehiclekeys:server:setVehLockState', NetworkGetNetworkIdFromEntity(company.vehicle), 0)
TriggerServerEvent('qb-npcservices:server:getin', company.job, company.vehicle)
TaskEnterVehicle(company.driver, company.vehicle, -1, -1, 1.0, 1, 0)
end
end
elseif company.cooldown then
sleep = 5
if waitTime > 0 then
DrawTxt(0.93, 1.44, 1.0, 1.0, 0.6, Lang:t('notify.cooldown',{cooldownTime = math.ceil(cooldownTime), job = company.job}), 255, 255, 255, 255)
end
end
end
end
Wait(sleep)
end
end)
-- Debug Stuff
CreateThread(function()
local count = 0
while true do
count = count + 1
if LocalPlayer.state.isLoggedIn then
if Config.Debug and company.job ~= nil then
if company.driveToCompany or company.driveToLocation or company.driveToMechanic or company.driveToPlayer or company.driveAway or company.isEscorted or isInJail or not isInJail then
-- print("-----------"..count.."-----------")
-- print("Driver "..company.job.." Debugger")
-- print("Driver in Vehicle: "..tostring(company.driverIsInVehicle))
-- print("Driver Is Driving: "..tostring(company.isDriving))
-- print("Driver is Escorted: "..tostring(company.isEscorted))
-- print("Drive to Company: "..tostring(company.driveToCompany))
-- print("Drive to Location: "..tostring(company.driveToLocation))
-- print("Drive to Mechanic: "..tostring(company.driveToMechanic))
-- print("Drive to Player: "..tostring(company.driveToPlayer))
-- print("Drive Away: "..tostring(company.driveAway))
-- print("Player is in Jail: "..tostring(isInJail))
else
count = 0
end
end
end
Wait(2000)
end
end)
RegisterNetEvent('qb-npcservices:client:getinvehicle', function(vehicle)
for i = 1, 7 do
if IsVehicleSeatFree(vehicle, i) then
TriggerServerEvent('qb-vehiclekeys:server:setVehLockState', NetworkGetNetworkIdFromEntity(vehicle), 0)
SetVehicleDoorsLocked(vehicle, 0)
TaskEnterVehicle(PlayerPedId(), vehicle, -1, i, 1.0, 1, 0)
end
end
end)
RegisterNetEvent('qb-npcservices:client:leavevehicle', function()
local vehicle = GetVehiclePedIsIn(PlayerPedId())
if IsPedInAnyVehicle(PlayerPedId(), false) then
SetVehicleDoorsLocked(vehicle, 0)
TaskLeaveVehicle(PlayerPedId(), vehicle, 1)
end
end)
-- for taxi and limousine
if Config.UseTarget then
RegisterNetEvent('qb-npcservices:client:taxi', function(vehicle)
local vehicle, distance = QBCore.Functions.GetClosestVehicle(GetEntityCoords(PlayerPedId()))
TriggerServerEvent('qb-npcservices:server:getin', 'taxi', vehicle)
end)
RegisterNetEvent('qb-npcservices:client:limousine', function(vehicle)
local vehicle, distance = QBCore.Functions.GetClosestVehicle(GetEntityCoords(PlayerPedId()))
TriggerServerEvent('qb-npcservices:server:getin', 'limousine', vehicle)
end)
for _, model in pairs(Config.Vehicles['taxi']) do
exports['qb-target']:AddTargetModel(model, {
options = {
{
type = "client",
event = "qb-npcservices:client:taxi",
icon = "fas fa-car",
label = Lang:t('target.get_in'),
},
},
distance = 2.5
})
end
for _, model in pairs(Config.Vehicles['limousine']) do
exports['qb-target']:AddTargetModel(model, {
options = {
{
type = "client",
event = "qb-npcservices:client:limousine",
icon = "fas fa-car",
label = Lang:t('target.get_in'),
},
},
distance = 2.5
})
end
end