# Special Slots

## Special Slots Events API

The Special Slots API allows developers to register custom events for special inventory slots (tool, armour, drug, radio, backpack, identification, phone, tablet, key, wallet).

### Available Slots

Available slots are configured via the `inventory:specialslots` convar in your `server.cfg`. By default, they include:

| Slot             | Description              |
| ---------------- | ------------------------ |
| `tool`           | Tools                    |
| `armour`         | Protective vests         |
| `drug`           | Substances / medications |
| `radio`          | Communication radios     |
| `backpack`       | Backpacks                |
| `identification` | Identity documents       |
| `phone`          | Mobile phones            |
| `tablet`         | Electronic tablets       |
| `key`            | Keys                     |
| `wallet`         | Wallets                  |

***

### Registering Events

Use the `RegisterSpecialSlotEvent` export to register a slot with its events:

```lua
exports.lvs_inventory:RegisterSpecialSlotEvent('tool', {
    onEquip = function(slotData)
        print('Tool equipped')
    end,

    onUnequip = function(slotData)
        print('Tool unequipped')
    end,

    onTick = function(slotData)
        -- Logic that runs while the item is equipped
    end,

    tickRate = 1000 -- (optional) Interval in ms. Default: 100
})
```

***

### Available Events

#### onEquip

Triggered when an item is placed in the special slot.

**Parameters:**

| Parameter  | Type  | Description                                             |
| ---------- | ----- | ------------------------------------------------------- |
| `slotData` | table | Data of the equipped item (name, count, metadata, etc.) |

**Example:**

```lua
onEquip = function(slotData)
    print('Item equipped:', slotData.name)
    print('Count:', slotData.count)
    print('Metadata:', json.encode(slotData.metadata))
end
```

#### onUnequip

Triggered when an item is removed from the special slot.

**Parameters:**

| Parameter  | Type  | Description                          |
| ---------- | ----- | ------------------------------------ |
| `slotData` | table | Data of the item that was unequipped |

**Example:**

```lua
onUnequip = function(slotData)
    if slotData then
        print('Item unequipped:', slotData.name)
    else
        print('Slot cleared without previous data')
    end
end
```

#### onTick

Executed periodically while the item remains in the special slot.

**Parameters:**

| Parameter  | Type  | Description                       |
| ---------- | ----- | --------------------------------- |
| `slotData` | table | Updated data of the equipped item |

**Example:**

```lua
onTick = function(slotData)
    -- Check if a tool has durability
    if slotData.metadata.durability then
        if slotData.metadata.durability <= 0 then
            -- Notify the player
            exports['ox_lib']:notify({
                title = 'Broken tool',
                description = 'Your tool has worn out completely',
                type = 'warning'
            })
        end
    end
end
```

### Tick Rate Configuration

You can configure the frequency of `onTick` execution using the `tickRate` property in milliseconds:

```lua
exports.lvs_inventory:RegisterSpecialSlotEvent('phone', {
    onTick = function(slotData)
        -- Runs every 5 seconds
        checkPhoneSignal(slotData.metadata.number)
    end,
    
    tickRate = 5000 -- 5 seconds
})
```

If `tickRate` is not specified, the default value is **100ms**.

> **Performance Note:** Very low values (such as 1ms) can impact server performance. Use the highest value that is functional for your use case.

***

### Complete Examples

#### Tool with Durability

```lua
exports.lvs_inventory:RegisterSpecialSlotEvent('tool', {
    onEquip = function(slotData)
        exports['ox_lib']:notify({
            title = 'Tool equipped',
            description = string.format('%s ready to use', slotData.label),
            type = 'success'
        })
    end,

    onUnequip = function(slotData)
        exports['ox_lib']:notify({
            title = 'Tool stored',
            description = string.format('%s stored away', slotData.label),
            type = 'info'
        })
    end,

    onTick = function(slotData)
        -- Reduce durability over time
        if slotData.metadata.durability and slotData.metadata.durability > 0 then
            -- Wear logic here...
        end
    end,

    tickRate = 1000 -- Every second
})
```

#### Radio with Channel Verification

```lua
exports.lvs_inventory:RegisterSpecialSlotEvent('radio', {
    onEquip = function(slotData)
        local channel = slotData.metadata.channel or 1
        SetRadioChannel(channel)
        exports['ox_lib']:notify({
            title = 'Radio turned on',
            description = string.format('Channel: %d', channel),
            type = 'success'
        })
    end,

    onUnequip = function(slotData)
        SetRadioChannel(0) -- Turn off radio
        exports['ox_lib']:notify({
            title = 'Radio turned off',
            type = 'info'
        })
    end,

    onTick = function(slotData)
        -- Check if there is signal on the current channel
        local channel = slotData.metadata.channel or 1
        if not HasRadioSignal(channel) then
            -- No signal...
        end
    end,

    tickRate = 2000 -- Every 2 seconds
})
```

#### Phone with State Updates

```lua
local phoneActive = false

exports.lvs_inventory:RegisterSpecialSlotEvent('phone', {
    onEquip = function(slotData)
        phoneActive = true
        local number = slotData.metadata.number or 'Unknown'
        exports['ox_lib']:notify({
            title = 'Phone started',
            description = string.format('Number: %s', number),
            type = 'success'
        })
        OpenPhoneUI()
    end,

    onUnequip = function(slotData)
        phoneActive = false
        ClosePhoneUI()
        exports['ox_lib']:notify({
            title = 'Phone turned off',
            type = 'info'
        })
    end,

    onTick = function(slotData)
        if phoneActive then
            -- Check for pending notifications
            CheckPendingNotifications()
        end
    end,

    tickRate = 3000 -- Every 3 seconds
})
```

### Manual Event Triggering

You can manually trigger events using the `TriggerSpecialSlotEvent` export:

```lua
local success, result = exports.lvs_inventory:TriggerSpecialSlotEvent('tool', 'onEquip', mySlotData)

if not success then
    print('Error executing event:', result)
end
```

**Parameters:**

| Parameter   | Type   | Description                             |
| ----------- | ------ | --------------------------------------- |
| `slotName`  | string | Name of the slot (tool, radio, etc.)    |
| `eventType` | string | Event type (onEquip, onUnequip, onTick) |
| `...`       | any    | Additional arguments for the callback   |

**Returns:**

| Value          | Type    | Description                                  |
| -------------- | ------- | -------------------------------------------- |
| `success`      | boolean | Whether the callback executed without errors |
| `result/error` | any     | Callback result or error message             |

### Important Notes

#### Slot Data (slotData)

The `slotData` parameter contains the equipped item's information and is automatically updated. Its general structure includes:

```lua
{
    name = "lvs_wrench",         -- Item name
    label = "Wrench",            -- Display label
    count = 1,                   -- Quantity
    weight = 500,                -- Weight in grams
    slot = 16,                   -- Slot number
    metadata = {                 -- Custom metadata
        durability = 85,
        description = "A robust tool"
        -- ...your own metadata
    }
}
```

#### Avoid Heavy Operations in onTick

If you need to perform expensive operations inside `onTick`, consider using `Citizen.CreateThread` to avoid blocking the cycle:

```lua
onTick = function(slotData)
    if not processing then
        processing = true
        Citizen.CreateThread(function()
            -- Heavy operation here
            processData(slotData)
            processing = false
        end)
    end
end
```


---

# Agent Instructions: Querying This Documentation

If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter:

```
GET https://fivem.lvsoft.com.ar/qb-esx/lvs-inventory/special-slots.md?ask=<question>
```

The question should be specific, self-contained, and written in natural language.
The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
