ed
This commit is contained in:
		
							parent
							
								
									0116d75418
								
							
						
					
					
						commit
						c00df8dec6
					
				
					 3 changed files with 60 additions and 461 deletions
				
			
		| 
						 | 
				
			
			@ -1,7 +1,5 @@
 | 
			
		|||
local QBCore = exports['qb-core']:GetCoreObject()
 | 
			
		||||
local isRobbing = false
 | 
			
		||||
local currentZone = nil
 | 
			
		||||
local containerBlip = nil
 | 
			
		||||
local inZone = false
 | 
			
		||||
local currentZoneId = nil
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -12,23 +10,6 @@ local function Debug(msg)
 | 
			
		|||
    end
 | 
			
		||||
end
 | 
			
		||||
 | 
			
		||||
-- Function to draw 3D text
 | 
			
		||||
function DrawText3D(x, y, z, text)
 | 
			
		||||
    -- Set the text properties
 | 
			
		||||
    SetTextScale(0.35, 0.35)
 | 
			
		||||
    SetTextFont(4)
 | 
			
		||||
    SetTextProportional(1)
 | 
			
		||||
    SetTextColour(255, 255, 255, 215)
 | 
			
		||||
    SetTextEntry("STRING")
 | 
			
		||||
    SetTextCentre(1)
 | 
			
		||||
    AddTextComponentString(text)
 | 
			
		||||
    SetDrawOrigin(x, y, z, 0)
 | 
			
		||||
    DrawText(0.0, 0.0)
 | 
			
		||||
    local factor = (string.len(text)) / 370
 | 
			
		||||
    DrawRect(0.0, 0.0125, 0.017 + factor, 0.03, 0, 0, 0, 75)
 | 
			
		||||
    ClearDrawOrigin()
 | 
			
		||||
end
 | 
			
		||||
 | 
			
		||||
-- Function to check if a point is inside a polygon
 | 
			
		||||
local function IsPointInPolygon(point, polygon)
 | 
			
		||||
    local x, y = point.x, point.y
 | 
			
		||||
| 
						 | 
				
			
			@ -61,196 +42,47 @@ local function GetCurrentZone()
 | 
			
		|||
    return nil
 | 
			
		||||
end
 | 
			
		||||
 | 
			
		||||
-- Function to create a blip at the robbery location
 | 
			
		||||
local function CreateRobberyBlip(coords)
 | 
			
		||||
    if containerBlip then
 | 
			
		||||
        RemoveBlip(containerBlip)
 | 
			
		||||
    end
 | 
			
		||||
-- Simple command to test if the script is working
 | 
			
		||||
RegisterCommand('containertest', function()
 | 
			
		||||
    local playerCoords = GetEntityCoords(PlayerPedId())
 | 
			
		||||
    print("Player coords: " .. playerCoords.x .. ", " .. playerCoords.y .. ", " .. playerCoords.z)
 | 
			
		||||
    
 | 
			
		||||
    containerBlip = AddBlipForCoord(coords)
 | 
			
		||||
    
 | 
			
		||||
    -- Set blip color based on job
 | 
			
		||||
    local playerJob = QBCore.Functions.GetPlayerData().job.name
 | 
			
		||||
    if playerJob == "marshal" then
 | 
			
		||||
        SetBlipColour(containerBlip, 38) -- Purple for Marshal
 | 
			
		||||
    elseif playerJob == "sheriff" then
 | 
			
		||||
        SetBlipColour(containerBlip, 16) -- Orange for Sheriff
 | 
			
		||||
    local zone = GetCurrentZone()
 | 
			
		||||
    if zone then
 | 
			
		||||
        QBCore.Functions.Notify("You are in zone: " .. zone.id, "success")
 | 
			
		||||
        print("In zone: " .. zone.id)
 | 
			
		||||
    else
 | 
			
		||||
        SetBlipColour(containerBlip, Config.Blip.color) -- Default color for regular police
 | 
			
		||||
        QBCore.Functions.Notify("You are not in any container zone", "error")
 | 
			
		||||
        print("Not in any zone")
 | 
			
		||||
    end
 | 
			
		||||
    
 | 
			
		||||
    SetBlipSprite(containerBlip, Config.Blip.sprite)
 | 
			
		||||
    SetBlipScale(containerBlip, Config.Blip.scale)
 | 
			
		||||
    SetBlipAsShortRange(containerBlip, true)
 | 
			
		||||
    BeginTextCommandSetBlipName("STRING")
 | 
			
		||||
    AddTextComponentString(Config.Blip.label)
 | 
			
		||||
    EndTextCommandSetBlipName(containerBlip)
 | 
			
		||||
    
 | 
			
		||||
    if Config.Blip.flash then
 | 
			
		||||
        SetBlipFlashes(containerBlip, true)
 | 
			
		||||
    end
 | 
			
		||||
    
 | 
			
		||||
    -- Remove blip after duration
 | 
			
		||||
    SetTimeout(Config.Blip.duration * 1000, function()
 | 
			
		||||
        if containerBlip then
 | 
			
		||||
            RemoveBlip(containerBlip)
 | 
			
		||||
            containerBlip = nil
 | 
			
		||||
        end
 | 
			
		||||
    end)
 | 
			
		||||
end
 | 
			
		||||
end, false)
 | 
			
		||||
 | 
			
		||||
-- Function to play container robbery animation
 | 
			
		||||
local function PlayRobberyAnimation(containerType)
 | 
			
		||||
    local playerPed = PlayerPedId()
 | 
			
		||||
    local animDict = containerType.animation.dict
 | 
			
		||||
    local animName = containerType.animation.name
 | 
			
		||||
-- Command to start robbery (for testing)
 | 
			
		||||
RegisterCommand('robcontainer', function()
 | 
			
		||||
    local zone = GetCurrentZone()
 | 
			
		||||
    
 | 
			
		||||
    RequestAnimDict(animDict)
 | 
			
		||||
    while not HasAnimDictLoaded(animDict) do
 | 
			
		||||
        Wait(10)
 | 
			
		||||
    if zone then
 | 
			
		||||
        QBCore.Functions.Notify("Starting robbery in zone: " .. zone.id, "success")
 | 
			
		||||
        TriggerServerEvent('container_heist:server:testRobbery', zone.id, zone.type)
 | 
			
		||||
    else
 | 
			
		||||
        QBCore.Functions.Notify("You are not in any container zone", "error")
 | 
			
		||||
    end
 | 
			
		||||
    
 | 
			
		||||
    TaskPlayAnim(playerPed, animDict, animName, 8.0, -8.0, containerType.animation.duration, containerType.animation.flag, 0, false, false, false)
 | 
			
		||||
    
 | 
			
		||||
    -- Add particle effects for welding
 | 
			
		||||
    local boneIndex = GetPedBoneIndex(playerPed, 28422)
 | 
			
		||||
    local particleDict = "core"
 | 
			
		||||
    local particleName = "ent_amb_welding"
 | 
			
		||||
    
 | 
			
		||||
    RequestNamedPtfxAsset(particleDict)
 | 
			
		||||
    while not HasNamedPtfxAssetLoaded(particleDict) do
 | 
			
		||||
        Wait(10)
 | 
			
		||||
    end
 | 
			
		||||
    
 | 
			
		||||
    UseParticleFxAssetNextCall(particleDict)
 | 
			
		||||
    local particleHandle = StartParticleFxLoopedOnPedBone(particleName, playerPed, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, boneIndex, 0.5, false, false, false)
 | 
			
		||||
    
 | 
			
		||||
    -- Clean up after animation
 | 
			
		||||
    SetTimeout(containerType.animation.duration, function()
 | 
			
		||||
        StopParticleFxLooped(particleHandle, 0)
 | 
			
		||||
        StopAnimTask(playerPed, animDict, animName, 1.0)
 | 
			
		||||
    end)
 | 
			
		||||
end
 | 
			
		||||
end, false)
 | 
			
		||||
 | 
			
		||||
-- Function to start container robbery
 | 
			
		||||
local function StartContainerRobbery(zone)
 | 
			
		||||
    if isRobbing then return end
 | 
			
		||||
    
 | 
			
		||||
    isRobbing = true
 | 
			
		||||
    currentZone = zone
 | 
			
		||||
    
 | 
			
		||||
    -- Get container type from zone
 | 
			
		||||
    local containerType = Config.ContainerTypes[zone.type]
 | 
			
		||||
    if not containerType then
 | 
			
		||||
        QBCore.Functions.Notify("Invalid container type!", "error")
 | 
			
		||||
        isRobbing = false
 | 
			
		||||
        currentZone = nil
 | 
			
		||||
        return
 | 
			
		||||
    end
 | 
			
		||||
    
 | 
			
		||||
    -- Check if player has required tools
 | 
			
		||||
    QBCore.Functions.TriggerCallback('container_heist:server:checkRequiredItems', function(hasTools)
 | 
			
		||||
        if not hasTools then
 | 
			
		||||
            QBCore.Functions.Notify(Config.Notifications.noTools, "error")
 | 
			
		||||
            isRobbing = false
 | 
			
		||||
            currentZone = nil
 | 
			
		||||
            return
 | 
			
		||||
        end
 | 
			
		||||
        
 | 
			
		||||
        -- Check cooldowns
 | 
			
		||||
        QBCore.Functions.TriggerCallback('container_heist:server:checkCooldown', function(cooldownCheck)
 | 
			
		||||
            if not cooldownCheck.success then
 | 
			
		||||
                QBCore.Functions.Notify(cooldownCheck.message, "error")
 | 
			
		||||
                isRobbing = false
 | 
			
		||||
                currentZone = nil
 | 
			
		||||
                return
 | 
			
		||||
            end
 | 
			
		||||
            
 | 
			
		||||
            -- Check police count
 | 
			
		||||
            QBCore.Functions.TriggerCallback('container_heist:server:getPoliceCount', function(policeCount)
 | 
			
		||||
                if policeCount < Config.PoliceRequired then
 | 
			
		||||
                    QBCore.Functions.Notify(Config.Notifications.notEnoughPolice, "error")
 | 
			
		||||
                    isRobbing = false
 | 
			
		||||
                    currentZone = nil
 | 
			
		||||
                    return
 | 
			
		||||
                end
 | 
			
		||||
                
 | 
			
		||||
                -- Alert police if configured
 | 
			
		||||
                if containerType.policeAlert then
 | 
			
		||||
                    local playerCoords = GetEntityCoords(PlayerPedId())
 | 
			
		||||
                    local streetName = GetStreetNameFromHashKey(GetStreetNameAtCoord(playerCoords.x, playerCoords.y, playerCoords.z))
 | 
			
		||||
                    TriggerServerEvent('container_heist:server:alertPolice', playerCoords, streetName, containerType.label)
 | 
			
		||||
                end
 | 
			
		||||
                
 | 
			
		||||
                -- Start robbery progress bar
 | 
			
		||||
                PlayRobberyAnimation(containerType)
 | 
			
		||||
                
 | 
			
		||||
                QBCore.Functions.Progressbar("container_robbery", 'Breaking into ' .. containerType.label, containerType.animation.duration, false, true, {
 | 
			
		||||
                    disableMovement = true,
 | 
			
		||||
                    disableCarMovement = true,
 | 
			
		||||
                    disableMouse = false,
 | 
			
		||||
                    disableCombat = true,
 | 
			
		||||
                }, {}, {}, {}, function() -- Done
 | 
			
		||||
                    -- Success
 | 
			
		||||
                    TriggerServerEvent('container_heist:server:finishRobbery', zone.id, zone.type)
 | 
			
		||||
                    QBCore.Functions.Notify(Config.Notifications.success, "success")
 | 
			
		||||
                    isRobbing = false
 | 
			
		||||
                    currentZone = nil
 | 
			
		||||
                end, function() -- Cancel
 | 
			
		||||
                    -- Cancelled
 | 
			
		||||
                    QBCore.Functions.Notify(Config.Notifications.failed, "error")
 | 
			
		||||
                    isRobbing = false
 | 
			
		||||
                    currentZone = nil
 | 
			
		||||
                end)
 | 
			
		||||
            end)
 | 
			
		||||
        end, zone.id)
 | 
			
		||||
    end)
 | 
			
		||||
end
 | 
			
		||||
 | 
			
		||||
-- Register usable item event handler - FIXED VERSION
 | 
			
		||||
-- Register usable item event handler
 | 
			
		||||
RegisterNetEvent('container_heist:client:useFlexItem', function()
 | 
			
		||||
    Debug("useFlexItem event triggered")
 | 
			
		||||
    print("useFlexItem event triggered")
 | 
			
		||||
    local zone = GetCurrentZone()
 | 
			
		||||
    
 | 
			
		||||
    if zone then
 | 
			
		||||
        Debug("Player is in zone: " .. zone.id)
 | 
			
		||||
        StartContainerRobbery(zone)
 | 
			
		||||
        print("Player is in zone: " .. zone.id)
 | 
			
		||||
        QBCore.Functions.Notify("Starting robbery with flex tool in zone: " .. zone.id, "success")
 | 
			
		||||
        TriggerServerEvent('container_heist:server:testRobbery', zone.id, zone.type)
 | 
			
		||||
    else
 | 
			
		||||
        QBCore.Functions.Notify(Config.Notifications.notInZone, "error")
 | 
			
		||||
    end
 | 
			
		||||
end)
 | 
			
		||||
 | 
			
		||||
-- Alternative method to handle item use
 | 
			
		||||
RegisterNetEvent('inventory:client:UseItem', function(item)
 | 
			
		||||
    if item.name == Config.RequiredItems.flex.name then
 | 
			
		||||
        Debug("Used item via inventory:client:UseItem: " .. item.name)
 | 
			
		||||
        TriggerEvent('container_heist:client:useFlexItem')
 | 
			
		||||
    end
 | 
			
		||||
end)
 | 
			
		||||
 | 
			
		||||
-- Command to test the robbery (for debugging)
 | 
			
		||||
RegisterCommand('testcontainerrob', function()
 | 
			
		||||
    local zone = GetCurrentZone()
 | 
			
		||||
    
 | 
			
		||||
    if zone then
 | 
			
		||||
        Debug("Testing robbery in zone: " .. zone.id)
 | 
			
		||||
        StartContainerRobbery(zone)
 | 
			
		||||
    else
 | 
			
		||||
        QBCore.Functions.Notify(Config.Notifications.notInZone, "error")
 | 
			
		||||
    end
 | 
			
		||||
end, false)
 | 
			
		||||
 | 
			
		||||
-- Command to toggle debug mode
 | 
			
		||||
RegisterCommand('containerdebug', function()
 | 
			
		||||
    Config.Debug = not Config.Debug
 | 
			
		||||
    
 | 
			
		||||
    if Config.Debug then
 | 
			
		||||
        QBCore.Functions.Notify("Container Debug mode enabled", "primary")
 | 
			
		||||
    else
 | 
			
		||||
        QBCore.Functions.Notify("Container Debug mode disabled", "primary")
 | 
			
		||||
    end
 | 
			
		||||
end, false)
 | 
			
		||||
 | 
			
		||||
-- Main thread for checking if player is in a zone
 | 
			
		||||
CreateThread(function()
 | 
			
		||||
    while true do
 | 
			
		||||
| 
						 | 
				
			
			@ -262,14 +94,14 @@ CreateThread(function()
 | 
			
		|||
                inZone = true
 | 
			
		||||
                currentZoneId = zone.id
 | 
			
		||||
                QBCore.Functions.Notify("You entered " .. zone.label .. ". Use your flex tool to break in.", "primary")
 | 
			
		||||
                Debug("Entered zone: " .. zone.id)
 | 
			
		||||
                print("Entered zone: " .. zone.id)
 | 
			
		||||
            end
 | 
			
		||||
            sleep = 500
 | 
			
		||||
        else
 | 
			
		||||
            if inZone then
 | 
			
		||||
                inZone = false
 | 
			
		||||
                currentZoneId = nil
 | 
			
		||||
                Debug("Left zone")
 | 
			
		||||
                print("Left zone")
 | 
			
		||||
            end
 | 
			
		||||
        end
 | 
			
		||||
        
 | 
			
		||||
| 
						 | 
				
			
			@ -280,8 +112,6 @@ end)
 | 
			
		|||
-- Debug thread for visualizing zones
 | 
			
		||||
CreateThread(function()
 | 
			
		||||
    while true do
 | 
			
		||||
        Wait(0)
 | 
			
		||||
        
 | 
			
		||||
        if Config.Debug then
 | 
			
		||||
            local playerPed = PlayerPedId()
 | 
			
		||||
            local playerCoords = GetEntityCoords(playerPed)
 | 
			
		||||
| 
						 | 
				
			
			@ -299,21 +129,7 @@ CreateThread(function()
 | 
			
		|||
                        point2.x, point2.y, zone.minZ,
 | 
			
		||||
                        255, 0, 0, 255
 | 
			
		||||
                    )
 | 
			
		||||
                    
 | 
			
		||||
                    -- Draw line at max height
 | 
			
		||||
                    DrawLine(
 | 
			
		||||
                        point1.x, point1.y, zone.maxZ,
 | 
			
		||||
                        point2.x, point2.y, zone.maxZ,
 | 
			
		||||
                        255, 0, 0, 255
 | 
			
		||||
                    )
 | 
			
		||||
                    
 | 
			
		||||
                    -- Connect min and max height
 | 
			
		||||
                    DrawLine(
 | 
			
		||||
                        point1.x, point1.y, zone.minZ,
 | 
			
		||||
                        point1.x, point1.y, zone.maxZ,
 | 
			
		||||
                        255, 0, 0, 255
 | 
			
		||||
                    )
 | 
			
		||||
                }
 | 
			
		||||
                end
 | 
			
		||||
                
 | 
			
		||||
                -- Calculate center of zone for label
 | 
			
		||||
                local centerX, centerY = 0, 0
 | 
			
		||||
| 
						 | 
				
			
			@ -326,52 +142,35 @@ CreateThread(function()
 | 
			
		|||
                
 | 
			
		||||
                -- Draw zone label
 | 
			
		||||
                local centerZ = (zone.minZ + zone.maxZ) / 2
 | 
			
		||||
                DrawText3D(centerX, centerY, centerZ, zone.id .. " (" .. zone.type .. ")")
 | 
			
		||||
            }
 | 
			
		||||
                DrawTextOnCoord(centerX, centerY, centerZ, zone.id .. " (" .. zone.type .. ")")
 | 
			
		||||
            end
 | 
			
		||||
            Wait(0)
 | 
			
		||||
        else
 | 
			
		||||
            Wait(1000)
 | 
			
		||||
        end
 | 
			
		||||
    end
 | 
			
		||||
end)
 | 
			
		||||
 | 
			
		||||
-- Event to show police alert
 | 
			
		||||
RegisterNetEvent('container_heist:client:policeAlert', function(coords, streetName, containerLabel)
 | 
			
		||||
    local playerJob = QBCore.Functions.GetPlayerData().job.name
 | 
			
		||||
    local alertTitle = Config.Notifications.policeTitle
 | 
			
		||||
    
 | 
			
		||||
    -- Customize alert based on job
 | 
			
		||||
    if playerJob == "marshal" then
 | 
			
		||||
        alertTitle = "MARSHAL SERVICE ALERT"
 | 
			
		||||
    elseif playerJob == "sheriff" then
 | 
			
		||||
        alertTitle = "SHERIFF DEPARTMENT ALERT"
 | 
			
		||||
-- Function to draw text in 3D space
 | 
			
		||||
function DrawTextOnCoord(x, y, z, text)
 | 
			
		||||
    local onScreen, _x, _y = World3dToScreen2d(x, y, z)
 | 
			
		||||
    if onScreen then
 | 
			
		||||
        SetTextScale(0.35, 0.35)
 | 
			
		||||
        SetTextFont(4)
 | 
			
		||||
        SetTextProportional(1)
 | 
			
		||||
        SetTextColour(255, 255, 255, 215)
 | 
			
		||||
        SetTextEntry("STRING")
 | 
			
		||||
        SetTextCentre(1)
 | 
			
		||||
        AddTextComponentString(text)
 | 
			
		||||
        DrawText(_x, _y)
 | 
			
		||||
        local factor = (string.len(text)) / 370
 | 
			
		||||
        DrawRect(_x, _y + 0.0125, 0.015 + factor, 0.03, 0, 0, 0, 75)
 | 
			
		||||
    end
 | 
			
		||||
    
 | 
			
		||||
    -- Create alert for police officers
 | 
			
		||||
    QBCore.Functions.Notify(alertTitle .. ": " .. string.format(Config.Notifications.policeMessage, streetName), "police", 10000)
 | 
			
		||||
    
 | 
			
		||||
    -- Add blip to map
 | 
			
		||||
    CreateRobberyBlip(coords)
 | 
			
		||||
    
 | 
			
		||||
    -- Play alert sound
 | 
			
		||||
    PlaySound(-1, "Lose_1st", "GTAO_FM_Events_Soundset", 0, 0, 1)
 | 
			
		||||
end)
 | 
			
		||||
 | 
			
		||||
-- Clean up on resource stop
 | 
			
		||||
AddEventHandler('onResourceStop', function(resourceName)
 | 
			
		||||
    if resourceName == GetCurrentResourceName() then
 | 
			
		||||
        if containerBlip then
 | 
			
		||||
            RemoveBlip(containerBlip)
 | 
			
		||||
        end
 | 
			
		||||
        
 | 
			
		||||
        if isRobbing then
 | 
			
		||||
            StopAnimTask(PlayerPedId(), "amb@world_human_welding@male@base", "base", 1.0)
 | 
			
		||||
        end
 | 
			
		||||
    end
 | 
			
		||||
end)
 | 
			
		||||
end
 | 
			
		||||
 | 
			
		||||
-- Print message when resource starts
 | 
			
		||||
AddEventHandler('onClientResourceStart', function(resourceName)
 | 
			
		||||
    if (GetCurrentResourceName() == resourceName) then
 | 
			
		||||
        Debug("Client script started successfully")
 | 
			
		||||
        print("^2[Container Heist]^7: Client script started successfully")
 | 
			
		||||
    end
 | 
			
		||||
end)
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -8,7 +8,6 @@ Config.PoliceRequired = 1 -- Minimum police required
 | 
			
		|||
Config.PoliceJobs = {
 | 
			
		||||
    "police",  -- Regular police
 | 
			
		||||
    "marshal", -- Marshal service
 | 
			
		||||
    "sheriff"  -- Sheriff department
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
-- Required Items
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -1,7 +1,4 @@
 | 
			
		|||
local QBCore = exports['qb-core']:GetCoreObject()
 | 
			
		||||
local zoneCooldowns = {}
 | 
			
		||||
local playerCooldowns = {}
 | 
			
		||||
local globalCooldowns = {}
 | 
			
		||||
 | 
			
		||||
-- Debug function
 | 
			
		||||
local function Debug(msg)
 | 
			
		||||
| 
						 | 
				
			
			@ -10,226 +7,30 @@ local function Debug(msg)
 | 
			
		|||
    end
 | 
			
		||||
end
 | 
			
		||||
 | 
			
		||||
-- Register usable item - FIXED VERSION
 | 
			
		||||
QBCore.Functions.CreateUseableItem(Config.RequiredItems.flex.name, function(source, item)
 | 
			
		||||
    local src = source
 | 
			
		||||
    Debug("Player " .. src .. " used item: " .. Config.RequiredItems.flex.name)
 | 
			
		||||
    TriggerClientEvent('container_heist:client:useFlexItem', src)
 | 
			
		||||
-- Register usable item
 | 
			
		||||
QBCore.Functions.CreateUseableItem(Config.RequiredItems.flex.name, function(source)
 | 
			
		||||
    print("Player " .. source .. " used item: " .. Config.RequiredItems.flex.name)
 | 
			
		||||
    TriggerClientEvent('container_heist:client:useFlexItem', source)
 | 
			
		||||
end)
 | 
			
		||||
 | 
			
		||||
-- Check if player has required items
 | 
			
		||||
QBCore.Functions.CreateCallback('container_heist:server:checkRequiredItems', function(source, cb)
 | 
			
		||||
    local src = source
 | 
			
		||||
    local Player = QBCore.Functions.GetPlayer(src)
 | 
			
		||||
    if not Player then return cb(false) end
 | 
			
		||||
    
 | 
			
		||||
    -- Check for required flex tool
 | 
			
		||||
    local hasItem = exports['tgiann-inventory']:HasItem(src, Config.RequiredItems.flex.name, Config.RequiredItems.flex.amount)
 | 
			
		||||
    Debug("Player " .. src .. " has required item: " .. tostring(hasItem))
 | 
			
		||||
    cb(hasItem)
 | 
			
		||||
end)
 | 
			
		||||
 | 
			
		||||
-- Check cooldowns
 | 
			
		||||
QBCore.Functions.CreateCallback('container_heist:server:checkCooldown', function(source, cb, zoneId)
 | 
			
		||||
    local src = source
 | 
			
		||||
    local Player = QBCore.Functions.GetPlayer(src)
 | 
			
		||||
    if not Player then return cb({success = false, message = "Player not found"}) end
 | 
			
		||||
    
 | 
			
		||||
    local citizenId = Player.PlayerData.citizenid
 | 
			
		||||
    local currentTime = os.time()
 | 
			
		||||
    
 | 
			
		||||
    -- Check player cooldown
 | 
			
		||||
    if playerCooldowns[citizenId] and (currentTime - playerCooldowns[citizenId]) < (Config.CooldownTime * 60) then
 | 
			
		||||
        local timeLeft = math.ceil(((playerCooldowns[citizenId] + (Config.CooldownTime * 60)) - currentTime) / 60)
 | 
			
		||||
        return cb({success = false, message = "You need to wait " .. timeLeft .. " more minutes before attempting another heist!"})
 | 
			
		||||
    end
 | 
			
		||||
    
 | 
			
		||||
    -- Check zone cooldown
 | 
			
		||||
    if zoneCooldowns[zoneId] and (currentTime - zoneCooldowns[zoneId]) < (Config.CooldownTime * 60) then
 | 
			
		||||
        return cb({success = false, message = Config.Notifications.alreadyRobbed})
 | 
			
		||||
    end
 | 
			
		||||
    
 | 
			
		||||
    -- Find zone type
 | 
			
		||||
    local zoneType = nil
 | 
			
		||||
    for _, zone in pairs(Config.ContainerZones) do
 | 
			
		||||
        if zone.id == zoneId then
 | 
			
		||||
            zoneType = zone.type
 | 
			
		||||
            break
 | 
			
		||||
        end
 | 
			
		||||
    end
 | 
			
		||||
    
 | 
			
		||||
    if not zoneType then
 | 
			
		||||
        return cb({success = false, message = "Invalid zone!"})
 | 
			
		||||
    end
 | 
			
		||||
    
 | 
			
		||||
    -- Check global cooldown for container type
 | 
			
		||||
    if globalCooldowns[zoneType] and (currentTime - globalCooldowns[zoneType]) < (Config.GlobalCooldown * 60) then
 | 
			
		||||
        local timeLeft = math.ceil(((globalCooldowns[zoneType] + (Config.GlobalCooldown * 60)) - currentTime) / 60)
 | 
			
		||||
        return cb({success = false, message = Config.Notifications.globalCooldown .. " (" .. timeLeft .. " minutes left)"})
 | 
			
		||||
    end
 | 
			
		||||
    
 | 
			
		||||
    cb({success = true})
 | 
			
		||||
end)
 | 
			
		||||
 | 
			
		||||
-- Get police count
 | 
			
		||||
QBCore.Functions.CreateCallback('container_heist:server:getPoliceCount', function(source, cb)
 | 
			
		||||
    local policeCount = 0
 | 
			
		||||
    local players = QBCore.Functions.GetPlayers()
 | 
			
		||||
    
 | 
			
		||||
    for _, playerId in ipairs(players) do
 | 
			
		||||
        local Player = QBCore.Functions.GetPlayer(playerId)
 | 
			
		||||
        if Player then
 | 
			
		||||
            -- Check if player's job is in the list of police jobs
 | 
			
		||||
            for _, jobName in ipairs(Config.PoliceJobs) do
 | 
			
		||||
                if Player.PlayerData.job.name == jobName and Player.PlayerData.job.onduty then
 | 
			
		||||
                    policeCount = policeCount + 1
 | 
			
		||||
                    break -- No need to check other job names for this player
 | 
			
		||||
                end
 | 
			
		||||
            end
 | 
			
		||||
        end
 | 
			
		||||
    end
 | 
			
		||||
    
 | 
			
		||||
    cb(policeCount)
 | 
			
		||||
end)
 | 
			
		||||
 | 
			
		||||
-- Alert police
 | 
			
		||||
RegisterNetEvent('container_heist:server:alertPolice', function(coords, streetName, containerLabel)
 | 
			
		||||
    local src = source
 | 
			
		||||
    local players = QBCore.Functions.GetPlayers()
 | 
			
		||||
    
 | 
			
		||||
    for _, playerId in ipairs(players) do
 | 
			
		||||
        local Player = QBCore.Functions.GetPlayer(playerId)
 | 
			
		||||
        if Player then
 | 
			
		||||
            -- Check if player's job is in the list of police jobs
 | 
			
		||||
            for _, jobName in ipairs(Config.PoliceJobs) do
 | 
			
		||||
                if Player.PlayerData.job.name == jobName and Player.PlayerData.job.onduty then
 | 
			
		||||
                    TriggerClientEvent('container_heist:client:policeAlert', playerId, coords, streetName, containerLabel)
 | 
			
		||||
                    break -- No need to send multiple alerts to the same player
 | 
			
		||||
                end
 | 
			
		||||
            end
 | 
			
		||||
        end
 | 
			
		||||
    end
 | 
			
		||||
end)
 | 
			
		||||
 | 
			
		||||
-- Finish robbery and give rewards
 | 
			
		||||
RegisterNetEvent('container_heist:server:finishRobbery', function(zoneId, containerTypeName)
 | 
			
		||||
-- Test robbery event
 | 
			
		||||
RegisterNetEvent('container_heist:server:testRobbery', function(zoneId, zoneType)
 | 
			
		||||
    local src = source
 | 
			
		||||
    local Player = QBCore.Functions.GetPlayer(src)
 | 
			
		||||
    if not Player then return end
 | 
			
		||||
    
 | 
			
		||||
    local citizenId = Player.PlayerData.citizenid
 | 
			
		||||
    local currentTime = os.time()
 | 
			
		||||
    print("Player " .. src .. " started robbery in zone: " .. zoneId .. " of type: " .. zoneType)
 | 
			
		||||
    TriggerClientEvent('QBCore:Notify', src, "Robbery started in zone: " .. zoneId, "success")
 | 
			
		||||
    
 | 
			
		||||
    -- Set cooldowns
 | 
			
		||||
    playerCooldowns[citizenId] = currentTime
 | 
			
		||||
    zoneCooldowns[zoneId] = currentTime
 | 
			
		||||
    globalCooldowns[containerTypeName] = currentTime
 | 
			
		||||
    
 | 
			
		||||
    -- Get container type
 | 
			
		||||
    local containerType = Config.ContainerTypes[containerTypeName]
 | 
			
		||||
    if not containerType then
 | 
			
		||||
        Debug("Container type not found: " .. containerTypeName)
 | 
			
		||||
        return
 | 
			
		||||
    end
 | 
			
		||||
    
 | 
			
		||||
    -- Decrease durability of flex tool if configured
 | 
			
		||||
    if Config.RequiredItems.flex.durability then
 | 
			
		||||
        local itemData = exports['tgiann-inventory']:GetItemByName(src, Config.RequiredItems.flex.name)
 | 
			
		||||
        if itemData and itemData.info then
 | 
			
		||||
            local newDurability = math.max(0, (itemData.info.durabilityPercent or 100) - Config.RequiredItems.flex.durabilityDecrease)
 | 
			
		||||
            exports['tgiann-inventory']:UpdateItemMetadata(src, Config.RequiredItems.flex.name, itemData.slot, {
 | 
			
		||||
                durabilityPercent = newDurability,
 | 
			
		||||
                serie = itemData.info.serie or "TOOL-" .. math.random(100000, 999999),
 | 
			
		||||
                usedTotalAmmo = itemData.info.usedTotalAmmo or 0,
 | 
			
		||||
                ammo = itemData.info.ammo or 0
 | 
			
		||||
            })
 | 
			
		||||
            
 | 
			
		||||
            -- Remove item if durability reaches 0
 | 
			
		||||
            if newDurability <= 0 and Config.RequiredItems.flex.remove then
 | 
			
		||||
                exports['tgiann-inventory']:RemoveItem(src, Config.RequiredItems.flex.name, 1)
 | 
			
		||||
                TriggerClientEvent('QBCore:Notify', src, "Your " .. Config.RequiredItems.flex.label .. " broke!", "error")
 | 
			
		||||
            end
 | 
			
		||||
        end
 | 
			
		||||
    elseif Config.RequiredItems.flex.remove then
 | 
			
		||||
        -- Remove item if configured
 | 
			
		||||
        exports['tgiann-inventory']:RemoveItem(src, Config.RequiredItems.flex.name, Config.RequiredItems.flex.amount)
 | 
			
		||||
    end
 | 
			
		||||
    
 | 
			
		||||
    -- Give rewards based on chances
 | 
			
		||||
    local rewardsGiven = 0
 | 
			
		||||
    for _, reward in pairs(containerType.rewards) do
 | 
			
		||||
        if math.random(1, 100) <= reward.chance then
 | 
			
		||||
            local amount = math.random(reward.min, reward.max)
 | 
			
		||||
            
 | 
			
		||||
            if reward.item == "cash" then
 | 
			
		||||
                Player.Functions.AddMoney("cash", amount)
 | 
			
		||||
                TriggerClientEvent('QBCore:Notify', src, "Found $" .. amount, "success")
 | 
			
		||||
            else
 | 
			
		||||
                -- Add item with proper metadata for weapons
 | 
			
		||||
                if string.match(reward.item, "weapon_") then
 | 
			
		||||
                    exports['tgiann-inventory']:AddItem(src, reward.item, amount, nil, {
 | 
			
		||||
                        serie = "HEIST-" .. math.random(100000, 999999),
 | 
			
		||||
                        durabilityPercent = 100,
 | 
			
		||||
                        usedTotalAmmo = 0,
 | 
			
		||||
                        ammo = 0
 | 
			
		||||
                    })
 | 
			
		||||
                else
 | 
			
		||||
                    exports['tgiann-inventory']:AddItem(src, reward.item, amount)
 | 
			
		||||
                end
 | 
			
		||||
                
 | 
			
		||||
                TriggerClientEvent('QBCore:Notify', src, "Found " .. amount .. "x " .. reward.label, "success")
 | 
			
		||||
            end
 | 
			
		||||
            
 | 
			
		||||
            rewardsGiven = rewardsGiven + 1
 | 
			
		||||
        end
 | 
			
		||||
    end
 | 
			
		||||
    
 | 
			
		||||
    if rewardsGiven == 0 then
 | 
			
		||||
        TriggerClientEvent('QBCore:Notify', src, "The container was empty!", "error")
 | 
			
		||||
    end
 | 
			
		||||
end)
 | 
			
		||||
 | 
			
		||||
-- Clean up cooldowns periodically
 | 
			
		||||
CreateThread(function()
 | 
			
		||||
    while true do
 | 
			
		||||
        Wait(60000) -- Check every minute
 | 
			
		||||
        local currentTime = os.time()
 | 
			
		||||
        
 | 
			
		||||
        -- Clean up player cooldowns
 | 
			
		||||
        for citizenId, cooldownTime in pairs(playerCooldowns) do
 | 
			
		||||
            if (currentTime - cooldownTime) > (Config.CooldownTime * 60) then
 | 
			
		||||
                playerCooldowns[citizenId] = nil
 | 
			
		||||
            end
 | 
			
		||||
        end
 | 
			
		||||
        
 | 
			
		||||
        -- Clean up zone cooldowns
 | 
			
		||||
        for zoneId, cooldownTime in pairs(zoneCooldowns) do
 | 
			
		||||
            if (currentTime - cooldownTime) > (Config.CooldownTime * 60) then
 | 
			
		||||
                zoneCooldowns[zoneId] = nil
 | 
			
		||||
            end
 | 
			
		||||
        end
 | 
			
		||||
        
 | 
			
		||||
        -- Clean up global cooldowns
 | 
			
		||||
        for containerType, cooldownTime in pairs(globalCooldowns) do
 | 
			
		||||
            if (currentTime - cooldownTime) > (Config.GlobalCooldown * 60) then
 | 
			
		||||
                globalCooldowns[containerType] = nil
 | 
			
		||||
            end
 | 
			
		||||
        end
 | 
			
		||||
    end
 | 
			
		||||
end)
 | 
			
		||||
 | 
			
		||||
-- Alternative method to register usable item for tgiann-inventory
 | 
			
		||||
RegisterNetEvent('QBCore:Server:UseItem', function(source, item)
 | 
			
		||||
    if item.name == Config.RequiredItems.flex.name then
 | 
			
		||||
        Debug("Player " .. source .. " used item via QBCore:Server:UseItem: " .. item.name)
 | 
			
		||||
        TriggerClientEvent('container_heist:client:useFlexItem', source)
 | 
			
		||||
    end
 | 
			
		||||
    -- Give a test reward
 | 
			
		||||
    exports['tgiann-inventory']:AddItem(src, "cash", 1000)
 | 
			
		||||
    TriggerClientEvent('QBCore:Notify', src, "You found $1000!", "success")
 | 
			
		||||
end)
 | 
			
		||||
 | 
			
		||||
-- Print message when resource starts
 | 
			
		||||
AddEventHandler('onResourceStart', function(resourceName)
 | 
			
		||||
    if (GetCurrentResourceName() == resourceName) then
 | 
			
		||||
        print('^2[Container Heist]^7: Script started successfully')
 | 
			
		||||
        print('^2[Container Heist]^7: Registered usable item: ' .. Config.RequiredItems.flex.name)
 | 
			
		||||
        print("^2[Container Heist]^7: Server script started successfully")
 | 
			
		||||
        print("^2[Container Heist]^7: Registered usable item: " .. Config.RequiredItems.flex.name)
 | 
			
		||||
    end
 | 
			
		||||
end)
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue