local QBCore = exports['qb-core']:GetCoreObject() -- List of prop models that should be targetable as immediate shredders local shredderPropModels = { 'p_secret_weapon_02', 'prop_bin_08a' } -- List of prop models that should be targetable as storage containers (formerly trash bins) local trashBinPropModels = { 'prop_bin_01a', 'prop_bin_03a', 'prop_bin_04a', 'prop_bin_07a', 'prop_dumpster_01a', 'prop_dumpster_02a', 'prop_dumpster_02b', 'prop_dumpster_3a' } -- Variable to store the current entity being interacted with local currentEntity = nil local currentType = nil -- Add QB-Target to all matching props in the world Citizen.CreateThread(function() -- Add target to shredder props exports['qb-target']:AddTargetModel(shredderPropModels, { options = { { type = "client", event = "disposal:openInventory", icon = "fas fa-dumpster", label = "Müllschredder öffnen", action = function(entity) currentEntity = entity currentType = "shredder" TriggerEvent('disposal:openInventory') end, canInteract = function() return true end, }, { type = "client", event = "disposal:openMenu", icon = "fas fa-fire", label = "Items vernichten", action = function(entity) currentEntity = entity currentType = "shredder" TriggerEvent('disposal:openMenu') end, canInteract = function() return true end, } }, distance = 2.0 }) -- Add target to storage container props (formerly trash bins) exports['qb-target']:AddTargetModel(trashBinPropModels, { options = { { type = "client", event = "disposal:openInventory", icon = "fas fa-box-open", label = "Lager öffnen", action = function(entity) currentEntity = entity currentType = "trash" TriggerEvent('disposal:openInventory') end, canInteract = function() return true end, }, { type = "client", event = "disposal:openMenu", icon = "fas fa-archive", label = "Items lagern", action = function(entity) currentEntity = entity currentType = "trash" TriggerEvent('disposal:openMenu') end, canInteract = function() return true end, } }, distance = 2.0 }) print("^2[DISPOSAL]^7 Added QB-Target to " .. #shredderPropModels .. " shredder models and " .. #trashBinPropModels .. " storage container models") end) -- Function to get container ID from entity function GetContainerIDFromEntity(entity, type) if not entity or not DoesEntityExist(entity) then return nil end local model = GetEntityModel(entity) local entityCoords = GetEntityCoords(entity) return type .. "_" .. model .. "_" .. math.floor(entityCoords.x) .. "_" .. math.floor(entityCoords.y) .. "_" .. math.floor(entityCoords.z) end -- Open container inventory RegisterNetEvent('disposal:openInventory', function() local playerPed = PlayerPedId() local coords = GetEntityCoords(playerPed) if not currentEntity or not DoesEntityExist(currentEntity) then lib.notify({ title = currentType == "shredder" and 'Müllschredder' or 'Lager', description = currentType == "shredder" and 'Kein Schredder gefunden!' or 'Kein Lager gefunden!', type = 'error' }) return end -- Get container ID local containerID = GetContainerIDFromEntity(currentEntity, currentType) if not containerID then return end -- Open inventory with this unique ID TriggerServerEvent('disposal:server:openInventory', containerID, currentType) end) -- Open disposal menu RegisterNetEvent('disposal:openMenu', function() local playerPed = PlayerPedId() local coords = GetEntityCoords(playerPed) if not currentEntity or not DoesEntityExist(currentEntity) then lib.notify({ title = currentType == "shredder" and 'Müllschredder' or 'Lager', description = currentType == "shredder" and 'Kein Schredder gefunden!' or 'Kein Lager gefunden!', type = 'error' }) return end -- Get container ID local containerID = GetContainerIDFromEntity(currentEntity, currentType) if not containerID then return end -- Get items in this container TriggerServerEvent('disposal:server:getItems', containerID, currentType) end) -- Show menu with items RegisterNetEvent('disposal:client:showMenu', function(items, containerID, type) -- Make sure items is a table items = items or {} -- Check if items is empty if next(items) == nil then lib.notify({ title = type == "shredder" and 'Müllschredder' or 'Lager', description = type == "shredder" and 'Der Schredder ist leer!' or 'Das Lager ist leer!', type = 'error' }) return end local menuOptions = {} -- All items action option local actionText = type == "shredder" and "ALLE ITEMS VERNICHTEN" or "ALLE ITEMS LAGERN" local actionDesc = type == "shredder" and 'Vernichtet alle Items im Schredder permanent!' or 'Lagert alle Items im Container!' table.insert(menuOptions, { title = type == "shredder" and '🔥 ' .. actionText or '📦 ' .. actionText, description = actionDesc, icon = type == "shredder" and 'fire' or 'archive', onSelect = function() confirmDestroyAll(containerID, type) end }) table.insert(menuOptions, { title = '─────────────────', description = 'Einzelne Items:', disabled = true }) -- Add individual items to menu local hasItems = false for slot, item in pairs(items) do if item and item.amount and item.amount > 0 then hasItems = true table.insert(menuOptions, { title = (item.label or item.name), description = 'Anzahl: ' .. item.amount .. ' | Slot: ' .. slot, icon = type == "shredder" and 'trash' or 'box', onSelect = function() confirmDestroySingle(item.name, item.amount, slot, containerID, type) end }) end end if not hasItems then lib.notify({ title = type == "shredder" and 'Müllschredder' or 'Lager', description = type == "shredder" and 'Der Schredder ist leer!' or 'Das Lager ist leer!', type = 'error' }) return end lib.registerContext({ id = 'disposal_menu', title = type == "shredder" and '🗑️ Müllschredder Verwaltung' or '📦 Lager Verwaltung', options = menuOptions }) lib.showContext('disposal_menu') end) -- Confirm single item disposal function confirmDestroySingle(itemName, amount, slot, containerID, type) local actionText = type == "shredder" and "vernichten" or "lagern" local actionDesc = type == "shredder" and (itemName .. ' (' .. amount .. 'x) wird permanent gelöscht!') or (itemName .. ' (' .. amount .. 'x) wird im Lager gespeichert!') lib.registerContext({ id = 'dispose_single_confirm', title = '⚠️ Item ' .. actionText .. '?', options = { { title = type == "shredder" and '🔥 Ja, vernichten' or '📦 Ja, lagern', description = actionDesc, icon = type == "shredder" and 'check' or 'box', onSelect = function() TriggerServerEvent('disposal:server:disposeSingle', itemName, amount, slot, containerID, type) end }, { title = '❌ Abbrechen', description = 'Zurück zum Hauptmenü', icon = 'times', onSelect = function() TriggerServerEvent('disposal:server:getItems', containerID, type) end } } }) lib.showContext('dispose_single_confirm') end -- Confirm all items disposal function confirmDestroyAll(containerID, type) local actionText = type == "shredder" and "VERNICHTEN" or "LAGERN" local actionDesc = type == "shredder" and 'ALLE Items im Schredder werden permanent gelöscht!' or 'ALLE Items werden im Lager gespeichert!' lib.registerContext({ id = 'dispose_all_confirm', title = type == "shredder" and '⚠️ WARNUNG ⚠️' or '📦 LAGERUNG', options = { { title = type == "shredder" and '🔥 JA, ALLES VERNICHTEN' or '📦 JA, ALLES LAGERN', description = actionDesc, icon = type == "shredder" and 'fire' or 'archive', onSelect = function() TriggerServerEvent('disposal:server:disposeAll', containerID, type) end }, { title = '❌ Abbrechen', description = 'Zurück zum Hauptmenü', icon = 'times', onSelect = function() TriggerServerEvent('disposal:server:getItems', containerID, type) end } } }) lib.showContext('dispose_all_confirm') end -- Success notification with effect RegisterNetEvent('disposal:client:itemDisposed', function(message, type) lib.notify({ title = type == "shredder" and 'Müllschredder' or 'Lager', description = message, type = 'success', duration = 4000 }) -- Particle effect local playerPed = PlayerPedId() local coords = GetEntityCoords(playerPed) RequestNamedPtfxAsset("core") while not HasNamedPtfxAssetLoaded("core") do Wait(1) end UseParticleFxAssetNextCall("core") -- Different effects for shredder vs storage if type == "shredder" then -- More intense effect for shredder StartParticleFxNonLoopedAtCoord("ent_sht_flame", coords.x, coords.y, coords.z + 1.0, 0.0, 0.0, 0.0, 1.0, false, false, false) PlaySoundFrontend(-1, "CHECKPOINT_PERFECT", "HUD_MINI_GAME_SOUNDSET", 1) else -- Subtle effect for storage StartParticleFxNonLoopedAtCoord("ent_sht_dust", coords.x, coords.y, coords.z + 0.5, 0.0, 0.0, 0.0, 1.0, false, false, false) PlaySoundFrontend(-1, "PICK_UP", "HUD_FRONTEND_DEFAULT_SOUNDSET", 1) end end)