> For the complete documentation index, see [llms.txt](https://docs.snt.gg/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://docs.snt.gg/resources/snt-inventory-pro.md).

# snt-inventory-pro

{% hint style="info" %}
**Em breve**, anexaremos aqui um vídeo explicativo e demonstrativo do painel administrativo por completo!
{% endhint %}

<figure><img src="https://3252830642-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FZteT3urr6Kudn1K5eHDp%2Fuploads%2F1nGF1V8OLofLDVWytNTz%2Ft_INVENTORY-PRO.jpg?alt=media&amp;token=3666ffe3-9cf4-4a65-8e35-93387a872fbc" alt=""><figcaption></figcaption></figure>

***

## Conceitos e referências

### Convenções de identificadores

* **`id`** *(number)* — **characterId**: o identificador do PERSONAGEM no framework. Persiste entre sessões e funciona offline. **Não** é o server id da conexão.
* **`src`** *(number)* — **server id**: o "playerId" da sessão atual do jogador conectado. Muda a cada conexão.
* **`chestId`** *(string)* — id de um baú. Ex.: `bau_central`, `trunk:<placa>:<hash_do_modelo>` (porta-malas), `gloves:<placa>` (porta-luvas), `container:<uuid>` (aluguel).

***

### Estrutura de slots

Estrutura de todo item guardado (jogador, baú, correio, etc.):

```lua
{
  i  = 'bandagem',  -- string : id do item (minúsculo)
  a  = 3,           -- number : quantidade (>= 1)
  d  = 512,         -- number? : durabilidade RESTANTE em segundos. Ausente = sem durabilidade; <= 0 = quebrado
  dm = 1440,        -- number? : durabilidade MÁXIMA (fixada na criação). O % exibido é d/dm
  md = { ... },     -- table?  : metadata da instância. SÓ itens com a == 1 podem ter md
}
```

Chaves de `md` que o próprio sistema usa (você pode gravar outras livremente):

* `wid` *(string)* — id único da instância de uma arma (liga o slot à arma equipada na mão).
* `ammo` *(number)* — munição carregada no pente.
* `atc` *(table)* — attachments equipados, no formato `{ [hashDoComponente] = 1 }`.
* `cnm` *(string)* — nome customizado (sobrepõe o nome do catálogo na UI).
* `cdsc` *(string)* — descrição customizada (sobrepõe a descrição; aceita o placeholder `${ITEM}`).

***

### Verificação de uso

É possível verificar se o snt-inventory-pro está em uso simplesmente checando a existência da GlobalState `SNT_INVENTORY_PRO`.

```lua
if GlobalState.SNT_INVENTORY_PRO then
    -- snt-inventory-pro em uso no servidor.
end
```

***

### Comando `sntinventory`

Comando único do recurso, com comportamento definido pela origem. **In-game** abre exclusivamente o painel de administração (argumentos são ignorados), exigindo `adminPermission` de `config/server.lua` e, se `lockAdministrationForIdentifiers` não estiver vazio, também um dos identificadores listados — sem permissão, notifica `NO_ADMIN_PANEL_PERMISSION`.&#x20;

**No console** (`src == 0`) ficam as ferramentas administrativas, disponíveis só após a autenticação de licença: `conversion`, que executa `conversions/<framework>/<arquivo>.lua` com os nomes sanitizados por `^[%w_%-]+$` (sem path traversal), e `reload`, que recarrega em runtime os quatro arquivos de config do servidor de forma isolada. O `reload` é **apenas server-side**: `config/functions/client.lua` e `config/api/client.lua` continuam exigindo `ensure`/`restart`, e ele sobrescreve definições sem removê-las (renomear um `Server.metodo` deixa o antigo vivo até um restart real).

```
/sntinventory
```

```
sntinventory conversion <framework> <arquivo>

# disponíveis: creative_network (inventories, itemlist) | vrpex (inventories)
sntinventory conversion vrpex inventories
→ conversions/vrpex/inventories.lua executed.
```

```
sntinventory reload

reloading server config...
config/framework.lua reloaded.                  # tabela Framework
config/server.lua reloaded.                     # token, adminPermission, webhooks (INSERT IGNORE)
config/api/server.lua reloaded.                 # tabela API
config/functions/server.lua reloaded (old handlers/threads cancelled).
note: client functions still require a full ensure/restart to update.
```

***

## Multichars - Cached Identifiers

#### `clearIdentifierCache(source)`

Invalida na hora os caches por-source (identifier, identidade e flags de admin) de um jogador. Use quando o jogador **troca de personagem sem reconectar** (caso sua base possua multiplos personagens, mesma source, `id` de personagem diferente) — sem isso os caches ficam apontando pro personagem anterior por até 30s.

* `source` *(number)* — server id do jogador. Chame **depois** que o framework já associou a source ao novo personagem.
* **Retorno** *(boolean)* — `true` se limpou; `false` se a `source` for inválida.

> **Quando chamar:** no fluxo de **seleção de personagem** do servidor, na troca sem relogar. **Não é necessário** no logout/relogin normal — o `playerDropped` já limpa. Idempotente e sem custo se chamado sem necessidade. **Não** descarrega a instância de inventário do personagem antigo.

```lua
-- Ex.: no seu evento de seleção de personagem, após trocar de char sem reconectar
exports['snt-inventory-pro']:clearIdentifierCache(source)
```

***

## Exports shared

#### `getItemList()`

Retorna o catálogo inteiro de itens registrados. É uma **referência** — não mutar.

* **Retorno** *(table)* — `{ [itemId] = config }`.

```lua
local all = exports['snt-inventory-pro']:getItemList()
```

#### `isRegisteredItem(item)`

* `item` *(string)* — id do item.
* **Retorno** *(boolean)*.

```lua
if exports['snt-inventory-pro']:isRegisteredItem('bandagem') then end
```

#### `getItemConfig(item)`

Config bruta do item. Referência — não mutar.

* `item` *(string)*.
* **Retorno** *(table | nil)*.

```lua
local cfg = exports['snt-inventory-pro']:getItemConfig('bandagem')
```

#### `getItemName(item)`

* `item` *(string)*.
* **Retorno** *(string)* — nome de exibição, ou `'?'` se não registrado.

```lua
local name = exports['snt-inventory-pro']:getItemName('bandagem')
```

#### `getItemType(item)`

Itens com `weapon` definido sempre retornam `'weapon'`, independente do campo `type`.

* `item` *(string)*.
* **Retorno** *(string)* — um de: `'weapon'`, `'use'`, `'consumable'`, `'ammo'`, `'weapon-attach'`, `'throwable'`, `'none'`/`'undefined'`.

```lua
local t = exports['snt-inventory-pro']:getItemType('rifle') -- 'weapon'
```

#### `getItemWeight(item)`

* `item` *(string)*.
* **Retorno** *(number)* — peso unitário em kg, ou 0.

```lua
local w = exports['snt-inventory-pro']:getItemWeight('bandagem')
```

#### `getItemDurability(item)`

Durabilidade máxima do **config atual** do item, em segundos. Para a durabilidade real de uma instância use `getSlotMaxDurability`.

* `item` *(string)*.
* **Retorno** *(number)* — segundos, ou 0 se o item não tem durabilidade.

```lua
local d = exports['snt-inventory-pro']:getItemDurability('rifle')
```

#### `getSlotMaxDurability(slotData)`

Durabilidade máxima de referência de um SLOT específico. Prioriza o snapshot `dm` do slot (fixado na criação); só cai no config atual se `dm` estiver ausente — assim, mudar a durabilidade no painel não altera itens já existentes.

* `slotData` *(table)* — o shape do slot.
* **Retorno** *(number)* — segundos, ou 0.

```lua
local maxD = exports['snt-inventory-pro']:getSlotMaxDurability(slotData)
```

#### `getItemDescription(item)`

* `item` *(string)*.
* **Retorno** *(string)* — descrição (pode conter HTML simples), ou `''`.

```lua
local desc = exports['snt-inventory-pro']:getItemDescription('bandagem')
```

#### `getItemLimit(item)`

Limite máximo de posse do item. Aplicado **somente ao inventário do jogador** (baús ignoram).

* `item` *(string)*.
* **Retorno** *(number)* — limite configurado, ou 0 (sem limite).

```lua
local lim = exports['snt-inventory-pro']:getItemLimit('lockpick')
```

#### `itemSpoilAction(item)`

Ação configurada para quando o item quebra (`items.json → item.spoil`).

* `item` *(string)*.
* **Retorno** *(string, string|nil)*:
  * 1º: `'remove'` (padrão — item some), `'keep'` (mantém quebrado, d=0) ou `'transform'` (vira outro item).
  * 2º: id do item de destino — presente **só** quando o 1º é `'transform'`.

```lua
local action, into = exports['snt-inventory-pro']:itemSpoilAction('leite')
```

#### `isItemPropertyEnabled(item, key)`

Lê uma propriedade booleana **crua** do config, sem default (ausente = false).

* `item` *(string)*.
* `key` *(string)* — nome da propriedade (ex.: `'safe'`, `'marketplace'`).
* **Retorno** *(boolean)*.

```lua
local safe = exports['snt-inventory-pro']:isItemPropertyEnabled('diamante', 'safe')
```

#### `isItemFlagAllowed(item, key)`

Checa uma flag com semântica **default-TRUE** — só um `false` explícito no config bloqueia. Use para `droppable`, `sendable`, `storable`, `stolenable`, `safestorable`.

* `item` *(string)*.
* `key` *(string)* — nome da flag.
* **Retorno** *(boolean)* — `true` se permitido/não bloqueado; `false` se o item não existe ou a flag está explicitamente `false`.

```lua
local canDrop = exports['snt-inventory-pro']:isItemFlagAllowed('celular', 'droppable')
```

#### `hasItemTag(item, tag)`

Verifica se um item possui determinada tag. As tags são cadastradas no painel administrativo em **Itens → Tags** (separadas por vírgula) e ficam salvas no `items.json` no formato de lista.

* `item` *(string)* — index do item (ex.: `'apple'`).&#x20;
* `tag` *(string)* — tag a verificar.&#x20;
* **Retorno** *(boolean)* — `true` se o item possui a tag; `false` caso contrário.

Retorna `false` (sem erro) quando: o item não existe, o item não tem tags cadastradas, a lista de tags está malformada, ou a `tag` informada não é uma string válida.

```lua
-- Item cadastrado com as tags: comida, perecivel
exports['snt-inventory-pro']:hasItemTag('apple', 'comida')      --> true
exports['snt-inventory-pro']:hasItemTag('apple', 'COMIDA')      --> true  (case-insensitive)
exports['snt-inventory-pro']:hasItemTag('apple', 'ilegal')      --> false
exports['snt-inventory-pro']:hasItemTag('rope', 'comida')       --> false (item sem tags)

-- Ex.: bloquear o uso de itens marcados como ilegais em zona segura
if exports['snt-inventory-pro']:hasItemTag(item, 'ilegal') and isInSafeZone(src) then
    notify(src, 'ITEM_BLOCKED_IN_SAFEZONE')
    return false
end
```

***

## Exports server

#### `getCharacterInventory(id)`

Retorna o objeto de inventário do personagem (carrega/cria se necessário).

* `id` *(number)* — characterId.
* **Retorno** *(table)* — objeto do inventário:
  * `id` *(number)*, `kind` *(string)* — sempre `'player'`.
  * `inventory` *(table)* — itens: `{ ['0'] = slot, ['1'] = slot, ... }` (chaves são strings numéricas; slot vazio não existe na tabela).
  * `slots` *(number)* — total de slots (padrão do config **+** comprados).
  * `maxWeight` *(number)* — peso máximo base em kg (não inclui o extra temporário concedido via API).
  * `purchasedSlots` *(number)* — slots extras comprados (já somados em `slots`).
  * `safeData` *(table)* — conteúdo dos bolsos seguros (mesmo shape de `inventory`).
  * `safeSlotsPurchased` *(number)* — bolsos seguros extras comprados.
  * `slowDurabilityMultiplier` *(number | nil)* — `> 1` = durabilidade decai mais devagar; `nil` = normal.
  * `last_update` *(number)* — `os.time()` da última atualização de durabilidade.

```lua
local inv = exports['snt-inventory-pro']:getCharacterInventory(1)
local qtd = inv.inventory['0'] and inv.inventory['0'].a or 0
```

#### `setCharacterInventory(id, inventory)`

Substitui o inventário inteiro (reconstrói peso e índice). Salva sempre.

* `id` *(number)*.
* `inventory` *(table)* — `{ [slot] = { i, a, d?, dm?, md? } }`.
* **Retorno** *(boolean, string)* — `true, 'INVENTORY_SET'` ou `false, 'INVALID_INVENTORY'`.

```lua
exports['snt-inventory-pro']:setCharacterInventory(1, { ['0'] = { i = 'agua', a = 2 } })
```

#### `getCharacterInventoryMaxWeight(id, ignoreExtras)`

Retorna o peso máximo (em kg) do inventário do personagem.

* `id` *(number)* — characterId.
* `ignoreExtras` *(boolean, opcional)* — quando `true`, retorna **somente** o peso máximo salvo no inventário, ignorando o espaço extra/temporário concedido via API (`API.getInventoryExtraCustomSpace`). Padrão: `false` (inclui o extra).
* **Retorno** *(number)* — peso máximo em kg.

O extra temporário da API nunca é persistido no banco. Use `ignoreExtras = true` quando precisar do valor real salvo — por exemplo, para calcular ajustes de peso sem somar o bônus temporário em cima de si mesmo a cada operação.

```lua
-- Peso máximo efetivo (base salva + extra temporário da API)
local total = exports['snt-inventory-pro']:getCharacterInventoryMaxWeight(1)         --> ex.: 60.0

-- Somente o peso máximo persistido no inventário
local base  = exports['snt-inventory-pro']:getCharacterInventoryMaxWeight(1, true)   --> ex.: 50.0

-- O extra concedido no momento
local extra = total - base                                           --> ex.: 10.0
```

#### `setCharacterInventoryMaxWeight(id, maxWeight)`

* `id` *(number)*.
* `maxWeight` *(number)* — novo peso máximo (deve ser `> 0`).
* **Retorno** *(boolean, string)* — `true, 'MAX_WEIGHT_UPDATED'|'NO_CHANGE'` ou `false, 'INVALID_WEIGHT'`.

```lua
exports['snt-inventory-pro']:setCharacterInventoryMaxWeight(1, 50000)
```

#### `getCharacterInventoryCurrentWeight(id)`

* `id` *(number)*.
* **Retorno** *(number)* — peso ocupado em kg.

```lua
local w = exports['snt-inventory-pro']:getCharacterInventoryCurrentWeight(1)
```

#### `clearCharacterInventory(id, includeSafe)`

Esvazia o inventário; fecha a UI se o jogador estiver online e revalida armas.

* `id` *(number)*.
* `includeSafe` *(boolean, opcional)* — `true` limpa também os bolsos seguros; `false`/omitido preserva itens marcados como `safe`.
* **Retorno** *(boolean)* — `true`.

```lua
exports['snt-inventory-pro']:clearCharacterInventory(1, false)
```

#### `getCharacterInventoryEmptySlots(id)`

* `id` *(number)*.
* **Retorno** *(number)* — quantidade de slots vazios.

```lua
local free = exports['snt-inventory-pro']:getCharacterInventoryEmptySlots(1)
```

#### `getInventoryItemAmount(id, item)`

* `id` *(number)*; `item` *(string)*.
* **Retorno** *(number)* — total do item somando todos os slots.

```lua
local qtd = exports['snt-inventory-pro']:getInventoryItemAmount(1, 'agua')
```

#### `isItemBroken(slotData)`

* `slotData` *(table)* — o shape do slot.
* **Retorno** *(boolean)* — true se o item tem durabilidade e ela chegou a 0.

```lua
local broken = exports['snt-inventory-pro']:isItemBroken(slotData)
```

#### `addInventoryItem(id, item, amount, notify, slot, metadatas)`

Adiciona item(ns) ao inventário do jogador. Respeita peso máximo, limite de item e slots. **Não** ignora peso (para isso só `addChestItem`).

* `id` *(number)*.
* `item` *(string)*.
* `amount` *(number)* — quantidade.
* `notify` *(boolean, opcional)* — envia a notificação de "recebeu item" ao jogador.
* `slot` *(string|number, opcional)* — força um slot específico.
* `metadatas` *(table, opcional)* — metadata do item (item com metadata nunca empilha).
* **Retorno** *(boolean, string, string|table)*:
  * Sucesso: `true, 'DONE', <slot>` (um slot) ou `true, 'DONE', { slot, slot, ... }` (itens não-stackáveis distribuídos).
  * Falha: `false, motivo` — `'INVALID_ITEM'`, `'INVALID_AMOUNT'`, `'ITEM_LIMIT_REACHED'`, `'WEIGHT_NOT_ENOUGH'`, `'ALL_SLOTS_OCCUPIED'`, `'INVALID_SLOT'`, `'SLOT_DIFFERENT_ITEM'`, `'SLOT_HAS_METADATA'`, `'DIFFERENT_DURABILITY'`.

```lua
local ok = exports['snt-inventory-pro']:addInventoryItem(1, 'agua', 2, true)
```

#### `removeInventoryItem(id, item, amount, notify, slot)`

* `id` *(number)*; `item` *(string)*; `amount` *(number)*.
* `notify` *(boolean, opcional)* — notifica o jogador.
* `slot` *(string|number, opcional)* — remove só deste slot; omitido remove globalmente.
* **Retorno** *(boolean, string)* — `true, 'ITEM_REMOVED'` ou `false, motivo` (`'NOT_ENOUGH_ITEMS'`, `'INVALID_ITEM'`, `'INVALID_AMOUNT'`).

```lua
exports['snt-inventory-pro']:removeInventoryItem(1, 'agua', 1, true)
```

#### `clearCharacterMail(id)`

Esvazia o correio do personagem.

* `id` *(number)*.
* **Retorno** *(boolean)* — `true`.

```lua
exports['snt-inventory-pro']:clearCharacterMail(1)
```

#### `addCharacterMail(id, item, amount, doNotify, metadata, sender, customExpirationDays)`

Envia um item ao correio (funciona **offline**; durabilidade não decai enquanto no correio).

* `id` *(number)* — characterId destino.
* `item` *(string)*; `amount` *(number)*.
* `doNotify` *(boolean, opcional)* — notifica se o jogador estiver online (rate-limit de 1/60s).
* `metadata` *(table, opcional)* — metadata do item.
* `sender` *(string, opcional)* — nome exibido como remetente (default `'Sistema'`).
* `customExpirationDays` *(number, opcional)* — sobrepõe o padrão de expiração (mail.json). `0` = nunca expira.
* **Retorno** *(boolean, string)* — `true` em sucesso; `false, motivo` (`'MAIL_DISABLED'`, `'NO_ID'`, `'INVALID_ITEM'`).

```lua
exports['snt-inventory-pro']:addCharacterMail(1, 'diamante', 5, true, nil, 'Loja')
```

#### `getChestInventory(chestId)`

* `chestId` *(string)*.
* **Retorno** *(table)* — inventário do baú (slot -> slot).

```lua
local inv = exports['snt-inventory-pro']:getChestInventory('bau_central')
```

#### `setChestInventory(chestId, inventory)`

* `chestId` *(string)*; `inventory` *(table)*.
* **Retorno** *(boolean, string)* — `true, 'INVENTORY_SET'` ou `false, 'INVALID_INVENTORY'`.

```lua
exports['snt-inventory-pro']:setChestInventory('bau_central', { ['0'] = { i = 'agua', a = 10 } })
```

#### `clearChestInventory(chestId, includeSafe)`

Esvazia o baú; fecha a UI de quem estiver visualizando. Alias idêntico: `clearContainerInventory`.

* `chestId` *(string)*.
* `includeSafe` *(boolean, opcional)* — ver `clearCharacterInventory`.
* **Retorno** *(boolean)* — `true`.

```lua
exports['snt-inventory-pro']:clearChestInventory('bau_central')
```

#### `getChestInventoryCurrentWeight(chestId)`

* `chestId` *(string)*.
* **Retorno** *(number)* — peso ocupado em kg.

```lua
local w = exports['snt-inventory-pro']:getChestInventoryCurrentWeight('bau_central')
```

#### `addChestItem(chestId, item, amount, slot, metadatas, ignoreWeightLimit)`

Adiciona item(ns) a um baú. Único add que aceita bypass de peso.

* `chestId` *(string)*; `item` *(string)*; `amount` *(number)*.
* `slot` *(string|number, opcional)* — força um slot.
* `metadatas` *(table, opcional)* — metadata do item.
* `ignoreWeightLimit` *(boolean, opcional)* — `true` entrega o item mesmo estourando o peso máximo do baú (o limite de **slots** continua valendo).
* **Retorno** — igual a `addInventoryItem`.

```lua
exports['snt-inventory-pro']:addChestItem('bau_central', 'agua', 100, nil, nil, true)
```

#### `removeChestItem(chestId, item, amount, slot)`

* `chestId` *(string)*; `item` *(string)*; `amount` *(number)*.
* `slot` *(string|number, opcional)* — só deste slot.
* **Retorno** — igual a `removeInventoryItem`.

```lua
exports['snt-inventory-pro']:removeChestItem('bau_central', 'agua', 5)
```

#### `canReceiveItems(id, item, amount)`

Checagem "a seco" (não modifica nada) se o **inventário do jogador** comportaria a adição. Apesar do nome, valida sempre contra o inventário de personagem — não de baú.

* `id` *(number)*; `item` *(string)*; `amount` *(number)*.
* **Retorno** *(boolean, string)* — `true` ou `false, motivo` (`'INVENTORY_WEIGHT_NOT_ENOUGH'`, `'ITEM_LIMIT_REACHED'`, `'ALL_INVENTORY_SLOTS_ARE_OCCUPIED'`, `'INVALID_ITEM'`, `'INVALID_AMOUNT'`).

```lua
local ok = exports['snt-inventory-pro']:canReceiveItems(1, 'agua', 5)
```

#### `canReceiveBulkItems(id, bulk)`

Checa vários itens. Atenção: cada item é validado **independentemente** — o peso não é acumulado entre eles (não garante que todos caibam simultaneamente).

* `id` *(number)*.
* `bulk` *(table)* — `{ [item] = amount, ... }`.
* **Retorno** *(boolean, string)* — `true, 'CAN_RECEIVE_ALL_ITEMS'` ou `false, 'item:MOTIVO'` (motivo do primeiro que falhar).

```lua
local ok = exports['snt-inventory-pro']:canReceiveBulkItems(1, { agua = 2, pao = 3 })
```

#### `setItemMetadata(id, slot, key, value)`

Define `md.<key>` de um slot do jogador. Bloqueado se o slot estiver empilhado (`a > 1`).

* `id` *(number)*; `slot` *(string|number)*; `key` *(string)*; `value` *(any)*.
* **Retorno** *(boolean, string)* — `true, 'METADATA_UPDATED'` ou `false, motivo` (`'SLOT_EMPTY'`, `'STACKED_ITEM'`, `'INVALID_SLOT'`, `'INVALID_KEY'`).

```lua
exports['snt-inventory-pro']:setItemMetadata(1, '0', 'cnm', 'Água Especial')
```

#### `setCharacterInventoryItemMetadatas(id, slot, metadatas)`

Substitui toda a `md` de um slot do jogador de uma vez.

* `id` *(number)*; `slot` *(string|number)*; `metadatas` *(table)*.
* **Retorno** *(boolean, string)* — `true, 'METADATAS_UPDATED'` ou `false, motivo`.

```lua
exports['snt-inventory-pro']:setCharacterInventoryItemMetadatas(1, '0', { cnm = 'X', ammo = 30 })
```

#### `setChestInventoryItemMetadata(chestId, slot, key, value)`

Igual a `setItemMetadata`, para um baú.

* `chestId` *(string)*; `slot` *(string|number)*; `key` *(string)*; `value` *(any)*.
* **Retorno** *(boolean, string)*.

```lua
exports['snt-inventory-pro']:setChestInventoryItemMetadata('bau_central', '0', 'cnm', 'X')
```

#### `setChestInventoryItemMetadatas(chestId, slot, metadatas)`

Igual a `setCharacterInventoryItemMetadatas`, para um baú.

* `chestId` *(string)*; `slot` *(string|number)*; `metadatas` *(table)*.
* **Retorno** *(boolean, string)*.

```lua
exports['snt-inventory-pro']:setChestInventoryItemMetadatas('bau_central', '0', { cnm = 'X' })
```

#### `getCharacterItemBySlot(id, slot)`

* `id` *(number)*; `slot` *(string|number)*.
* **Retorno** *(table | nil, string)* — o slot (nil se vazio/inválido) + uma string informativa.

```lua
local slotData = exports['snt-inventory-pro']:getCharacterItemBySlot(1, '0')
```

#### `getChestItemBySlot(chestId, slot)`

Igual ao anterior, para um baú.

* `chestId` *(string)*; `slot` *(string|number)*.
* **Retorno** *(table | nil, string)*.

```lua
local slotData = exports['snt-inventory-pro']:getChestItemBySlot('bau_central', '0')
```

#### `setCharacterInventorySlotData(id, slot, key, value)`

Define uma chave arbitrária no objeto do slot **fora de `md`** (ex.: durabilidade `d`). Uso avançado.

* `id` *(number)*; `slot` *(string|number)*; `key` *(string)*; `value` *(any)*.
* **Retorno** *(boolean, string)* — `true, 'SLOT_DATA_UPDATED'` ou `false, motivo` (`'SLOT_EMPTY'`, `'INVALID_SLOT'`, `'INVALID_DATA_KEY'`).

```lua
exports['snt-inventory-pro']:setCharacterInventorySlotData(1, '0', 'd', 300)
```

#### `setCharacterInventorySlotDatas(id, slot, datas)`

Define várias chaves no objeto do slot.

* `id` *(number)*; `slot` *(string|number)*; `datas` *(table)*.
* **Retorno** *(boolean, string)* — `true, 'SLOT_DATAS_UPDATED'` ou `false, motivo`.

```lua
exports['snt-inventory-pro']:setCharacterInventorySlotDatas(1, '0', { d = 300, dm = 600 })
```

#### `setChestInventorySlotData(chestId, slot, key, value)`

Igual a `setCharacterInventorySlotData`, para um baú.

* `chestId` *(string)*; `slot` *(string|number)*; `key` *(string)*; `value` *(any)*.
* **Retorno** *(boolean, string)*.

```lua
exports['snt-inventory-pro']:setChestInventorySlotData('bau_central', '0', 'd', 300)
```

#### `setChestInventorySlotDatas(chestId, slot, datas)`

Igual a `setCharacterInventorySlotDatas`, para um baú.

* `chestId` *(string)*; `slot` *(string|number)*; `datas` *(table)*.
* **Retorno** *(boolean, string)*.

```lua
exports['snt-inventory-pro']:setChestInventorySlotDatas('bau_central', '0', { d = 300 })
```

#### `tryChest(src, id, weight, slots, items, webhook, save, slowDurMult, upgradeOpts, imageUrl, flags)`

Registra/atualiza um baú dinâmico e **abre a UI** dele para o jogador `src`. É a forma de expor baús ad-hoc de outro resource.

* `src` *(number)* — server id de quem vai abrir.
* `id` *(string)* — id único do baú.
* `weight` *(number)* — peso máximo em kg (obrigatório, `> 0`).
* `slots` *(number | false)* — nº de slots. `false`/`0` mantém o existente (ou usa o default 120).
* `items` *(table | false)* — inventário inicial a aplicar (**substitui** o conteúdo atual). `false`/omitido não mexe no conteúdo já existente.
* `webhook` *(string, opcional)* — URL de webhook para logs deste baú.
* `save` *(reservado)* — sem efeito atualmente.
* `slowDurMult` *(number, opcional)* — multiplicador de **lentidão de durabilidade**. `> 1` faz a durabilidade dos itens dentro do baú decair mais devagar (o tempo decorrido é dividido por esse valor; ex.: `2` = decai na metade da velocidade). Valores `<= 1` são ignorados.
* `upgradeOpts` *(table, opcional)* — upgrades compráveis pelo jogador, no formato:

  ```lua
  {
    slots  = { price = 5000, max = 20, currency = 'secondary' },              -- +slots compráveis
    weight = { price = 5000, amount = 1000, max = 10000, currency = 'secondary' }, -- +peso comprável
  }
  ```

  Cada bloco só é aceito se todos os seus números forem `> 0`. `currency`: `'primary'`/`'secondary'` (default `'secondary'`).
* `imageUrl` *(string, opcional)* — logo/imagem custom do baú.
* `flags` *(table, opcional)* — restrição de acesso (mutuamente exclusivas; se ambas vierem, `storeOnly` vence):
  * `{ storeOnly = true }` — o baú **só aceita guardar** (não deixa retirar).
  * `{ withdrawOnly = true }` — o baú **só deixa retirar** (não aceita guardar).
* **Retorno** — nenhum.

```lua
exports['snt-inventory-pro']:tryChest(
  src, 'bau_faccao', 500, 60, false, nil, false,
  2,                                              -- durabilidade decai 2x mais devagar
  { slots = { price = 5000, max = 20, currency = 'secondary' } },
  nil,
  { storeOnly = true }                            -- só guardar
)
```

#### `validateWeapons(src)`

Revalida se as armas/arremessáveis na mão do jogador ainda existem no inventário; remove da mão se não. Chame após alterar externamente o inventário de quem pode estar com uma arma equipada.

* `src` *(number)*.
* **Retorno** — nenhum.

```lua
exports['snt-inventory-pro']:validateWeapons(src)
```

#### `setUseCooldown(id, time)`

Cooldown **global** de uso de itens (qualquer item) para o personagem. Decai automaticamente (1/s).

* `id` *(number)*; `time` *(number)* — segundos.
* **Retorno** — nenhum.

```lua
exports['snt-inventory-pro']:setUseCooldown(1, 30)
```

#### `isInUseCooldown(id)`

* `id` *(number)*.
* **Retorno** *(boolean)*.

```lua
local blocked = exports['snt-inventory-pro']:isInUseCooldown(1)
```

#### `setItemCooldown(id, item, time)`

Cooldown **específico** de um item (independente do global). Decai automaticamente (1/s).

* `id` *(number)*; `item` *(string)*; `time` *(number)* — segundos.
* **Retorno** — nenhum.

```lua
exports['snt-inventory-pro']:setItemCooldown(1, 'medkit', 300)
```

#### `getSpecificItemUseCooldown(id, item)`

* `id` *(number)*; `item` *(string)*.
* **Retorno** *(number)* — segundos restantes (0 se nenhum).

```lua
local left = exports['snt-inventory-pro']:getSpecificItemUseCooldown(1, 'medkit')
```

#### `consumeItemUse(id, item, charges)`

* `id` *(number)*; `item` *(string)*; `charges` *(number).*&#x20;
* **Retorno** *(boolean)* — se a quantidade de cargas desejada foi consumida do item determinado.

```lua
local consumed = exports['snt-inventory-pro']:consumeItemUse(1, 'repairkit', 1)
```

#### `forceInspect(src, targetId)`

Abre, para o admin `src`, a revista do inventário do personagem `targetId` (funciona **offline**).

* `src` *(number)* — admin; `targetId` *(number)* — characterId do alvo.
* **Retorno** — nenhum.

```lua
exports['snt-inventory-pro']:forceInspect(src, 42)
```

#### `tryTrade(src, targetSrc)`

Envia um convite de negociação de `src` para `targetSrc`.

* `src` *(number)* — quem envia.
* `targetSrc` *(number, opcional)* — alvo; omitido/inválido = jogador mais próximo de `src` (≤ 3m).
* **Retorno** *(boolean)* — `true` se o convite foi enviado (`false` se negado: sistema off, sem alvo, já em negociação, alvo ocupado).

```lua
exports['snt-inventory-pro']:tryTrade(src, targetSrc)
```

#### `tryOpenTrunkChest(src, definedVeh)`

Instrui o cliente de `src` a abrir o porta-malas de um veículo.

* `src` *(number)*; `definedVeh` *(number, opcional)* — network id; omitido = detecta o mais próximo.
* **Retorno** — nenhum.

```lua
exports['snt-inventory-pro']:tryOpenTrunkChest(src)
```

#### `registerItem(item, config, useFunction)`

Registra um item em **runtime** (não é permanente — some no restart; sincroniza com os clientes automaticamente). Falha se o item já existir (inclusive vindo do items.json).

* `item` *(string)* — id único (será convertido para minúsculo).
* `config` *(table)* — mesmos campos do items.json. Principais:
  * `type` *(string)* — `'use'`, `'consumable'`, `'weapon'`, `'ammo'`, `'weapon-attach'`, `'throwable'`, `'none'`.
  * `name` *(string)*, `description` *(string)*.
  * `weight` *(number)* — kg.
  * `durability` *(number)* — em **segundos** quando registrado via API (diferente do items.json, que é em minutos).
  * `limit` *(number)* — limite de posse (0 = sem limite).
  * `droppable`/`sendable`/`storable`/`stolenable`/`safestorable`/`marketplace` *(boolean)* — default `true`.
  * `safe` *(boolean)* — default `false`.
  * `weapon` *(string)*, `ammo` *(string)*, `maxAmmo` *(number)* — para armas.
  * `consumable` *(table)* — `{ timer, requiredItem?, consumeRequired?, anim? }` (ver doc de consumíveis).
* `useFunction` *(function)* — **obrigatória** se `type` for `'use'` ou `'consumable'`. Assinatura: `function(src, id, itemName, amount, slotId, slotData, coords)`. É onde você aplica o efeito (e remove o item).
* **Retorno** *(boolean, string)* — `true, true` em sucesso; `false, motivo` em falha (`'ITEM_ALREADY_REGISTERED'`, `'INVALID_TYPE'`, `'INVALID_USE_FUNCTION'`, `'INVALID_WEAPON_ID'`, `'INVALID_CONSUMABLE_TIMER'`, ...).

```lua
exports['snt-inventory-pro']:registerItem('agua', {
  type = 'use', name = 'Água', weight = 0.5,
}, function(src, id, item, amount, slot)
  if exports['snt-inventory-pro']:removeInventoryItem(id, item, 1, true, slot) then
    -- aplicar efeito (ex.: matar a sede)
  end
end)
```

***

## Exports client

#### `tryOpenInventory()`

Abre o inventário do jogador local (sujeito às checagens de acesso: não morto, sem outra UI, etc.).

* **Retorno** — nenhum.

```lua
exports['snt-inventory-pro']:tryOpenInventory()
```

#### `tryOpenTrunkChest(definedVeh)`

Abre o porta-malas de um veículo.

* `definedVeh` *(entity, opcional)* — handle local; omitido = detecta o mais próximo (distância do vehicles.json).
* **Retorno** — nenhum.

```lua
exports['snt-inventory-pro']:tryOpenTrunkChest()
```

#### `tryOpenGlovesChest()`

Abre o porta-luvas do veículo em que o jogador está sentado (motorista ou carona). Sem efeito fora de um veículo.

* **Retorno** — nenhum.

```lua
exports['snt-inventory-pro']:tryOpenGlovesChest()
```

#### `tryOpenChest(id, skipValidations)`

* `id` *(string)* — id do baú.
* `skipValidations` *(boolean, opcional)* — reseta flags internas de interface/cooldown antes de abrir (uso interno para aberturas forçadas).
* **Retorno** — nenhum.

```lua
exports['snt-inventory-pro']:tryOpenChest('bau_central')
```

#### `tryOpenShop(id, skipValidations)`

* `id` *(string)*; `skipValidations` *(boolean, opcional)*.
* **Retorno** — nenhum.

```lua
exports['snt-inventory-pro']:tryOpenShop('loja_24h')
```

#### `tryOpenRentalMenu(areaId, skipValidations)`

* `areaId` *(string)*; `skipValidations` *(boolean, opcional)*.
* **Retorno** — nenhum.

```lua
exports['snt-inventory-pro']:tryOpenRentalMenu('area_docas')
```

#### `tryOpenAdminContainers(targetId)`

Menu admin de containers alugados de um personagem.

* `targetId` *(number)* — characterId.
* **Retorno** — nenhum.

```lua
exports['snt-inventory-pro']:tryOpenAdminContainers(42)
```

#### `tryOpenCraftMenu(stationId, skipValidations)`

* `stationId` *(string)*; `skipValidations` *(boolean, opcional)*.
* **Retorno** — nenhum.

```lua
exports['snt-inventory-pro']:tryOpenCraftMenu('bancada_1')
```

#### `tryOpenRepairMenu(stationId, skipValidations)`

* `stationId` *(string)*; `skipValidations` *(boolean, opcional)*.
* **Retorno** — nenhum.

```lua
exports['snt-inventory-pro']:tryOpenRepairMenu('reparo_1')
```

#### `tryTrade(targetSrc)`

Inicia uma negociação a partir do jogador local.

* `targetSrc` *(number, opcional)* — server id do alvo; omitido/inválido = mais próximo (≤ 3m).
* **Retorno** *(boolean)*.

```lua
exports['snt-inventory-pro']:tryTrade()
```

#### `tryInspect(definedTarget)`

Revista o jogador mais próximo, ou um alvo específico.

* `definedTarget` *(number, opcional)* — server id; omitido = mais próximo (≤ 2m).
* **Retorno** — nenhum.

```lua
exports['snt-inventory-pro']:tryInspect()
```

#### `getCurrentHotbar()`

* **Retorno** *(table)* — `{ ["0".."4"] = itemId }` (só os slots ocupados da hotbar).

```lua
local hotbar = exports['snt-inventory-pro']:getCurrentHotbar()
```

***

## Funções disponíveis em `config/functions/`

> Diferente dos exports, dentro de `config/functions/server.lua` e `config/functions/client.lua` as funções do sistema são chamadas **diretamente** (como globais), sem `exports['snt-inventory-pro']:`.

***

### Registrando efeitos de itens (server)

O propósito principal de `config/functions/server.lua` é definir o que cada item do tipo `use`/`consumable` faz. Isso é feito por duas tabelas globais:

* **`ItemUseFunctions[itemId]`** *(function)* — o **efeito** do item, executado ao usar (para consumíveis, ao terminar o timer). Você é responsável por remover o item. Assinatura: `function(src, id, itemName, amount, slotId, slotData, coords)`.
* **`ItemCheckUseFunctions[itemId]`** *(function, opcional)* — checagem **antes** de usar. Se retornar `false`, o uso é bloqueado (e a animação nem começa). Mesma assinatura; retorna `boolean`.

```lua
ItemCheckUseFunctions['bandagem'] = function(src, id, item, amount, slot, slotData, coords)
  if Framework.isDead(src) then return false end
  return true
end

ItemUseFunctions['bandagem'] = function(src, id, item, amount, slot, slotData, coords)
  if removeInventoryItem(id, item, 1, true, slot) then
    TriggerClientEvent('snt.inventory@healFunction', src, 25, getItemName(item))
    setItemCooldown(id, item, 60)
  end
end
```

***

### SERVER — `config/functions/server.lua`

#### Estado do jogador

**`closeInventory(src)`** Fecha o inventário/interface aberta do jogador. `src` *(number)*. Retorno: nenhum.

```lua
closeInventory(src)
```

**`isInWater(src)`** → *(boolean)* Se o ped do jogador está dentro d'água.

```lua
if isInWater(src) then end
```

**`isInVehicle(src)`** → *(number | false)* Network id do veículo em que o jogador está, ou `false`.

```lua
local netVeh = isInVehicle(src)
```

**`isVehicleDriver(src)`** → *(number | false)* Network id do veículo se o jogador estiver **dirigindo**, senão `false`.

```lua
local drivingVeh = isVehicleDriver(src)
```

**`getNearestVehicle(src, radius)`** → *(number | nil)* Network id do veículo mais próximo. `radius` *(number, opcional, default 7)* em metros.

```lua
local netVeh = getNearestVehicle(src, 5)
```

**`getNearestPlayer(src, radius)`** → *(number | nil)* Server id do jogador mais próximo. `radius` *(default 2)*.

```lua
local target = getNearestPlayer(src, 3)
```

**`getNearestPlayers(src, radius)`** → *(table)* `{ [serverId] = distância }`

```lua
local nearby = getNearestPlayers(src, 5)
```

**`isNearToModel(src, model, dist)`** → *(boolean)* Se o jogador está perto de um objeto de um modelo. `model` *(string|number)*; `dist` *(default 2)*.

```lua
local near = isNearToModel(src, 'prop_toolchest_01', 2)
```

**`validateWeapons(src)`** Revalida as armas na mão do jogador (remove se saíram do inventário). Chame após remover/alterar armas manualmente.

```lua
validateWeapons(src)
```

**`playerPlaceModel(src, model)`** → *(boolean, table, number)* Abre o modo de posicionar objeto no cliente e **bloqueia** até confirmar/cancelar. Retorna: aplicado, `coords {x,y,z}`, heading.

```lua
local ok, coords, heading = playerPlaceModel(src, 'prop_barrel_01a')
```

#### Cooldowns

**`setUseCooldown(id, time)`** Cooldown **global** de usar itens (qualquer item) para o personagem. `time` em segundos.

```lua
setUseCooldown(id, 30)
```

**`isInUseCooldown(id)`** → *(boolean)*

```lua
if isInUseCooldown(id) then return end
```

**`setItemCooldown(id, item, time)`** Cooldown de um **item específico**. `time` em segundos.

```lua
setItemCooldown(id, 'medkit', 300)
```

**`getSpecificItemUseCooldown(id, item)`** → *(number)* Segundos restantes do cooldown daquele item (0 se nenhum).

```lua
local left = getSpecificItemUseCooldown(id, 'medkit')
```

#### Inventário

**`addInventoryItem(id, item, amount, notify, slot, metadatas)`** → *(boolean, string, ...)* Adiciona item(ns). `notify` *(boolean)* mostra a notificação; `slot`/`metadatas` opcionais.

```lua
addInventoryItem(id, 'agua', 1, true)
```

**`removeInventoryItem(id, item, amount, notify, slot)`** → *(boolean, string)* Remove item(ns). `slot` opcional (só desse slot).

```lua
removeInventoryItem(id, 'agua', 1, true, slot)
```

**`getInventoryItemAmount(id, item)`** → *(number)* Quantidade total do item no inventário do jogador.

```lua
local qtd = getInventoryItemAmount(id, 'agua')
```

**`canReceiveItems(id, item, amount)`** → *(boolean, string)* Checa (sem modificar) se o item cabe no inventário do jogador.

```lua
if canReceiveItems(id, 'agua', 5) then end
```

**`clearCharacterInventory(id, includeSafe)`** Esvazia o inventário. `includeSafe` opcional limpa também os bolsos seguros.

```lua
clearCharacterInventory(id)
```

**`getCharacterInventory(id)`** → *(table)* Objeto do inventário (`.inventory`, `.slots`, `.maxWeight`, `.safeData`, ...). No mesmo ambiente do resource, os métodos funcionam (`:getItemAmount(item)`, `:getEmptySlots()`, etc.).

```lua
local inv = getCharacterInventory(id)
```

**`addChestItem(chestId, item, amount, slot, metadatas, ignoreWeightLimit)`** / **`removeChestItem(chestId, item, amount, slot)`** Manipulam baús. `ignoreWeightLimit` (add) ignora o peso máximo.

```lua
addChestItem('bau_central', 'agua', 10)
```

#### Notificações e logs

**`notify(src, key, extras)`** Envia uma notificação ao jogador. `key` *(string)* é uma chave de idioma (notifyLang); se não existir, o próprio texto é usado. `extras` *(table, opcional)* substitui placeholders `{NOME}` no texto (ex.: `{ ['@item'] = 'Água' }`).

```lua
notify(src, 'ITEM_USED')
notify(src, 'Você não pode usar isso agora.') -- texto literal
```

**`createLog(webhookUrl, title, fields, color)`** Dispara uma log (Discord por padrão). `fields` é uma lista de pares `{ {'label','valor'}, ... }`. `color` *(number, opcional)*.

```lua
createLog(Webhooks['item:used'], 'Item usado', {
  { 'jogador', id },
  { 'item', getItemName(item) },
})
```

#### Framework (server)

**`Framework.getIdentifier(src)`** → *(number | nil)* — characterId a partir do server id. **`Framework.getSource(id)`** → *(number | nil)* — server id a partir do characterId (nil se offline). **`Framework.getIdentity(src)`** → *(table | nil)* — `{ id, name, phone, bank, gems, job, vip, staff, avatar }`. **`Framework.tryPayment(src, amount, currency)`** → *(boolean)* — cobra do jogador; `false` se não tem saldo. `currency`: `'primary'`/`'secondary'`. **`Framework.givePayment(src, amount, currency)`** → *(boolean)* — credita ao jogador online. **`Framework.givePaymentById(id, amount, currency)`** → *(boolean)* — credita pelo characterId (funciona **offline**). **`Framework.getCharFunds(src)`** → *(number, number)* — banco, coins. **`Framework.hasPermission(src, permission)`** → *(boolean)* — `permission` string ou lista (true se tiver qualquer uma). **`Framework.isDead(src)`** → *(boolean)*.

```lua
if not Framework.tryPayment(src, 500, 'secondary') then
  notify(src, 'Sem coins suficientes.')
  return
end
```

***

### CLIENT — `config/functions/client.lua`

> Sem `src` — sempre o jogador local.

#### Proximidade / entidades

**`getNearestPlayer(radius)`** → *(number | nil)* — server id do jogador mais próximo (`radius` default 2). **`getNearestPlayers(radius)`** → *(table)* `{ [serverId] = distância }`. **`getNearestVehicle(radius)`** → *(entity | nil)* — handle **local** do veículo (não é network id). **`getNearestVehicles(radius)`** → *(table)* — lista de handles locais. **`isPedNearToModel(model, dist)`** → *(boolean, entity|nil)* — `model` string/hash ou lista.

```lua
local target = getNearestPlayer(3)
local veh = getNearestVehicle(5)
```

#### Carregamento

**`loadAnimDictionary(dict)`** → *(boolean)* — carrega (bloqueante) um dicionário de animação. **`loadModel(modelName)`** → *(number)* — carrega (bloqueante) um modelo; retorna o hash.

```lua
loadAnimDictionary('mp_player_intdrink')
TaskPlayAnim(PlayerPedId(), 'mp_player_intdrink', 'loop_bottle', 8.0, -8.0, -1, 49, 0, false, false, false)
```

#### Interface

**`canAccessInventories()`** → *(boolean)* Se o jogador pode abrir interfaces agora (não morto, sem UI aberta, sem pause menu, não bloqueado).

```lua
if not canAccessInventories() then return end
```

**`notify(nil, key, extras)`** Notifica o jogador local. 1º argumento ignorado no client (passe `nil`). `key`/`extras` como no server.

```lua
notify(nil, 'ACTION_BLOCKED')
```

#### Framework (client)

**`Framework.isDead()`** → *(boolean)* — jogador local morto. **`Framework.lockActions(bool)`** — `true` bloqueia ações do jogador (andar, inventário, animações); `false` libera. **`Framework.toggleHud(bool)`** — mostra (`true`) / esconde (`false`) a HUD do servidor.

```lua
Framework.lockActions(true)
-- ... fazer algo ...
Framework.lockActions(false)
```

***

### Helpers de item (shared — server e client)

Disponíveis nos dois arquivos:

* **`getItemName(item)`** → *(string)*
* **`getItemConfig(item)`** → *(table | nil)*
* **`getItemType(item)`** → *(string)*
* **`getItemWeight(item)`** → *(number)*
* **`getItemDurability(item)`** → *(number, segundos)*
* **`getItemLimit(item)`** → *(number)*
* **`isRegisteredItem(item)`** → *(boolean)*
* **`isItemFlagAllowed(item, key)`** → *(boolean)* — flags default-true (`droppable`, `sendable`, ...).
* **`isItemPropertyEnabled(item, key)`** → *(boolean)* — propriedade crua (default false).
* **`itemSpoilAction(item)`** → *(string, string|nil)* — ação ao quebrar.
* **`formatCurrency(value, currencyId)`** → *(string)*
* **`formatTime(seconds)`** → *(string)*

```lua
local nome = getItemName(item)   -- funciona no server e no client
```

***

## StateBags (Client)

As seguintes [StateBags](https://docs.fivem.net/docs/scripting-manual/networking/state-bags/) são mantidas no player local (`LocalPlayer.state`) e controlam o comportamento do inventário e das ações relacionadas ao jogador:

**`inventoryDisabled` (true | false)**

Desabilita completamente o inventário.

Quando ativo, bloqueia integralmente o funcionamento do inventário, incluindo seu acesso, uso e demais operações relacionadas.

***

**`inventoryBlocked` (true | false)**

Bloqueia o acesso e o uso do inventário, mas mantém suas threads internas ativas.

Utilizado quando o inventário deve permanecer funcional internamente, porém não pode ser acessado ou utilizado pelo jogador.

> Exemplo: mantém ativas threads responsáveis por funcionalidades como o bloqueio da roda de armas.

***

**`alternatingWeapon` (true | false)**

Indica que o jogador está no processo de alternar ou equipar uma arma.

Permanece `true` durante todo o processo de troca ou equipamento da arma, incluindo o período em que a animação correspondente está sendo executada.

***

**`animBlocked` (true | false)**

Indica que as animações do jogador estão bloqueadas.

Também é utilizada pelo asset `snt-animations` para impedir a execução de animações e, adicionalmente, bloquear o disparo de armas enquanto estiver ativa.

***

`disableInventoryWeaponHud` **(true | false)**

Esconde/mostra a hud de munição de armas (caso esteja habilitada).

***

## Forçar o fechamento

{% hint style="warning" icon="arrow-right-from-bracket" %}
Net event **client** ( `snt/closeAnyInterface` ) que força o fechamento de qualquer interface aberta do inventário — inventário, baú, porta-malas/porta-luvas, negociação, loja, correio, marketplace, revista e painel admin.\
*Também fechará **outras interfaces compatíveis** da **SNT Resources** :)*
{% endhint %}

```lua
-- No CLIENTE (qualquer recurso), fecha as interfaces do jogador local:
TriggerEvent('snt/closeAnyInterface')
```

```lua
-- Do SERVIDOR, fecha as interfaces de um jogador específico:
TriggerClientEvent('snt/closeAnyInterface', source)

-- ...ou de todos os jogadores:
TriggerClientEvent('snt/closeAnyInterface', -1)
```

***

## Notificação de itens

#### `snt.inventory@notifyItem`

Dispara a **notificação flutuante de item** — aquele `+2 Água` / `-1 Faca` no canto da tela. **Não altera o inventário**; é só o aviso visual.&#x20;

{% hint style="danger" %}
Lembre-se os exports **addInventoryItem** e **removeInventoryItem** já possuem o parâmetro "notify" para enviar a notificação. \
*Sendo assim, este evento é útil para OUTRAS integrações e fins.*
{% endhint %}

| Arg      | Tipo     | Descrição                                                                    |
| -------- | -------- | ---------------------------------------------------------------------------- |
| `item`   | `string` | Id do item (ex: `'water'`, `'lockpick'`).                                    |
| `amount` | `number` | Quantidade. **Positivo** = ganhou (verde), **negativo** = perdeu (vermelho). |

{% code title="EXEMPLOS" %}

```lua
-- Item ganho:
TriggerClientEvent('snt.inventory@notifyItem', src, 'water', 2)     -- +2 Água

-- Item perdido:
TriggerClientEvent('snt.inventory@notifyItem', src, 'lockpick', -1) -- -1 Lockpick
```

{% endcode %}

***

## Conversor de itens (painel in-game)

Guia do botão **Converter do arquivo**, na aba **Itens** do painel admin do `snt-inventory-pro`. Explica:

* o que o conversor aceita;
* os campos que cada item pode ter;
* o padrão de cada campo quando ele fica de fora;
* de onde vem o que não é campo do item.

### Resumo rápido

* O conversor copia a tabela Lua **campo por campo** para o `items.json`. Ele não traduz nomes de campo e não preenche padrões. O que você escreve em cada item é o que vai para o catálogo.
* A importação **substitui o catálogo inteiro** no rascunho. Nada é gravado até você clicar em **Salvar tudo**.
* Escreva sempre os quatro bloqueios (`droppable`, `sendable`, `storable`, `stolenable`) como `true` ou `false`. Quando um deles fica de fora, o jogo o trata como **bloqueado**, embora o painel o mostre liberado (veja Bloqueios e flags).

### Passo a passo

1. No painel admin, abra **Itens** e clique em **Converter do arquivo**.
2. Cole o conteúdo Lua e clique em **Analisar**.
3. Confira o resumo: quantos itens serão importados, quantos serão removidos e os avisos (IDs ajustados ou ignorados).
4. Marque a confirmação e clique em **Substituir tudo**.
5. Revise os itens e clique em **Salvar tudo**.
6. Em importações grandes, rode `ensure snt-inventory-pro` no console para otimizar a rede.

### Formato aceito

O conteúdo precisa **começar** pela tabela de itens.

| Entrada                                                                                                           | Funciona?                                                                      |
| ----------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------ |
| `return { ... }`                                                                                                  | Sim                                                                            |
| `{ ... }`                                                                                                         | Sim                                                                            |
| `local list = { ... }` e `return list` no fim                                                                     | **Não.** Apague o `local list =` e o `return list`                             |
| `Items = { ... }`, `Config.Items = { ... }`                                                                       | **Não.** Apague o que vem antes do `{`                                         |
| Chave `['agua'] = { ... }` ou `agua = { ... }`                                                                    | Sim                                                                            |
| Comentários `--` e `--[[ ... ]]`                                                                                  | Sim                                                                            |
| Textos `'...'`, `"..."` e `[[...]]`                                                                               | Sim                                                                            |
| Números, `true`, `false` e `nil`                                                                                  | Sim                                                                            |
| Listas `{ 'a', 'b' }` e tabelas dentro de tabelas                                                                 | Sim                                                                            |
| Contas (`0.1 * 2`), concatenação (`'a' .. 'b'`), chamadas (`vector3(...)`, `GetHashKey(...)`), `function ... end` | **Não.** A importação inteira falha. Troque pelo valor final ou apague o campo |
| `[==[ ... ]==]` (com `=`)                                                                                         | **Não.** Use `[[ ... ]]`                                                       |
| Valor sem aspas (`type = use`)                                                                                    | Vira texto, mas prefira `type = 'use'`                                         |

### IDs dos itens

A chave de cada item vira o ID dele.

* Só são aceitos letras minúsculas, números, `-` e `_`.
* Maiúsculas viram minúsculas. O conversor avisa: *"ID 'X' normalizado para 'x'"*.
* Espaço, acento ou outro caractere faz o item ser **ignorado**.
* Dois IDs que ficam iguais depois de passar para minúsculas (`Agua` e `agua`): o segundo é ignorado.
* Uma entrada que não é tabela (`agua = 'x'`) é ignorada.

Os IDs citados **dentro** dos campos não são ajustados pelo conversor: `ammo`, `spoil.into`, `usesSpoil.into`, `consumable.requiredItem`, `repair.items[].item` e as chaves de `attachs`. Escreva-os em minúsculas, como os IDs. Um `ammo` em maiúsculas nunca combina com o item de munição, e a recarga recusa com "munição inválida".

### Campos do item

As tabelas abaixo dizem o que acontece **em jogo** quando o campo fica de fora.

#### Básico

| Campo         | Valor                                                                     | Se omitir                   | O que faz                                                                                                                                                    |
| ------------- | ------------------------------------------------------------------------- | --------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------ |
| `type`        | `'none'`, `'use'`, `'weapon'`, `'ammo'`, `'weapon-attach'`, `'throwable'` | genérico                    | Comportamento do item (veja Campos por tipo)                                                                                                                 |
| `name`        | texto                                                                     | as notificações mostram `?` | Nome exibido                                                                                                                                                 |
| `description` | texto                                                                     | sem descrição               | Descrição do item                                                                                                                                            |
| `weight`      | número, em kg                                                             | `0`                         | Peso de cada unidade                                                                                                                                         |
| `rarity`      | `'common'`, `'uncommon'`, `'rare'`, `'epic'`, `'lendary'`, `'ultimate'`   | sem cor                     | Cor do slot. As cores ficam em **Interface → Cores de raridade**. Atenção: o valor é **`lendary`**. Com `legendary` (o de outras bases), o slot fica sem cor |
| `tags`        | lista de textos                                                           | sem tags                    | Classificação livre, consultada pelo export `hasItemTag(item, tag)` (não diferencia maiúsculas)                                                              |

#### Limite e durabilidade

| Campo              | Valor                                                         | Se omitir             | O que faz                                                                                                                                                                                                                 |
| ------------------ | ------------------------------------------------------------- | --------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `limit`            | inteiro                                                       | `0` (sem limite)      | Quantidade máxima no inventário do **jogador**. Baús e containers ignoram                                                                                                                                                 |
| `durability`       | inteiro, em **minutos**                                       | `0` (não estraga)     | Tempo de vida do item. 1440 = 1 dia, 10080 = 7 dias, 43200 = 30 dias                                                                                                                                                      |
| `spoil`            | `{ action = 'remove' \| 'keep' \| 'transform', into = 'id' }` | `remove`              | O que acontece quando a durabilidade chega a 0. `keep` mantém o item quebrado no inventário. `transform` troca pelo item `into` no mesmo slot. Se o `into` não existir, o item é removido. Só vale com `durability`       |
| `durabilityPerUse` | `{ enabled = true, shots = 30, percent = 5 }`                 | desligado             | Só armas com `durability`: a cada `shots` tiros, gasta `percent`% da durabilidade                                                                                                                                         |
| `usesSpoil`        | `{ enabled = true, uses = 5, action = ..., into = ... }`      | desligado             | Estraga depois de N usos (`action` e `into` funcionam como no `spoil`). A função de uso precisa retornar `true` quando o uso valeu, senão nada é contado. Com mais de 1 unidade no slot, o uso é recusado até desempilhar |
| `repair`           | `{ enabled = true, items = { { item = 'id', amount = 1 } } }` | não pode ser reparado | Itens gastos para reparar. O item também precisa estar na lista de uma bancada em **Reparação** (`repair.json`), que define o tempo e a cobrança                                                                          |

#### Bloqueios e flags

| Campo          | Se omitir        | Com `false`                                        | Com `true`                                                             |
| -------------- | ---------------- | -------------------------------------------------- | ---------------------------------------------------------------------- |
| `droppable`    | ⚠️ **bloqueado** | não pode ser descartado                            | liberado                                                               |
| `sendable`     | ⚠️ **bloqueado** | não pode ser enviado a outro jogador nem negociado | liberado                                                               |
| `storable`     | ⚠️ **bloqueado** | não pode ir para baú, porta-malas ou porta-luvas   | liberado                                                               |
| `stolenable`   | ⚠️ **bloqueado** | não pode ser roubado na revista                    | liberado                                                               |
| `safestorable` | liberado         | não pode ir para o bolso seguro                    | liberado                                                               |
| `safe`         | `false`          | —                                                  | item permanente: não se perde quando o inventário é limpo (morte etc.) |
| `marketplace`  | liberado         | não pode ser anunciado no marketplace              | liberado                                                               |

> ⚠️ **Escreva sempre os quatro marcados.** O painel mostra `droppable`, `sendable`, `storable` e `stolenable` como liberados quando eles faltam no item, mas o servidor bloqueia. Um item importado sem eles não pode ser descartado, enviado, guardado nem roubado.

Limitar quem pode gerar o item:

| Campo             | Valor                                                    | Se omitir           | O que faz                                                                                                                                     |
| ----------------- | -------------------------------------------------------- | ------------------- | --------------------------------------------------------------------------------------------------------------------------------------------- |
| `spawnPermission` | `{ enabled = true, permissions = { 'admin', 'owner' } }` | qualquer staff gera | Só staff com uma das permissões pode gerar o item. A permissão é checada pela framework (`config/framework.lua`). O console sempre pode gerar |

### Campos por tipo

#### `weapon` (armamento)

| Campo     | Valor                                      | Se omitir          | O que faz                                                                                                 |
| --------- | ------------------------------------------ | ------------------ | --------------------------------------------------------------------------------------------------------- |
| `weapon`  | nome nativo do GTA, ex.: `'WEAPON_PISTOL'` | obrigatório        | A arma entregue ao equipar ([lista de armas](https://docs.fivem.net/docs/game-references/weapon-models/)) |
| `ammo`    | ID do item de munição                      | arma sem munição   | O item que recarrega a arma quando o jogador o arrasta sobre ela                                          |
| `maxAmmo` | 1 a 250                                    | `250` (com `ammo`) | Máximo de balas no pente                                                                                  |

* Um item com `weapon` já funciona como arma em jogo. Mesmo assim, escreva `type = 'weapon'`: o filtro "Armamentos" e os seletores de arma do painel (munição automática, attachs) só mostram itens com esse `type`.
* O item apontado em `ammo` precisa ter `type = 'ammo'`, senão arrastá-lo sobre a arma não recarrega.
* Configurações gerais de armas ficam em **Armas** (`weapons.json`): animação de troca, HUD de munição, munição automática ao equipar e armas ignoradas.

#### `ammo` (munição)

Não tem campos próprios. Recarrega toda arma cujo `ammo` seja o ID deste item.

#### `weapon-attach` (equipamento de arma)

| Campo     | Valor                                          | Se omitir           | O que faz                                                                   |
| --------- | ---------------------------------------------- | ------------------- | --------------------------------------------------------------------------- |
| `attachs` | `{ ['id_do_item_da_arma'] = 'COMPONENT_...' }` | não encaixa em nada | O componente aplicado em cada arma. O jogador arrasta o attach sobre a arma |

* A chave é o **ID do item** da arma (ex.: `pistol`), não o `WEAPON_PISTOL`.
* Arma sem entrada aqui recusa o attach ("attach inválido").
* Também vale o formato antigo: `attachs` em **Armas** (`weapons.json`), organizado por item de attach e pelo nome `WEAPON_...`.

#### `throwable` (arremessável)

| Campo             | Valor                   | Se omitir         | O que faz                                                      |
| ----------------- | ----------------------- | ----------------- | -------------------------------------------------------------- |
| `throwableWeapon` | ex.: `'WEAPON_GRENADE'` | `'weapon_' .. id` | A arma arremessável entregue ao usar, com a quantidade do slot |

#### `use` (usável)

Um item `use` só faz algo se tiver uma **função de uso**, definida de um destes jeitos:

* `ItemUseFunctions['id']` em `config/functions/server.lua`;
* pelo export `registerItem`.

A função é quem aplica o efeito e remove o item. Para bloquear o uso antes de começar, use `ItemCheckUseFunctions['id']` no mesmo arquivo: se retornar `false`, o uso é cancelado.

Sem `consumable`, a função roda na hora. Com `consumable`, o jogador vê uma barra de progresso com animação e a função roda no fim (cancelar ou morrer não gasta o item):

| Campo                                          | Valor                                                      | Se omitir     | O que faz                                                                                                      |
| ---------------------------------------------- | ---------------------------------------------------------- | ------------- | -------------------------------------------------------------------------------------------------------------- |
| `consumable.timer`                             | segundos                                                   | `3`           | Duração da barra, multiplicada pela quantidade usada. A redução por VIP vem de **Benefícios VIP** (`vip.json`) |
| `consumable.requiredItem`                      | ID                                                         | sem exigência | O jogador precisa ter ao menos 1 deste item para usar. `''` = sem exigência                                    |
| `consumable.consumeRequired`                   | `true` / `false`                                           | `false`       | Remove 1 do item exigido ao concluir                                                                           |
| `consumable.anim.dict`, `consumable.anim.anim` | dicionário e animação do GTA                               | sem animação  | A animação durante a barra                                                                                     |
| `consumable.anim.prop`, `consumable.anim.bone` | modelo do prop e índice do osso                            | sem prop      | O prop na mão. Só aparece com os dois preenchidos                                                              |
| `consumable.anim.flag`                         | inteiro                                                    | `0`           | Flag da animação (49 = só tronco, em loop)                                                                     |
| `consumable.anim.placement`                    | `{ posX, posY, posZ, rotX, rotY, rotZ }`                   | tudo `0`      | Posição e rotação do prop no osso                                                                              |
| `consumable.anim.extra_props`                  | `{ { prop = ..., bone = ..., placement = { ... } }, ... }` | nenhum        | Props adicionais                                                                                               |

### O que não é campo do item

Estes itens não vão na tabela Lua. Vêm de outro lugar:

| O quê                                                 | De onde vem                                                                                                                                                               |
| ----------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| Imagem                                                | **Interface → `images.item`**: um endereço com `{ITEM}` no lugar do ID (padrão `https://static.snt.gg/items/{ITEM}.png`). Imagem que não carrega usa `images.missingItem` |
| Função de uso                                         | `config/functions/server.lua` (`ItemUseFunctions`, `ItemCheckUseFunctions`) ou o export `registerItem`                                                                    |
| Bancada, tempo e cobrança do reparo                   | **Reparação** (`repair.json`)                                                                                                                                             |
| Munição automática, HUD de munição, animação de troca | **Armas** (`weapons.json`)                                                                                                                                                |
| Itens que estragam ou se transformam na água          | **Inventário** (`inventory.json → waterSpoil`)                                                                                                                            |
| Preço mínimo e máximo no marketplace                  | **Marketplace** (`marketplace.json`)                                                                                                                                      |
| Redução do tempo de consumíveis                       | **Benefícios VIP** (`vip.json`)                                                                                                                                           |

### Vindo de outra base (Creative, vRP etc.)

O conversor **não traduz** campos de outras bases. Um item no formato Creative (`Index`, `Name`, `Weight`, `Type = 'Consumível'`...) entra com esses nomes, e o inventário não reconhece nenhum deles. Converta para os campos deste guia antes de colar. Um exemplo de catálogo já no formato certo está em `conversions/itemlist.result.lua`.

Campos que o inventário não conhece não dão erro. Ficam gravados no `items.json` e são ignorados.

### Exemplos

```lua
return {
    -- Genérico
    ['documento'] = {
        type = 'none', name = 'Documento', weight = 0.05, rarity = 'common',
        droppable = true, sendable = true, storable = true, stolenable = true,
        safe = true, -- não se perde ao morrer
    },

    -- Usável com barra, animação e prop (precisa de ItemUseFunctions['agua'])
    ['agua'] = {
        type = 'use', name = 'Garrafa de Água', weight = 0.5, rarity = 'common',
        durability = 10080, -- 7 dias
        spoil = { action = 'transform', into = 'garrafa_vazia' },
        tags = { 'bebida' },
        droppable = true, sendable = true, storable = true, stolenable = true,
        consumable = {
            timer = 5,
            anim = {
                dict = 'mp_player_intdrink', anim = 'loop_bottle', flag = 49,
                prop = 'prop_ld_flow_bottle', bone = 28422,
                placement = { 0.0, 0.0, 0.05, 0.0, 0.0, 0.0 },
            },
        },
    },

    -- Usável que estraga após 3 usos (a função de uso precisa retornar true)
    ['lockpick'] = {
        type = 'use', name = 'Lockpick', weight = 0.2, rarity = 'uncommon',
        usesSpoil = { enabled = true, uses = 3, action = 'remove' },
        droppable = true, sendable = true, storable = true, stolenable = true,
    },

    -- Munição
    ['ammo_pistol'] = {
        type = 'ammo', name = 'Munição de Pistola', weight = 0.02, rarity = 'common',
        droppable = true, sendable = true, storable = true, stolenable = true,
    },

    -- Arma com munição, desgaste por tiro, reparo e geração restrita
    ['pistol'] = {
        type = 'weapon', name = 'Pistola', weight = 1.2, rarity = 'rare',
        weapon = 'WEAPON_PISTOL', ammo = 'ammo_pistol', maxAmmo = 12,
        durability = 43200, -- 30 dias
        durabilityPerUse = { enabled = true, shots = 30, percent = 5 },
        repair = { enabled = true, items = { { item = 'kit_reparo', amount = 1 } } },
        spawnPermission = { enabled = true, permissions = { 'admin', 'owner' } },
        droppable = true, sendable = true, storable = true, stolenable = false,
        marketplace = false,
    },

    -- Attach (a chave é o ID do item da arma)
    ['lanterna_pistola'] = {
        type = 'weapon-attach', name = 'Lanterna de Pistola', weight = 0.1, rarity = 'uncommon',
        attachs = { ['pistol'] = 'COMPONENT_AT_PI_FLSH' },
        droppable = true, sendable = true, storable = true, stolenable = true,
    },

    -- Arremessável
    ['granada'] = {
        type = 'throwable', name = 'Granada', weight = 0.4, rarity = 'epic',
        throwableWeapon = 'WEAPON_GRENADE',
        droppable = true, sendable = false, storable = true, stolenable = false,
        safestorable = false,
    },
}
```

> Os IDs de `spoil.into` (`garrafa_vazia`) e `repair.items` (`kit_reparo`) precisam existir no catálogo. Um `into` que não existe faz o item ser removido em vez de transformado.

### Mensagens do conversor

**Avisos.** O item afetado é ignorado ou ajustado, e o resto é importado normalmente:

| Mensagem                                              | O que fazer                                                                |
| ----------------------------------------------------- | -------------------------------------------------------------------------- |
| `ID 'X' normalizado para 'x'.`                        | Nada. Só confira se os campos que citam esse ID também estão em minúsculas |
| `ID 'X' é inválido — ... Ignorado.`                   | Renomeie: só minúsculas, números, `-` e `_`                                |
| `ID 'X' colide com 'x' após normalização — ignorado.` | Dois IDs iguais. Renomeie um deles                                         |
| `Entrada 'X' não é uma tabela — será ignorada.`       | O valor do item precisa ser `{ ... }`                                      |

**Erros.** Nada é importado:

| Mensagem                                         | Causa comum                                                                                        |
| ------------------------------------------------ | -------------------------------------------------------------------------------------------------- |
| `A configuração deve ser uma tabela de itens...` | Há algo antes do `{` (`local list =`, `Items =`)                                                   |
| `Caractere inesperado em '...'`                  | Conta, concatenação, chamada de função ou `function` em algum campo. O trecho mostrado aponta onde |
| `Esperado '...', recebido '...'`                 | Vírgula, chave ou colchete faltando perto do trecho                                                |
| `String longa não fechada ([[ ... ]])`           | Um `[[` sem o `]]`                                                                                 |
| `Conteúdo vazio.`                                | Nada foi colado                                                                                    |
