local QBCore = exports['qb-core']:GetCoreObject() local isRobbing = false local currentContainer = nil local containerBlip = nil local addedEntities = {} -- Debug function local function Debug(msg) if Config.Debug then print("[Container Heist] " .. msg) end end -- Function to get model name from hash local function GetModelNameFromHash(hash) for _, containerType in pairs(Config.ContainerTypes) do if GetHashKey(containerType.model) == hash then return containerType.model end end return "Unknown" end -- Function to check if player is near a valid container local function IsNearValidContainer() local playerPed = PlayerPedId() local playerCoords = GetEntityCoords(playerPed) local foundEntity = nil local foundType = nil local closestDistance = 999.0 -- Check for containers in the area (objects) local objects = GetGamePool('CObject') for _, object in ipairs(objects) do if DoesEntityExist(object) and not IsEntityDead(object) then local model = GetEntityModel(object) local objectCoords = GetEntityCoords(object) local distance = #(playerCoords - objectCoords) if distance <= 5.0 and distance < closestDistance then for _, containerType in pairs(Config.ContainerTypes) do if model == GetHashKey(containerType.model) then foundEntity = object foundType = containerType closestDistance = distance break end end end end end -- Check for trailers in the area (vehicles) local vehicles = GetGamePool('CVehicle') for _, vehicle in ipairs(vehicles) do if DoesEntityExist(vehicle) and not IsEntityDead(vehicle) then local model = GetEntityModel(vehicle) local vehicleCoords = GetEntityCoords(vehicle) local distance = #(playerCoords - vehicleCoords) if distance <= 5.0 and distance < closestDistance then for _, containerType in pairs(Config.ContainerTypes) do if model == GetHashKey(containerType.model) then foundEntity = vehicle foundType = containerType closestDistance = distance break end end end end end return foundEntity, foundType end -- Function to create a blip at the robbery location local function CreateRobberyBlip(coords) if containerBlip then RemoveBlip(containerBlip) end containerBlip = AddBlipForCoord(coords) SetBlipColour(containerBlip, 1) 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 * 2000, function() if containerBlip then RemoveBlip(containerBlip) containerBlip = nil end end) end -- Function to play container robbery animation local function PlayRobberyAnimation(containerType) local playerPed = PlayerPedId() local animDict = containerType.animation.dict local animName = containerType.animation.name RequestAnimDict(animDict) while not HasAnimDictLoaded(animDict) do Wait(10) 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 -- Function to start container robbery local function StartContainerRobbery(container, containerType) if isRobbing then return end isRobbing = true currentContainer = container -- Check if player has required tools local hasTools = lib.callback.await('container_heist:server:checkRequiredItems', false) if not hasTools then lib.notify({ title = Config.Notifications.title, description = Config.Notifications.noTools, type = 'error' }) isRobbing = false currentContainer = nil return end -- Generate a unique ID for this container robbery local containerID = "container_" .. math.random(100000, 999999) -- Check cooldowns local cooldownCheck = lib.callback.await('container_heist:server:checkCooldown', false, containerID) if not cooldownCheck.success then lib.notify({ title = Config.Notifications.title, description = cooldownCheck.message, type = 'error' }) isRobbing = false currentContainer = nil return end -- Check police count local policeCount = lib.callback.await('container_heist:server:getPoliceCount', false) if policeCount < Config.PoliceRequired then lib.notify({ title = Config.Notifications.title, description = Config.Notifications.notEnoughPolice, type = 'error' }) isRobbing = false currentContainer = nil return end -- Position player for animation - use current player position and orientation local playerPed = PlayerPedId() local playerCoords = GetEntityCoords(playerPed) local playerHeading = GetEntityHeading(playerPed) -- Alert police if configured if containerType.policeAlert then local containerCoords = GetEntityCoords(container) local streetName = GetStreetNameFromHashKey(GetStreetNameAtCoord(containerCoords.x, containerCoords.y, containerCoords.z)) TriggerServerEvent('container_heist:server:alertPolice', containerCoords, streetName, containerType.label) end -- Start robbery progress bar PlayRobberyAnimation(containerType) if lib.progressBar({ duration = containerType.animation.duration, label = 'Breaking into ' .. containerType.label, useWhileDead = false, canCancel = true, disable = { car = true, move = true, combat = true, }, anim = { dict = containerType.animation.dict, clip = containerType.animation.name, }, }) then -- Success TriggerServerEvent('container_heist:server:finishRobbery', containerID, containerType.type) lib.notify({ title = Config.Notifications.title, description = Config.Notifications.success, type = 'success' }) else -- Cancelled lib.notify({ title = Config.Notifications.title, description = Config.Notifications.failed, type = 'error' }) end isRobbing = false currentContainer = nil end -- Function to scan and add all nearby containers to target system local function ScanAndAddContainersToTarget() local playerPed = PlayerPedId() local playerCoords = GetEntityCoords(playerPed) local count = 0 -- Check for containers in the area (objects) local objects = GetGamePool('CObject') for _, object in ipairs(objects) do if DoesEntityExist(object) and not IsEntityDead(object) then local objectCoords = GetEntityCoords(object) local distance = #(playerCoords - objectCoords) if distance <= 50.0 then local model = GetEntityModel(object) if not addedEntities[object] then for _, containerType in pairs(Config.ContainerTypes) do if model == GetHashKey(containerType.model) then exports['qb-target']:AddTargetEntity(object, { options = { { type = "client", event = "container_heist:client:startRobbery", icon = "fas fa-angle-double-right", label = "Einbrechen " .. containerType.label, containerType = containerType, } }, distance = 3.0 }) addedEntities[object] = true count = count + 1 break end end end end end end -- Check for trailers in the area (vehicles) local vehicles = GetGamePool('CVehicle') for _, vehicle in ipairs(vehicles) do if DoesEntityExist(vehicle) and not IsEntityDead(vehicle) then local vehicleCoords = GetEntityCoords(vehicle) local distance = #(playerCoords - vehicleCoords) if distance <= 50.0 then local model = GetEntityModel(vehicle) if not addedEntities[vehicle] then for _, containerType in pairs(Config.ContainerTypes) do if model == GetHashKey(containerType.model) then exports['qb-target']:AddTargetEntity(vehicle, { options = { { type = "client", event = "container_heist:client:startRobbery", icon = "fas fa-angle-double-right", label = "Break into " .. containerType.label, containerType = containerType, } }, distance = 3.0 }) addedEntities[vehicle] = true count = count + 1 break end end end end end end return count end -- Command to start container robbery RegisterCommand('robcontainer', function() local container, containerType = IsNearValidContainer() if container and containerType then StartContainerRobbery(container, containerType) else lib.notify({ title = Config.Notifications.title, description = "No valid container nearby!", type = 'error' }) end end, false) -- Command to scan and add all nearby containers to target system RegisterCommand('scancontainers', function() local count = ScanAndAddContainersToTarget() lib.notify({ title = "Container Scanner", description = "Added " .. count .. " containers/trailers to target system", type = 'success', position = 'top', duration = 3000 }) end, false) -- Debug command to show all nearby containers and trailers RegisterCommand('containersdebug', function() if not Config.Debug then return end local playerPed = PlayerPedId() local playerCoords = GetEntityCoords(playerPed) local foundContainers = 0 -- Check for containers in the area (objects) local objects = GetGamePool('CObject') for _, object in ipairs(objects) do if DoesEntityExist(object) and not IsEntityDead(object) then local objectCoords = GetEntityCoords(object) local distance = #(playerCoords - objectCoords) if distance <= 20.0 then local model = GetEntityModel(object) local modelName = "Unknown" for _, containerType in pairs(Config.ContainerTypes) do if model == GetHashKey(containerType.model) then modelName = containerType.model break end end print("Found container object: " .. modelName .. " (Hash: " .. model .. ") at distance: " .. distance) foundContainers = foundContainers + 1 end end end -- Check for trailers in the area (vehicles) local vehicles = GetGamePool('CVehicle') for _, vehicle in ipairs(vehicles) do if DoesEntityExist(vehicle) and not IsEntityDead(vehicle) then local vehicleCoords = GetEntityCoords(vehicle) local distance = #(playerCoords - vehicleCoords) if distance <= 20.0 then local model = GetEntityModel(vehicle) local modelName = "Unknown" for _, containerType in pairs(Config.ContainerTypes) do if model == GetHashKey(containerType.model) then modelName = containerType.model break end end print("Found trailer vehicle: " .. modelName .. " (Hash: " .. model .. ") at distance: " .. distance) foundContainers = foundContainers + 1 end end end print("Total containers/trailers found: " .. foundContainers) end, false) -- Command to identify the model of what you're looking at RegisterCommand('identifycontainer', function() local playerPed = PlayerPedId() local success, entity = GetEntityPlayerIsFreeAimingAt(PlayerId()) if success and DoesEntityExist(entity) then local model = GetEntityModel(entity) local modelName = GetModelNameFromHash(model) local entityType = GetEntityType(entity) local entityTypeStr = "Unknown" if entityType == 1 then entityTypeStr = "Ped" elseif entityType == 2 then entityTypeStr = "Vehicle" elseif entityType == 3 then entityTypeStr = "Object" end print("Entity Type: " .. entityTypeStr) print("Model Hash: " .. model) print("Model Name: " .. modelName) -- Add visual indicator local coords = GetEntityCoords(entity) DrawMarker(0, coords.x, coords.y, coords.z + 2.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 1.0, 1.0, 1.0, 255, 0, 0, 100, false, true, 2, false, nil, nil, false) -- Show notification lib.notify({ title = "Container Identification", description = "Type: " .. entityTypeStr .. "\nModel: " .. modelName .. "\nHash: " .. model, type = 'inform', position = 'top', duration = 5000 }) else lib.notify({ title = "Container Identification", description = "No entity found. Aim at a container or trailer.", type = 'error', position = 'top', duration = 3000 }) end end, false) -- Setup target interactions for containers CreateThread(function() -- Wait for target system to be ready Wait(1000) -- Check if Config.ContainerTypes exists and is not empty if Config.ContainerTypes and next(Config.ContainerTypes) then -- Add target for all container types for _, containerType in pairs(Config.ContainerTypes) do exports['qb-target']:AddTargetModel(containerType.model, { options = { { type = "client", event = "container_heist:client:startRobbery", icon = "fas fa-angle-double-right", label = "Break into " .. containerType.label, containerType = containerType, } }, distance = 3.0 }) end else print("[Container Heist] Error: Config.ContainerTypes is nil or empty!") end end) -- Automatically scan for containers periodically CreateThread(function() while true do ScanAndAddContainersToTarget() Wait(30000) -- Scan every 30 seconds end end) -- Event handler for target interaction RegisterNetEvent('container_heist:client:startRobbery', function(data) local container, _ = IsNearValidContainer() if container then StartContainerRobbery(container, data.containerType) end end) -- Event to show police alert RegisterNetEvent('container_heist:client:policeAlert', function(coords, streetName, containerType) local playerJob = QBCore.Functions.GetPlayerData().job.name local alertTitle = Config.Notifications.policeTitle local alertIcon = 'fas fa-exclamation-triangle' -- Customize alert based on job if playerJob == "marshal" then alertTitle = "MARSHAL SERVICE ALERT" alertIcon = 'fas fa-star' -- Marshal badge icon elseif playerJob == "sheriff" then alertTitle = "SHERIFF DEPARTMENT ALERT" alertIcon = 'fas fa-shield-alt' -- Sheriff badge icon end -- Create alert for police officers lib.notify({ title = alertTitle, description = string.format(Config.Notifications.policeMessage, streetName), type = 'inform', position = 'top', icon = alertIcon, iconColor = '#ff0000', duration = 20000 -- 10 Sekunden (10000 Millisekunden) }) -- 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 and currentContainer then StopAnimTask(PlayerPedId(), "amb@world_human_welding@male@base", "base", 1.0) end end end)