# Item, Inventory & Container Lua API

This document describes the Lua APIs for managing item definitions, inventories,
and persistent container state in the editScene editor.

---

## Overview

The item system is split into three namespaces:

| Namespace | Purpose |
|-----------|---------|
| `ecs.items` | Register and query item **definitions** (global registry) |
| `ecs.inventory` | Add, remove, and query items in an entity's **inventory** |
| `ecs.container` | Save/load persistent **container state** by `containerId` |

Item data lives in a single authoritative registry (`ItemRegistry`). Entities
only store `itemId` + `stackSize`, so changing a definition (name, weight, etc.)
propagates automatically to all instances.

---

## `ecs.items` — Item Definition Registry

### `ecs.items.register(itemId, definition)`

Register a new item type or overwrite an existing one.

**Parameters:**
- `itemId` *(string)* — Unique identifier, e.g. `"potion_health"`
- `definition` *(table)* — Item properties

**Definition fields:**

| Field | Type | Default | Description |
|-------|------|---------|-------------|
| `itemName` | string | `""` | Human-readable name |
| `itemType` | string | `"misc"` | Category: `consumable`, `weapon`, `armor`, `misc`, … |
| `maxStackSize` | int | `99` | How many fit in one inventory slot |
| `weight` | float | `0.1` | Weight per unit (for encumbrance) |
| `value` | int | `1` | Base trade value |
| `useActionName` | string | `""` | Action triggered on "use" |
| `unique` | bool | `false` | If `true`, only one may exist in the world |

**Example:**
```lua
ecs.items.register('potion_health', {
    itemName = 'Health Potion',
    itemType = 'consumable',
    maxStackSize = 10,
    weight = 0.5,
    value = 25,
    useActionName = 'drink_potion',
    unique = false
})
```

---

### `ecs.items.find(itemId)` → table | nil

Look up a registered item definition.

**Returns:**
- Table with all definition fields (see above), or `nil` if not found.

**Example:**
```lua
local def = ecs.items.find('potion_health')
if def then
    print(def.itemName, 'weight:', def.weight)
end
```

---

### `ecs.items.list()` → array of strings

Get a list of all registered `itemId`s.

**Example:**
```lua
local allItems = ecs.items.list()
for _, id in ipairs(allItems) do
    print(id)
end
```

---

### `ecs.items.is_unique(itemId)` → bool

Check whether an item is marked as unique.

**Example:**
```lua
if ecs.items.is_unique('amulet_legendary') then
    print('There can be only one!')
end
```

---

## `ecs.inventory` — Entity Inventory Operations

All functions operate on a specific entity that has an `InventoryComponent`.
The entity is referenced by its numeric ECS id (the same id used with
`ecs.create_entity()`).

### `ecs.inventory.add(entityId, itemId, count)` → bool

Add `count` copies of an item to the entity's inventory.

**Parameters:**
- `entityId` *(number)* — ECS entity id
- `itemId` *(string)* — Registered item id
- `count` *(number)* — Quantity to add (default 1 if omitted in C++, but Lua
  wrapper requires all 3 arguments)

**Returns:** `true` if the operation succeeded, `false` if the inventory is
full, over weight limit, or the item is unique and already exists elsewhere.

**Example:**
```lua
local player = ecs.get_player_entity()  -- or any entity id
ecs.inventory.add(player, 'potion_health', 5)
```

---

### `ecs.inventory.remove(entityId, itemId, count)` → int

Remove up to `count` copies of an item.

**Returns:** The number of items actually removed.

**Example:**
```lua
local removed = ecs.inventory.remove(player, 'potion_health', 2)
print('Removed', removed, 'potions')
```

---

### `ecs.inventory.has(entityId, itemId)` → bool

Check if the inventory contains at least one of the given item.

**Example:**
```lua
if ecs.inventory.has(player, 'key_temple') then
    ecs.event('unlock_temple_door')
end
```

---

### `ecs.inventory.count(entityId, itemId)` → int

Get the total stack size of an item across all slots.

**Example:**
```lua
local coins = ecs.inventory.count(player, 'gold_coin')
print('You have', coins, 'gold coins')
```

---

### `ecs.inventory.get_slots(entityId)` → array of slots

Get a snapshot of the inventory's non-empty slots.

**Returns:** Array of tables, each with:
- `itemId` *(string)*
- `stackSize` *(number)*

**Example:**
```lua
local slots = ecs.inventory.get_slots(player)
for _, slot in ipairs(slots) do
    print(slot.itemId, 'x' .. slot.stackSize)
end
```

---

### `ecs.inventory.set_slots(entityId, slots)`

Overwrite the entire inventory with a new array of slots.

**Parameters:**
- `slots` *(array)* — Each element is `{ itemId = "...", stackSize = N }`

**Example:**
```lua
ecs.inventory.set_slots(chestEntity, {
    { itemId = 'gold_coin', stackSize = 50 },
    { itemId = 'iron_dagger', stackSize = 1 }
})
```

---

## `ecs.container` — Persistent Container State

Containers with a `containerId` in their `InventoryComponent` automatically
sync to the global `ContainerStateRegistry`. This lets chests, shops, and
loot crates retain their contents across scene reloads.

The `ecs.container` API exposes the same persistence layer directly so Lua
scripts can read or override container state.

### `ecs.container.get_state(containerId)` → array of slots

Load the persisted contents of a container.

**Returns:** Array of `{ itemId, stackSize }` tables. Empty array if no state
has been saved.

**Example:**
```lua
local loot = ecs.container.get_state('chest_village')
for _, slot in ipairs(loot) do
    print('Chest contains', slot.itemId, 'x' .. slot.stackSize)
end
```

---

### `ecs.container.set_state(containerId, slots)`

Overwrite the persisted state of a container.

**Parameters:**
- `slots` *(array)* — `{ itemId = "...", stackSize = N }`

**Example:**
```lua
ecs.container.set_state('chest_village', {
    { itemId = 'healing_herb', stackSize = 3 },
    { itemId = 'rusty_key',    stackSize = 1 }
})
```

---

### `ecs.container.clear_state(containerId)`

Delete the persisted state for a container, so it will revert to its scene
 defaults on next load.

**Example:**
```lua
ecs.container.clear_state('chest_village')
```

---

## Persistence

| File | Content | Auto-save? |
|------|---------|------------|
| `items.json` | All item definitions | Yes, on every mutation |
| `container_state.json` | Container slot overrides | Yes, on every mutation |

Both files live in the working directory of the editor executable and are
loaded automatically on startup.

---

## Unique Items

When `unique = true` is set on an item definition, the engine rejects any
attempt to create a duplicate:

- `ecs.inventory.add` returns `false` if the item already exists in any
  inventory or as a world entity.
- Scene deserialization skips unique items that are already present.

This is useful for quest keys, legendary artifacts, and one-off rewards.
