> For the complete documentation index, see [llms.txt](https://atiysus-organization.gitbook.io/aty-scripts/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://atiysus-organization.gitbook.io/aty-scripts/inventory/developers/adding-items-and-recipes.md).

# Adding Items & Recipes

## Adding Items & Recipes

#### An item

`data/items.lua`:

```lua
lockpick = {
    label       = 'Lockpick',
    weight      = 180,
    stack       = 5,
    category    = 'tool',
    rarity      = 'uncommon',
    description = 'Opens what was not meant to be opened.',
    usable      = true,
},
```

Then drop `ui/images/lockpick.png` in. Restart the resource. The admin panel's **Definitions** tab changes an existing item live, with no restart, but a new item starts in this file.

#### Making it do something

Built-in effects cover food, drink and medical:

```lua
burger = {
    useTime = 2500,
    effect  = { hunger = 35, anim = 'eat' },
}
```

One item is one use. `portions = 4` makes it four, but only with `Config.Portions.enabled = true`; it is off by default, as in ox\_inventory.

Anything else gets a handler:

```lua
exports.aty_inventory:RegisterUsable('lockpick', function(src, info)
    TriggerClientEvent('my_lockpicking:start', src, info.slot)
end)
```

A usable item is spent when it is used unless its definition says `consume = false` — a lockpick that should survive the attempt needs it.

`examples/usable_handler.lua` is a complete worked example, including how to answer cancellation properly.

#### A recipe

`data/recipes.lua`:

```lua
{
    id          = 'lockpick',
    ingredients = {
        { item = 'scrap',   count = 2 },
        { item = 'plastic', count = 1 },
    },
    results = { { item = 'lockpick', count = 1 } },
    time    = 2500,
},
```

A recipe lists at least two ingredients; dropping any one of them onto any other starts it. Mark an ingredient `consume = false` to make it a tool — required but not spent. `time` is how long the hands are busy: a recipe that names none takes 3000 ms, and `0` is instant.

{% hint style="warning" %}
A pair of items belongs to one recipe. The admin panel refuses a second recipe for a pair it already knows and names the one that owns it. The file is not checked that way — two recipes in `data/recipes.lua` sharing a pair means only one of them answers the drag. If your new recipe does not appear, `invrecipes` prints the book as the engine holds it, with where each recipe came from.
{% endhint %}

#### Importing framework items

Items defined in QBCore or ESX already work — they are read through the bridge. To make this resource own them instead:

```
invmigrate items          dry run — shows what would be written
invmigrate items write    writes them into data/items.generated.lua
```

Add `data/items.generated.lua` to `shared_scripts` in `fxmanifest.lua`, after `data/items.lua`, then `refresh` and restart; an item defined in `data/items.lua` wins over a generated one. After that the catalogue no longer depends on the framework being up.

#### Checking your work

```
invdoctor
```

reports items with no image, items whose labels are confusable with each other, and shops or loot tables naming items that do not exist. A recipe naming an unknown item is skipped at start, and the console says which one and why.

{% hint style="info" %}
The confusable-label check is worth taking seriously. `metalscrap` labelled "Metal Scrap" beside `scrap` labelled "Scrap Metal" produces bug reports that read like "crafting is broken" and are actually "the player picked the wrong item".
{% endhint %}
