if Config.Inventory ~= 'qs-inventory' then return end -- ════════════════════════════════════════ -- QS-INVENTORY SERVER INTEGRATION -- ════════════════════════════════════════ local Inventory = {} Inventory.Config = { ItemName = Config.ItemName or 'phone', RequireItem = Config.ItemRequired ~= false, DebugMode = Config.Debug or false } -- ════════════════════════════════════════ -- UTILITY FUNCTIONS -- ════════════════════════════════════════ local function Log(type, message, ...) if not Inventory.Config.DebugMode then return end local prefix = '^2[QS-Inventory]^7' if type == 'error' then prefix = '^1[QS-Inventory ERROR]^7' end if type == 'warn' then prefix = '^3[QS-Inventory WARNING]^7' end print(string.format('%s %s', prefix, string.format(message, ...))) end local function ValidatePlayer(source) local src = tonumber(source) if not src or src == 0 then Log('error', 'Invalid source: %s', tostring(source)) return nil end local Player = Core.Functions.GetPlayer(src) if not Player then Log('error', 'Player not found for source: %s', src) return nil end return Player end -- ════════════════════════════════════════ -- INVENTORY FUNCTIONS -- ════════════════════════════════════════ function Inventory.GetAllItems(source) return exports['qs-inventory']:GetInventory(source) or {} end function Inventory.GetItemsByName(source, itemName) itemName = itemName or Inventory.Config.ItemName local items = {} local inventory = Inventory.GetAllItems(source) for slot, item in pairs(inventory) do if item and item.name == itemName then items[#items + 1] = { slot = slot, name = item.name, amount = item.amount or 1, info = item.info or {}, CodemPhoneNumber = item.info and item.info.CodemPhoneNumber or nil, CodemFormattedNumber = item.info and item.info.CodemFormattedNumber or nil } end end return items end function Inventory.GetPhoneItem(source) if not Inventory.Config.RequireItem then Log('debug', 'Item requirement disabled, returning true') return true end local Player = ValidatePlayer(source) if not Player then return false end local amount = exports['qs-inventory']:GetItemTotalAmount(source, Inventory.Config.ItemName) if not amount or amount == 0 then Log('warn', 'Player %s does not have phone item', source) return nil end return true end function Inventory.HasPhoneWithNumber(source, phoneNumber) local phones = Inventory.GetItemsByName(source, Inventory.Config.ItemName) if #phones == 0 then Log('debug', 'Player %s has no phone items', source) return { success = false, itemAmount = 0, } end local foundPhoneWithDifferentNumber = false local differentNumber = nil for i = 1, #phones do local phone = phones[i] if phone.CodemPhoneNumber then if phone.CodemPhoneNumber == phoneNumber then Log('debug', 'Player %s has phone with number %s', source, phoneNumber) return { success = true, myPhone = true } else foundPhoneWithDifferentNumber = true differentNumber = phone.CodemPhoneNumber end end end if foundPhoneWithDifferentNumber then Log('debug', 'Player %s has phone but with different number: %s (expected: %s)', source, differentNumber, phoneNumber) return { success = true, myPhone = false, differentNumber = differentNumber } end Log('debug', 'Player %s has phone but no number assigned', source) return { success = true, myPhone = false, firstSetup = true } end function Inventory.HasAnyPhone(source) local phones = Inventory.GetItemsByName(source, Inventory.Config.ItemName) if #phones == 0 then Log('debug', 'Player %s has no phone items', source) return false end Log('debug', 'Player %s has %d phone item(s)', source, #phones) return true end function Inventory.SetPhoneNumber(source, phoneNumber) if not phoneNumber then Log('error', 'SetPhoneNumber called without phone number') return false end local inventory = Inventory.GetAllItems(source) local updated = false for slot, item in pairs(inventory) do if item and item.name == Inventory.Config.ItemName then if item.info and item.info.CodemPhoneNumber then Log('debug', 'Skipping phone in slot %s (already has number)', slot) goto continue end local newInfo = item.info or {} newInfo.CodemPhoneNumber = phoneNumber newInfo.CodemFormattedNumber = FormatPhoneNumber(phoneNumber) exports['qs-inventory']:SetItemMetadata(source, slot, newInfo) Log('debug', 'Assigned number %s to phone in slot %s', phoneNumber, slot) updated = true break end ::continue:: end if not updated then Log('warn', 'Could not find available phone to assign number for player %s', source) end return updated end function Inventory.UpdatePhoneMetadata(source, phoneNumber, metadata) local inventory = Inventory.GetAllItems(source) local updated = false for slot, item in pairs(inventory) do if item and item.name == Inventory.Config.ItemName then local itemNumber = item.info and item.info.CodemPhoneNumber if itemNumber == phoneNumber then local newInfo = item.info or {} for key, value in pairs(metadata) do if value == "DELETE" or value == nil then newInfo[key] = nil else newInfo[key] = value end end exports['qs-inventory']:SetItemMetadata(source, slot, newInfo) Log('debug', 'Updated metadata for phone %s in slot %s', phoneNumber, slot) updated = true break end end end return updated end function Inventory.RemoveInventoryItem(source, itemname, amount) local Player = ValidatePlayer(source) if not Player then return false end local removed = exports['qs-inventory']:RemoveItem(source, itemname, amount) if removed then Log('debug', 'Removed %d of item %s from player %s', amount, itemname, source) else Log('warn', 'Failed to remove item %s from player %s', itemname, source) end return removed end -- ════════════════════════════════════════ -- USEABLE ITEM REGISTRATION -- ════════════════════════════════════════ Citizen.CreateThread(function() exports['qs-inventory']:CreateUsableItem(Inventory.Config.ItemName, function(source, item) if item then TriggerClientEvent("codem-phone:PhoneUsed", source, item) end end) if Config.BatterySystem.enable then exports['qs-inventory']:CreateUsableItem(Config.BatterySystem.powerBankItemName, function(source, item) TriggerClientEvent("codem-phone:UsePowerBank", source) Inventory.RemoveInventoryItem(source, Config.BatterySystem.powerBankItemName, 1) end) end end) -- ════════════════════════════════════════ -- RPC REGISTRATIONS -- ════════════════════════════════════════ RPC.Register('codem-phone:inventory:HasPhoneItem', function(source, phoneNumber) return Inventory.HasPhoneWithNumber(source, phoneNumber) end) RPC.Register('codem-phone:inventory:HasAnyPhone', function(source) return Inventory.HasAnyPhone(source) end) RPC.Register('codem-phone:inventory:GetPhoneItem', function(source) return Inventory.GetPhoneItem(source) end) -- ════════════════════════════════════════ -- GLOBAL EXPORTS -- ════════════════════════════════════════ GetPlayerInventoryItem = Inventory.GetPhoneItem SetPhoneNumber = Inventory.SetPhoneNumber UpdatePhoneMetadata = Inventory.UpdatePhoneMetadata GetItemsByName = Inventory.GetItemsByName