291 lines
		
	
	
	
		
			9.9 KiB
		
	
	
	
		
			Lua
		
	
	
	
	
	
			
		
		
	
	
			291 lines
		
	
	
	
		
			9.9 KiB
		
	
	
	
		
			Lua
		
	
	
	
	
	
| EquippedItem = nil
 | |
| ItemData = nil
 | |
| local AttachedProp
 | |
| local PerformingAction
 | |
| local ProcessingEffect
 | |
| 
 | |
| function DisableControls(denied)
 | |
|     for i=1, #denied do 
 | |
|         DisableControlAction(0, denied[i], true)
 | |
|     end
 | |
| end
 | |
| 
 | |
| function RemoveAttachedProp()
 | |
|     if AttachedProp and DoesEntityExist(AttachedProp) then
 | |
|         DeleteEntity(AttachedProp)
 | |
|     end
 | |
|     AttachedProp = nil
 | |
| end
 | |
| 
 | |
| function AttachProp(name)
 | |
|     RemoveAttachedProp()
 | |
|     local ped = PlayerPedId()
 | |
|     local coords = GetEntityCoords(ped)
 | |
|     local cfg = Config.Items[name]
 | |
|     local prop = cfg.prop
 | |
|     AttachedProp = CreateProp(prop.model, coords.x, coords.y, coords.z, true, true, false)
 | |
|     SetEntityCollision(AttachedProp, false, true)
 | |
|     AttachEntityToEntity(AttachedProp, ped, GetPedBoneIndex(ped, prop.boneId), 
 | |
|     prop.offset.x, prop.offset.y, prop.offset.z, 
 | |
|     prop.rotation.x, prop.rotation.y, prop.rotation.z, false, false, false, true, 2, true)
 | |
| end
 | |
| 
 | |
| function ConsumeItem(name)
 | |
|     if PerformingAction then return end
 | |
|     PerformingAction = "consume"
 | |
|     local cfg = Config.Items[name]
 | |
|     
 | |
|     -- Check if config exists
 | |
|     if not cfg then
 | |
|         print("^1ERROR: Configuration missing for item: " .. name .. "^0")
 | |
|         PerformingAction = nil
 | |
|         return
 | |
|     end
 | |
|     
 | |
|     local anim = cfg.animation
 | |
|     
 | |
|     -- Check if animation exists
 | |
|     if not anim then
 | |
|         print("^1ERROR: Animation configuration missing for item: " .. name .. "^0")
 | |
|         PerformingAction = nil
 | |
|         return
 | |
|     end
 | |
|     
 | |
|     -- Ensure animation time exists
 | |
|     if not anim.time then
 | |
|         print("^1ERROR: Animation time not defined for item: " .. name .. "^0")
 | |
|         anim.time = 2000 -- Default to 2 seconds if missing
 | |
|     end
 | |
|     
 | |
|     local ped = PlayerPedId()
 | |
|     CreateThread(function()
 | |
|         local timeLeft = anim.time -- Now we know this won't be nil
 | |
|         SendNUIMessage({
 | |
|             type = "holdInteract",
 | |
|             bool = true
 | |
|         })
 | |
|         
 | |
|         while PerformingAction == "consume" and timeLeft > 0 do
 | |
|             if anim.time - timeLeft > 100 and not IsEntityPlayingAnim(ped, anim.dict, anim.anim, 13) then
 | |
|                 timeLeft = timeLeft - 100
 | |
|                 PlayAnim(ped, anim.dict, anim.anim, anim.params[1] or 1.0, anim.params[2] or -1.0, anim.params[3] or -1, anim.params[4] or 1, anim.params[5] or 1, anim.params[6], anim.params[7], anim.params[8])
 | |
|                 Wait(100)
 | |
|             else
 | |
|                 timeLeft = timeLeft - 10
 | |
|                 Wait(10)
 | |
|             end
 | |
|         end
 | |
|         
 | |
|         SendNUIMessage({
 | |
|             type = "holdInteract",
 | |
|             bool = false
 | |
|         })
 | |
|         
 | |
|         ClearPedTasks(ped)
 | |
|         
 | |
|         -- Store animation time in a local variable to avoid nil reference
 | |
|         local animTime = anim.time
 | |
|         
 | |
|         -- Check if timeLeft is nil and provide a default
 | |
|         if timeLeft == nil then
 | |
|             timeLeft = 0
 | |
|         end
 | |
|         
 | |
|         -- Now use the local variable for comparison
 | |
|         if timeLeft > 0 and animTime and (animTime - timeLeft <= 100) then
 | |
|             OptionsMenu()
 | |
|             PerformingAction = nil
 | |
|         elseif timeLeft <= 0 then
 | |
|             lib.callback("pickle_consumables:useItem", "", function(result, uses)
 | |
|                 -- Check if cfg still exists (could have changed during callback)
 | |
|                 if not cfg then
 | |
|                     PerformingAction = nil
 | |
|                     return
 | |
|                 end
 | |
|                 
 | |
|                 -- Safe access to cfg.effect
 | |
|                 local effectName = ""
 | |
|                 if cfg.effect and cfg.effect.name then
 | |
|                     effectName = cfg.effect.name
 | |
|                 end
 | |
|                 
 | |
|                 if result and Config.Effects[effectName] and Config.Effects[effectName].process then
 | |
|                     CreateThread(function()
 | |
|                         if ProcessingEffect and not Config.Effects[effectName].canOverlap then return end
 | |
|                         ProcessingEffect = true
 | |
|                         Config.Effects[effectName].process(cfg.effect)
 | |
|                         ProcessingEffect = false
 | |
|                     end)
 | |
|                 end
 | |
|                 
 | |
|                 -- Check if ItemData exists
 | |
|                 if not ItemData then
 | |
|                     PerformingAction = nil
 | |
|                     return
 | |
|                 end
 | |
|                 
 | |
|                 -- Check if uses is nil and provide a default
 | |
|                 if uses == nil then
 | |
|                     print("^1WARNING: Server returned nil for uses. Defaulting to 0.^0")
 | |
|                     uses = 0
 | |
|                 end
 | |
|                 
 | |
|                 ItemData.uses = uses
 | |
|                 if uses < 1 then
 | |
|                     return RemoveItem()
 | |
|                 end
 | |
|                 
 | |
|                 -- Re-fetch config to ensure it's current
 | |
|                 local cfg = Config.Items[name]
 | |
|                 if cfg and cfg.animation and cfg.animation.time then
 | |
|                     SendNUIMessage({
 | |
|                         type = "displayApp",
 | |
|                         data = { quantity = uses, time = cfg.animation.time }
 | |
|                     })
 | |
|                 else
 | |
|                     -- Fallback if config is missing
 | |
|                     SendNUIMessage({
 | |
|                         type = "displayApp",
 | |
|                         data = { quantity = uses, time = 2000 }
 | |
|                     })
 | |
|                 end
 | |
|                 PerformingAction = nil
 | |
|             end)
 | |
|         else
 | |
|             PerformingAction = nil
 | |
|         end
 | |
|     end)
 | |
| end
 | |
| 
 | |
| 
 | |
| 
 | |
| function RemoveItem()
 | |
|     local ped = PlayerPedId()
 | |
|     SendNUIMessage({
 | |
|         type = "hideApp",
 | |
|     })
 | |
|     RemoveAttachedProp()
 | |
|     ClearPedTasks(ped)
 | |
|     EquippedItem = nil
 | |
|     ItemData = nil
 | |
|     PerformingAction = nil
 | |
| end
 | |
| 
 | |
| function ItemThread(name, metadata)
 | |
|     if EquippedItem then return end
 | |
|     EquippedItem = name
 | |
|     ItemData = metadata
 | |
|     AttachProp(name)
 | |
|     local cfg = Config.Items[name]
 | |
|     
 | |
|     -- Check if config exists
 | |
|     if not cfg then
 | |
|         print("^1ERROR: Configuration missing for item: " .. name .. "^0")
 | |
|         return RemoveItem()
 | |
|     end
 | |
|     
 | |
|     -- Safe access to animation time
 | |
|     local animTime = (cfg.animation and cfg.animation.time) or 2000
 | |
|     
 | |
|     SendNUIMessage({
 | |
|         type = "displayApp",
 | |
|         data = { quantity = ItemData.uses, time = animTime }
 | |
|     })
 | |
|     
 | |
|     CreateThread(function()
 | |
|         local pressTime = 0
 | |
|         local holding = false
 | |
|         while EquippedItem == name do
 | |
|             local ped = PlayerPedId()
 | |
|             if IsControlJustPressed(1, 45) then
 | |
|                 TriggerServerEvent("pickle_consumables:returnItem")
 | |
|                 RemoveItem()
 | |
|             elseif IsControlPressed(1, 191) or IsControlPressed(1, 51) then
 | |
|                 if not PerformingAction then
 | |
|                     ConsumeItem(name)
 | |
|                 end
 | |
|             elseif PerformingAction then
 | |
|                 PerformingAction = nil
 | |
|             end
 | |
|             if cfg.idle and not PerformingAction then
 | |
|                 local anim = cfg.idle
 | |
|                 if not IsEntityPlayingAnim(ped, anim.dict, anim.anim, 13) then
 | |
|                     PlayAnim(ped, anim.dict, anim.anim, anim.params[1] or 1.0, anim.params[2] or -1.0, anim.params[3] or -1, anim.params[4] or 1, anim.params[5] or 1, anim.params[6], anim.params[7], anim.params[8])
 | |
|                     Wait(100)
 | |
|                 end
 | |
|             end
 | |
|             if GetEntityHealth(ped) < 1 then 
 | |
|                 local coords = GetEntityCoords(AttachedProp)
 | |
|                 local _, zCoords = GetGroundZFor_3dCoord(coords.x, coords.y, coords.z)
 | |
|                 RemoveItem()
 | |
|                 TriggerServerEvent("pickle_consumables:drop:createDrop", vector3(coords.x, coords.y, zCoords + 1.0))
 | |
|             end
 | |
|             if insideMenu then 
 | |
|                 DisableControls({1, 2, 24, 69, 70, 92, 114, 140, 141, 142, 257, 263, 264})
 | |
|             else
 | |
|                 DisableControls({24, 69, 70, 92, 114, 140, 141, 142, 257, 263, 264})
 | |
|             end
 | |
|             Wait(0)
 | |
|         end
 | |
|         local ped = PlayerPedId()
 | |
|         ClearPedTasks(ped)
 | |
|     end)
 | |
| end
 | |
| 
 | |
| 
 | |
| RegisterNetEvent("pickle_consumables:equipItem", function(name, metadata)
 | |
|     if not Config.Items[name] then return print("^1ERROR: This item is not configured.^0") end
 | |
|     if EquippedItem then return ShowNotification(_L("item_active")) end
 | |
|     ItemThread(name, metadata)
 | |
| end)
 | |
| 
 | |
| RegisterNetEvent("pickle_consumables:removeItem", function()
 | |
|     RemoveItem()
 | |
| end)
 | |
| 
 | |
| AddEventHandler("onResourceStop", function(name)
 | |
|     if name ~= GetCurrentResourceName() then return end
 | |
|     TransitionFromBlurred(0)
 | |
|     RemoveAttachedProp()
 | |
| end)
 | |
| 
 | |
| function ValidateItemConfigs()
 | |
|     print("^2Validating item configurations...^0")
 | |
|     local issues = 0
 | |
|     
 | |
|     for itemName, itemConfig in pairs(Config.Items) do
 | |
|         -- Check for required properties
 | |
|         if not itemConfig.animation then
 | |
|             print("^1WARNING: Item '" .. itemName .. "' is missing animation configuration^0")
 | |
|             issues = issues + 1
 | |
|         elseif not itemConfig.animation.time then
 | |
|             print("^1WARNING: Item '" .. itemName .. "' is missing animation time configuration^0")
 | |
|             issues = issues + 1
 | |
|         end
 | |
|         
 | |
|         if not itemConfig.prop then
 | |
|             print("^1WARNING: Item '" .. itemName .. "' is missing prop configuration^0")
 | |
|             issues = issues + 1
 | |
|         end
 | |
|         
 | |
|         -- Check for effect configuration if referenced
 | |
|         if itemConfig.effect and itemConfig.effect.name then
 | |
|             if not Config.Effects[itemConfig.effect.name] then
 | |
|                 print("^1WARNING: Item '" .. itemName .. "' references non-existent effect: " .. itemConfig.effect.name .. "^0")
 | |
|                 issues = issues + 1
 | |
|             end
 | |
|         end
 | |
|     end
 | |
|     
 | |
|     if issues > 0 then
 | |
|         print("^1Found " .. issues .. " configuration issues. Please fix them to ensure proper functionality.^0")
 | |
|     else
 | |
|         print("^2All item configurations validated successfully!^0")
 | |
|     end
 | |
| end
 | |
| 
 | |
| -- Call this when the resource starts
 | |
| AddEventHandler('onResourceStart', function(resourceName)
 | |
|     if (GetCurrentResourceName() ~= resourceName) then return end
 | |
|     ValidateItemConfigs()
 | |
| end)
 | 
