Main/resources/[jobs]/[civ]/nordi_delivery/cl_pizzajob.lua

501 lines
16 KiB
Lua
Raw Normal View History

2025-06-07 08:51:21 +02:00
local Config = lib.require('config')
local QBCore = exports['qb-core']:GetCoreObject()
local pizzaBlips = {}
local bossPoints = {}
local isHired, holdingPizza, pizzaDelivered, activeOrder = false, false, false, false
local pizzaProp, pizzaBoss, pizzaCar, currZone, JobBlip, currentDelivery
local oxtarget = GetResourceState('ox_target') == 'started'
-- Check if player has required job
local function hasRequiredJob()
local Player = QBCore.Functions.GetPlayerData()
if not Player or not Player.job then return false end
local PlayerJob = Player.job.name
local PlayerGrade = Player.job.grade.level
for _, allowedJob in ipairs(Config.AllowedJobs) do
if PlayerJob == allowedJob then
if Config.RequiredJobGrade and PlayerGrade >= Config.RequiredJobGrade then
return true
elseif not Config.RequiredJobGrade then
return true
end
end
end
return false
end
-- Handle pizza box prop and animation
local function doEmote(bool)
if bool then
local model = `prop_coolbox_01`
lib.requestModel(model)
local coords = GetEntityCoords(cache.ped)
pizzaProp = CreateObject(model, coords.x, coords.y, coords.z, true, true, true)
AttachEntityToEntity(pizzaProp, cache.ped, GetPedBoneIndex(cache.ped, 28422), 0.0100,-0.1000, -0.1590, 20.0000007, 0.0, 0.0, true, true, false, true, 0, true)
lib.requestAnimDict('anim@heists@box_carry@')
TaskPlayAnim(cache.ped, 'anim@heists@box_carry@', 'idle', 5.0, 5.0, -1, 51, 0, 0, 0, 0)
SetModelAsNoLongerNeeded(model)
CreateThread(function()
while DoesEntityExist(pizzaProp) do
if not IsEntityPlayingAnim(cache.ped, 'anim@heists@box_carry@', 'idle', 3) then
TaskPlayAnim(cache.ped, 'anim@heists@box_carry@', 'idle', 5.0, 5.0, -1, 51, 0, 0, 0, 0)
end
Wait(1000)
end
RemoveAnimDict('anim@heists@box_carry@')
end)
else
if DoesEntityExist(pizzaProp) then
DetachEntity(cache.ped, true, false)
DeleteEntity(pizzaProp)
pizzaProp = nil
ClearPedTasksImmediately(cache.ped)
end
end
holdingPizza = bool
end
-- Reset job state
local function resetJob()
if oxtarget then
if currZone then exports.ox_target:removeZone(currZone) end
else
if currZone then exports['qb-target']:RemoveZone(currZone) end
end
currZone = nil
if JobBlip then RemoveBlip(JobBlip) end
isHired = false
holdingPizza = false
pizzaDelivered = false
activeOrder = false
doEmote(false)
end
-- Cleanup function
local function cleanupBossPeds()
for _, boss in pairs(bossPoints) do
if DoesEntityExist(boss) then
if oxtarget then
exports.ox_target:removeLocalEntity(boss, {'Liefern starten', 'Liefern beenden'})
else
exports['qb-target']:RemoveTargetEntity(boss)
end
DeleteEntity(boss)
end
end
bossPoints = {}
end
-- Handle taking pizza from vehicle
local function TakePizza()
if IsPedInAnyVehicle(cache.ped, false) or IsEntityDead(cache.ped) or holdingPizza then
return
end
local pos = GetEntityCoords(cache.ped)
if #(pos - vec3(currentDelivery.x, currentDelivery.y, currentDelivery.z)) >= 30.0 then
return QBCore.Functions.Notify('Park dichter am Kundenhaus!', 'error')
end
doEmote(true)
end
-- Handle pizza delivery
local function deliverPizza()
if not hasRequiredJob() then
return QBCore.Functions.Notify('Du hast den Job nicht mehr!', 'error')
end
if holdingPizza and isHired and not pizzaDelivered then
lib.requestAnimDict('timetable@jimmy@doorknock@')
TaskPlayAnim(cache.ped, 'timetable@jimmy@doorknock@', 'knockdoor_idle', 3.0, 1.0, -1, 49, 0, true, true, true)
RemoveAnimDict('timetable@jimmy@doorknock@')
pizzaDelivered = true
if lib.progressCircle({
duration = 7000,
position = 'bottom',
label = 'Ausliefern',
useWhileDead = false,
canCancel = false,
disable = { move = true, car = true, mouse = false, combat = true, },
}) then
local success, data = lib.callback.await('randol_pizzajob:server:Payment', false)
if not success then return end
if JobBlip then RemoveBlip(JobBlip) end
if oxtarget then
if currZone then exports.ox_target:removeZone(currZone) end
else
if currZone then exports['qb-target']:RemoveZone(currZone) end
end
currZone = nil
activeOrder = false
pizzaDelivered = false
doEmote(false)
if data then
NextDelivery(data)
end
end
else
QBCore.Functions.Notify('Hol die Lieferung aus dem Auto... Idiot!', 'error')
end
end
-- Setup next delivery
function NextDelivery(data)
if activeOrder or not hasRequiredJob() then return end
currentDelivery = data.current
if JobBlip then RemoveBlip(JobBlip) end
JobBlip = AddBlipForCoord(currentDelivery.x, currentDelivery.y, currentDelivery.z)
SetBlipSprite(JobBlip, 1)
SetBlipDisplay(JobBlip, 4)
SetBlipScale(JobBlip, 0.8)
SetBlipFlashes(JobBlip, true)
SetBlipAsShortRange(JobBlip, false)
SetBlipColour(JobBlip, 2)
SetBlipRoute(JobBlip, true)
SetBlipRouteColour(JobBlip, 2)
BeginTextCommandSetBlipName('STRING')
AddTextComponentSubstringPlayerName('Nächster Kunde')
EndTextCommandSetBlipName(JobBlip)
if oxtarget then
if currZone then exports.ox_target:removeZone(currZone) end
currZone = exports.ox_target:addSphereZone({
coords = vec3(currentDelivery.x, currentDelivery.y, currentDelivery.z),
radius = 1.3,
debug = false,
options = {
{
icon = 'fa-solid fa-pizza-slice',
label = 'Ausliefern',
onSelect = deliverPizza,
distance = 1.5,
},
}
})
else
if currZone then exports['qb-target']:RemoveZone(currZone) end
local zoneName = 'deliverZone'..math.random(1,1000)
exports['qb-target']:AddBoxZone(zoneName,
vector3(currentDelivery.x, currentDelivery.y, currentDelivery.z),
1.5, 1.5, {
name = zoneName,
heading = 0,
debugPoly = false,
minZ = currentDelivery.z - 1,
maxZ = currentDelivery.z + 2,
}, {
options = {
{
type = "client",
icon = 'fas fa-pizza-slice',
label = 'Ausliefern',
action = function()
deliverPizza()
end
}
},
distance = 2.0
}
)
currZone = zoneName
end
activeOrder = true
QBCore.Functions.Notify('Du hast eine neue Lieferung', 'success')
end
-- Handle finishing work
local function finishWork()
if not hasRequiredJob() then
return QBCore.Functions.Notify('Du hast den Job nicht mehr!', 'error')
end
local pos = GetEntityCoords(cache.ped)
if not isHired then return end
if oxtarget then
exports.ox_target:removeEntity(NetworkGetNetworkIdFromEntity(pizzaCar), {'Take Pizza', 'Return Pizza'})
else
exports['qb-target']:RemoveTargetEntity(pizzaCar)
end
local success = lib.callback.await('randol_pizzajob:server:clockOut', false)
if success then
resetJob()
QBCore.Functions.Notify('Liefern beenden.', 'success')
pizzaCar = nil
end
end
-- Handle vehicle spawn
local function PullOutVehicle(netid, data)
if not hasRequiredJob() then
return QBCore.Functions.Notify('Du hast den Job nicht mehr!', 'error')
end
pizzaCar = lib.waitFor(function()
if NetworkDoesEntityExistWithNetworkId(netid) then
return NetToVeh(netid)
end
end, 'Could not load entity in time.', 1000)
if pizzaCar == 0 then
return QBCore.Functions.Notify('Fehler beim Fahrzeug ausparken.', 'error')
end
SetVehicleNumberPlateText(pizzaCar, 'NORDI'..tostring(math.random(1000, 9999)))
SetVehicleColours(pizzaCar, 111, 111)
SetVehicleDirtLevel(pizzaCar, 1)
TriggerEvent('vehiclekeys:client:SetOwner', QBCore.Functions.GetPlate(pizzaCar))
SetVehicleEngineOn(pizzaCar, true, true)
isHired = true
Wait(500)
if Config.FuelScript.enable then
exports[Config.FuelScript.script]:SetFuel(pizzaCar, 100.0)
else
Entity(pizzaCar).state.fuel = 100
end
if oxtarget then
exports.ox_target:addEntity(netid, {
{
icon = 'fa-solid fa-pizza-slice',
label = 'Lieferung nehmen',
onSelect = TakePizza,
canInteract = function()
return isHired and activeOrder and not holdingPizza and hasRequiredJob()
end,
distance = 2.5
},
{
icon = 'fa-solid fa-pizza-slice',
label = 'Lieferung zurücklegen',
onSelect = function()
doEmote(false)
end,
canInteract = function()
return isHired and activeOrder and holdingPizza and hasRequiredJob()
end,
distance = 2.5
},
})
else
exports['qb-target']:AddTargetEntity(pizzaCar, {
options = {
{
type = "client",
icon = 'fas fa-pizza-slice',
label = 'Lieferung nehmen',
action = function()
TakePizza()
end
},
{
type = "client",
icon = 'fas fa-pizza-slice',
label = 'Lieferung zurücklegen',
action = function()
doEmote(false)
end
}
},
distance = 2.0
})
end
NextDelivery(data)
end
-- Create boss peds at all locations
local function spawnBossPeds()
cleanupBossPeds()
for _, location in pairs(Config.BossLocations) do
lib.requestModel(Config.BossModel)
local boss = CreatePed(0, Config.BossModel, location.coords.x, location.coords.y, location.coords.z, location.coords.w, false, false)
SetEntityAsMissionEntity(boss)
SetPedFleeAttributes(boss, 0, 0)
SetBlockingOfNonTemporaryEvents(boss, true)
SetEntityInvincible(boss, true)
FreezeEntityPosition(boss, true)
-- Phone animation
local phoneModel = `prop_npc_phone_02`
lib.requestModel(phoneModel)
local phoneProps = CreateObject(phoneModel, 0.0, 0.0, 0.0, true, true, true)
AttachEntityToEntity(phoneProps, boss, GetPedBoneIndex(boss, 28422), 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, true, true, false, true, 1, true)
lib.requestAnimDict('cellphone@')
TaskPlayAnim(boss, 'cellphone@', 'cellphone_call_listen_base', 8.0, 1.0, -1, 49, 0, false, false, false)
RemoveAnimDict('cellphone@')
SetModelAsNoLongerNeeded(phoneModel)
if oxtarget then
exports.ox_target:addLocalEntity(boss, {
{
icon = 'fa-solid fa-pizza-slice',
label = 'Liefern starten',
onSelect = function()
if not hasRequiredJob() then
return QBCore.Functions.Notify('Geh weg, du arbeitest nicht hier!', 'error')
end
local netid, data = lib.callback.await('randol_pizzajob:server:spawnVehicle', false, location.vehicleSpawn)
if netid and data then
PullOutVehicle(netid, data)
end
end,
canInteract = function()
return not isHired and hasRequiredJob()
end,
distance = 1.5,
},
{
icon = 'fa-solid fa-pizza-slice',
label = 'Liefern beenden',
onSelect = finishWork,
canInteract = function()
return isHired and hasRequiredJob()
end,
distance = 1.5,
},
})
else
exports['qb-target']:AddTargetEntity(boss, {
options = {
{
type = "client",
icon = 'fas fa-pizza-slice',
label = 'Liefern starten',
action = function()
if not hasRequiredJob() then
return QBCore.Functions.Notify('Geh weg, du arbeitest nicht hier!', 'error')
end
local netid, data = lib.callback.await('randol_pizzajob:server:spawnVehicle', false, location.vehicleSpawn)
if netid and data then
PullOutVehicle(netid, data)
end
end
},
{
type = "client",
icon = 'fas fa-pizza-slice',
label = 'Liefern beenden',
action = function()
finishWork()
end
}
},
distance = 2.0
})
end
table.insert(bossPoints, boss)
end
end
-- Create points for all locations
local function createJobPoints()
for _, location in pairs(Config.BossLocations) do
lib.points.new({
coords = vector3(location.coords.x, location.coords.y, location.coords.z),
distance = 50,
onEnter = spawnBossPeds,
onExit = cleanupBossPeds,
})
end
end
-- Create blips for all locations
local function toggleBlips()
for _, blip in pairs(pizzaBlips) do
if DoesBlipExist(blip) then
RemoveBlip(blip)
end
end
pizzaBlips = {}
if not hasRequiredJob() then return end
for _, location in pairs(Config.BossLocations) do
local blip = AddBlipForCoord(location.coords.x, location.coords.y, location.coords.z)
SetBlipSprite(blip, 545)
SetBlipAsShortRange(blip, true)
SetBlipScale(blip, 0.6)
SetBlipColour(blip, 2)
BeginTextCommandSetBlipName('STRING')
AddTextComponentString(location.blipName or 'Liefern')
EndTextCommandSetBlipName(blip)
table.insert(pizzaBlips, blip)
end
end
-- Events für QB-Target
RegisterNetEvent('pizzajob:client:startWork', function()
if not hasRequiredJob() then
return QBCore.Functions.Notify('Geh weg, du arbeitest nicht hier!', 'error')
end
local netid, data = lib.callback.await('randol_pizzajob:server:spawnVehicle', false, Config.BossLocations[1].vehicleSpawn)
if netid and data then
PullOutVehicle(netid, data)
end
end)
RegisterNetEvent('pizzajob:client:finishWork', function()
finishWork()
end)
RegisterNetEvent('pizzajob:client:takePizza', function()
TakePizza()
end)
RegisterNetEvent('pizzajob:client:returnPizza', function()
doEmote(false)
end)
RegisterNetEvent('pizzajob:client:deliverPizza', function()
deliverPizza()
end)
-- Register core events
RegisterNetEvent('QBCore:Client:OnPlayerLoaded', function()
toggleBlips()
createJobPoints()
end)
RegisterNetEvent('QBCore:Client:OnJobUpdate', function(JobInfo)
toggleBlips()
end)
-- Initial setup
CreateThread(function()
Wait(1000)
toggleBlips()
createJobPoints()
end)
-- Resource handlers
AddEventHandler('onResourceStart', function(resource)
if GetCurrentResourceName() ~= resource then return end
Wait(1000)
toggleBlips()
createJobPoints()
end)
AddEventHandler('onResourceStop', function(resourceName)
if GetCurrentResourceName() ~= resourceName then return end
cleanupBossPeds()
resetJob()
end)