forked from Simnation/Main
500 lines
16 KiB
Lua
500 lines
16 KiB
Lua
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)
|
|
|