# Containers and Rules

> An inventory config gives a character its containers, such as a backpack of slots, a grid case or a bank, and limits on what it carries, such as a weight limit that tags the character Overburdened.

Markdown version of https://rigbak.com/docs/universal-player-combat/inventory-containers, a page of the Universal Player Combat documentation. Link that page when citing it.

## Set it up (5 minutes)

1. **Give the potion a weight**

   Follow the [Inventory](https://rigbak.com/docs/universal-player-combat/inventory) quick start first (three `Item_MyPotion` at start), then add a **Weight** fragment with **Weight** 25 to `Item_MyPotion`.
2. **Give the character a config that weighs it**

   On `BP_UPC_Character`'s **InventoryComponent**, set **Config** to `Demo/Items/Inventory/InventoryConfig_UPC_OpenWorldList`. Its first carry rule, a **Weight Limit** of 60 with **Refuse Over Limit** off, lets everything in and puts `UPC.State.Overburdened` on the character once the load reaches 60. [Open World List](https://rigbak.com/docs/universal-player-combat/inventory-open-world-list) shows its other settings.

   In **BP_UPC_Character**, under UPC > Inventory, set:

   | Property | Value |
   | --- | --- |
   | Config | InventoryConfig_UPC_OpenWorldList (replaces InventoryConfig_UPC_Simple) |
3. **Press Play, then drink**

   Three potions weigh 75, so the character cannot move: its **UPC Speed Modifier** scales walking to 0 under Overburdened and UPC Sprint blocks on the tag. With no belt on the open world list, drink from the inventory screen: press **I**, pick the potion, press **E** (**Consume**). The load drops to 50, the tag comes off, and closing the screen with **I** lets the character walk.

---

## Make a config

1. Right-click in the Content Browser, **UPC**, **Items**, **Inventory Config**.
2. Add a **Containers** row per container: a gameplay tag naming it and a **Container Definition** (**UPC**, **Items**) laying it out.
3. Set the config on the character's **InventoryComponent**. A config the screens component does not list opens the fallback screen ([Inventory Screens](https://rigbak.com/docs/universal-player-combat/inventory-screens)).

Adds and pickups try the containers in this order; what fits nowhere stays out. The survival grid lists the case first and filters keys and pouches out of it, so they go on to the key items list.

**Details panel: Container_UPC_Case** (data asset, in Content Browser)

**Category: Display**

| Property | Value |
| --- | --- |
| Display Name | Case |
| Icon | None |

**Category: Layout**

| Property | Value |
| --- | --- |
| Layout | Grid |
| Grid Size | (6, 4) |
| Allow Rotation | true |
| Capacity Tag | UPC.Inventory.Capacity.CaseRows |

**Category: Rules**

| Property | Value |
| --- | --- |
| Rules | 1 Array element |
| Rules > Index [0] | Item Filter |
| Rules > Index [0] > Allowed Tags | no tags |
| Rules > Index [0] > Blocked Tags | UPC.Slot.KeyItem, UPC.Slot.Upgrade |

**Category: Access**

| Property | Value |
| --- | --- |
| Carried | true |
| Takes New Items | true |
| Access Tag | None |

**Category: Bags**

| Property | Value |
| --- | --- |
| Opens Bags | false |

*Six columns by four rows, where an item may lie turned. Keys and pouches stay out through its filter. Each point of UPC.Inventory.Capacity.CaseRows the character owns adds a row.*

| Setting | Does |
| --- | --- |
| **Display Name**, **Icon** | Shown by a screen. |
| **Layout** | **List**: no size, arrival order. **Slots**: **Slot Count** slots, one stack each. **Grid**: **Grid Size** columns by rows; an item covers its **Grid Footprint** **Size** (width by height, 3 by 1 for a three-cell sword), one cell without one. |
| **Allow Rotation** | Grid only. Items may lie turned a quarter; adds try upright first. |
| **Capacity Tag** | Slots and Grid only. Each Capacity Bonus point owned adds a slot or grid row; empty keeps the size fixed ([Capacity from items](https://rigbak.com/docs/universal-player-combat/inventory-containers#capacity-from-items)). |
| **Rules** | Limits judged over this container alone, such as a quiver filter ([Rules](https://rigbak.com/docs/universal-player-combat/inventory-containers#rules)). |
| **Carried** | Off for storage off the character (bank, stash): the belt, starting draw, a rack's Put Back, Consume Item, Get Item Count and Carry Rules ignore its items. |
| **Takes New Items** | Whether adds and pickups land here; off for a container players fill only by moving items in. |
| **Access Tag** | Tag the character must hold to move, use, drop, draw or consume the container's items (such as one a stash box grants). Empty is always in reach. |
| **Opens Bags** | A bag placed here opens its own container ([Bags and Banks](https://rigbak.com/docs/universal-player-combat/inventory-bags)). |

The config's **Sort Order** lists item kinds as Slot Tags, the order **Request Sort** lays a container out in.

---

## Rules

A rule limits what goes in. Put it on a container's **Rules** to limit that container, or on the config's **Carry Rules** to limit everything carried. An item goes in only as far as every rule accepts: 15 arrows under a cap with room for 5 take 5.

| Rule | Settings | Does |
| --- | --- | --- |
| **Weight Limit** | **Limit**, **Capacity Tag**, **Refuse Over Limit**, **Thresholds** | Caps the load (each Weight fragment times its count), refusing the rest with `TooHeavy`. Refuse Over Limit off lets everything in; each threshold puts its **Tag** on the character at its **Fraction** of the limit. |
| **Category Limit** | **Limits**: **Category**, **Max Units**, **Capacity Tag** | Caps units per category, matched against Slot Tags with children. An item in no row passes; in several, the tightest applies. |
| **Item Filter** | **Allowed Tags**, **Blocked Tags** | Takes only items matching an Allowed Tag (empty takes any) and no Blocked Tag. |
| **Belt Only** | None | Takes an item only while a belt slot takes it, and more units only into the stacks on the belt, for a style with no inventory; pair it with the belt's **Auto Populate from Inventory**. On a container it limits that container alone, as on Simple's Belt list beside its Worn slots. Refuses with `Full` when the slots for it are held, `CategoryFull` at its copy limit, `NotAdmitted` when no slot takes it, and takes nothing new while the belt is switched off. A character with no player's belt, such as an AI, takes what the other rules allow. |

**Get Units That Fit**, on the inventory and on a world item for its prompt, answers how many units an add would take and why it leaves the rest: `Full`, `TooHeavy`, `CategoryFull`, `NotAdmitted`, or `NoAccess` when only reach stopped it ([every reason](https://rigbak.com/docs/universal-player-combat/inventory-screens#why-a-move-is-refused)).

### Status tags

A rule can put tags on the character while the contents earn them, as the Weight Limit's thresholds do in the [Open World List](https://rigbak.com/docs/universal-player-combat/inventory-open-world-list) and [Party RPG](https://rigbak.com/docs/universal-player-combat/inventory-party-rpg) configs. Give each tag an effect: a **UPC Speed Modifier** scale, or a sprint's or transition's **Blocked Tags** ([Sprint and Speed](https://rigbak.com/docs/universal-player-combat/sprint-and-speed)).

### A rule of your own

[Inventory Rules and Combines in Blueprint](https://rigbak.com/docs/universal-player-combat/inventory-blueprint) builds a rule from a Blueprint class whose parent is `UPCInventoryRule`.

---

## Capacity from items

An item with a **Capacity Bonus** fragment raises a capacity while owned (a quiver adds arrow space, a case upgrade a row). Each row names a **Capacity Tag** and an **Amount** per unit owned.

**Details panel: Capacity Bonus** (instanced object, in Item_MyCaseUpgrade)

**Category: Capacity Bonus**

| Property | Value |
| --- | --- |
| Bonuses | 1 Array element |
| Bonuses > Index [0] > Capacity Tag | UPC.Inventory.Capacity.CaseRows |
| Bonuses > Index [0] > Amount | 1 |

*A case upgrade of your own. Owning it raises every capacity that reads UPC.Inventory.Capacity.CaseRows by 1, so the survival grid's case gets one more row. No demo item carries one.*

A setting naming the tag reads the bonus in its own unit. With a bonus of 2 for `MyGame.Capacity.Pack`, a Grid container whose **Capacity Tag** is that tag gets 2 more rows, a Weight Limit naming it carries 2 more weight, and a Category Limit row naming it takes 2 more units. **Get Capacity Bonus** answers the total for a tag. The bonus counts in any container, the stash included. An upgrade inside the rows it enlarges cannot leave while they hold items, so keep it in the stash or in a container whose filter keeps it apart.

For example, a case upgrade kept in the stash adds one row to the case, and a herb sits in that row. Dropping the upgrade, storing it in a chest or putting it back on a rack is refused while the herb stays: **Can Item Leave** answers false with `UPC.Inventory.Refused.CapacityInUse` (the demo screens say Empty the extra slots first). Move the herb into the case's other rows and the upgrade can go. Game code that removes the upgrade asks nothing and moves nothing, so ask **Can Item Leave** first. A bag is judged with the bonus items inside it. For extra space whose items go with it when dropped, make the item a bag, as the survival grid's hip pouch is ([Bags](https://rigbak.com/docs/universal-player-combat/inventory-bags)).

---

## Caps per kind

A **Category Limit** carry rule caps each kind with no slots or weight (20 arrows, 4 consumables):

**Details panel: InventoryConfig_MyCaps** (data asset, in Content Browser)

**Category: Containers**

| Property | Value |
| --- | --- |
| Containers | 1 Array element |
| Containers > Index [0] > Container | UPC.Inventory.Container.Satchel |
| Containers > Index [0] > Definition | Container_UPC_Satchel |

**Category: Rules**

| Property | Value |
| --- | --- |
| Carry Rules | 1 Array element |
| Carry Rules > Index [0] | Category Limit |
| Carry Rules > Index [0] > Limits | 2 Array elements |
| Carry Rules > Index [0] > Limits > Index [0] > Category | UPC.Slot.Ammo.Arrow |
| Carry Rules > Index [0] > Limits > Index [0] > Max Units | 20 |
| Carry Rules > Index [0] > Limits > Index [0] > Capacity Tag | MyGame.Capacity.Quiver |
| Carry Rules > Index [0] > Limits > Index [1] > Category | UPC.Slot.Consumable |
| Carry Rules > Index [0] > Limits > Index [1] > Max Units | 4 |
| Carry Rules > Index [0] > Limits > Index [1] > Capacity Tag | None |

*Your own config with caps per kind: 20 arrows plus one per point of MyGame.Capacity.Quiver the character owns, and 4 consumables carried at once. Everything else passes.*

Give each item its kind in **Slot Tags** (`UPC.Slot.Ammo.Arrow`). For a quiver carrying more arrows, give the arrows row a **Capacity Tag** of your own and the quiver a **Capacity Bonus** for it.

---

## Items on the belt and in hand

| Setting | Does |
| --- | --- |
| **Belt Space** | Whether a belt item still takes its container spot. **Keeps Its Place** (default) keeps it. **Frees Its Place** gives it up while on the belt, so a belt clear or unequip that would leave no spot to return to is refused. Weight and category caps count the item either way. In a one-slot container the sword goes on the belt and the slot frees; a pickup fills it; taking the sword off the belt is then refused. |
| **Equipped Space** | The same for an item drawn or worn and off the belt. |
| **Has Belt**, **Belt Slots** | Whether the player has a belt under this config, and its slots' Slot Tags ([Quick Bar](https://rigbak.com/docs/universal-player-combat/quick-bar#a-belt-an-inventory-config-names)). |
| **Show Carried Items On Body** | Hangs every carried Stowable item outside a bag on the body, not only the belt's ([Equipment](https://rigbak.com/docs/universal-player-combat/equipment#show-carried-items-on-the-body)). Off by default; the survival grid turns it on. |
| **Swap When Full** | A pickup with no room puts down the item in the way, in hand or on a belt slot that takes the new one, for the new one ([Pickups, Drops and Holders](https://rigbak.com/docs/universal-player-combat/pickups-drops-holders#when-there-is-no-room)). |

---

## Combine Sets and timing

| Setting | Does |
| --- | --- |
| **Combine Sets** | **Combine Set** assets this style uses, asked in order; empty means a drop never combines ([Combines](https://rigbak.com/docs/universal-player-combat/inventory-combines)). |
| **Equip At Once** | An item equipped from the inventory reaches the hand instantly, no animation or wait. Off plays its draw animation or waits **Draw Timing**. |
| **Draw Timing** | Wait for an item with no draw animation (default 0.2 s; 0 is instant); an item's Equippable can override it. |
| **Put Away At Once**, **Stow Timing** | The same for putting an item away from the inventory. |
| **Combine Result Place** | Where a recipe's first result goes: **Onto The Target** (default), the place of the item combined onto; **Onto The Source**, the place of the item picked first; **As Added**, where a pickup would land. A place counts only when the combine uses up that item's whole stack and the result fits; otherwise the result goes where a pickup would. |
| **Combine At Once** | Every combine unit lands instantly, no wait or unit sounds. Needed for a screen that pauses the game, since a paused world runs no timers. |

A belt press is not timed by these.

---

## Debug it

- Saving a config, a container definition or an item names each setup problem in the Message Log.
- An add took fewer units than asked: print **Get Units That Fit**'s **Out Reason**.

<details>
<summary>Rules in detail (Advanced)</summary>

- A rule is one object every character using the asset shares, so it keeps no state of its own and answers from the inventory alone. **Context** names the inventory and the **Scope** judged: one container, or empty for everything carried, the scope **Get Weight** and **Get Category Count** read.
- The inventory asks each rule once per add, over the contents as they stand, never between units. A rule letting in N units must let in any offer of N or fewer whole, since a pickup adds exactly the units its preview answered.
- A move inside one container changes nothing a rule counts. A move between two judges the destination's rules, and the Carry Rules when it brings an item from storage into what the character carries.
- A swap judges each side as if the other item were already gone (the context's **Departing Item** and **Departing Units**), so two items of equal weight trade places under a full Weight Limit.
- Losing a capacity bonus removes nothing: items past a container's new end keep their places, the container takes new items only in free places inside its end, and a category over its cap takes no more until it is back under.
- A held item moves where it is dropped: **Request Move** lets go of the belt slot or hand first, then places it, and turns the move down when letting go leaves it no place (a Plan Stow that keeps it in hand).
- A rule reading something outside the inventory, such as a strength attribute, calls **Refresh Limits** on the inventory when that thing changes.
- **Is Container In Reach** answers for a whole container, for a bank screen.
- Saving flags a config where nothing takes new items, a Weight Limit of 0, a repeated or incomplete container row, a Slots or Grid container with no room and no bonus, an empty rule or Combine Sets entry, a recipe result no container lets in, and a threshold, category row or Capacity Bonus row with no tag.

</details>

<details>
<summary>What runs where (Multiplayer)</summary>

- The server places every unit and reads the timing settings from the character's config; a request carries no choice of its own.
- Rule status tags sit on the character as one gameplay effect that reaches every machine about half a round trip later and returns at the next change if removed.

</details>

<details>
<summary>C++</summary>

- A rule is a `UUPCInventoryRule` subclass overriding `GetUnitsAccepted_Implementation(const FUPCInventoryRuleContext&, const UUPCItemDefinition*, int32 Count, FGameplayTag& OutReason)` and `GetStatusTags_Implementation(const FUPCInventoryRuleContext&)`. Pass `Context.Scope` as it is to `GetWeight` and `GetCategoryCount`.
- Rules are instanced objects on the config and definition assets, never on the inventory component. `UUPCInventoryConfig::FindCombine` returns the first recipe or combine that takes a pair.
- `UUPCInventoryConfig::FindContainer(Tag)` returns a container's definition; `UUPCInventoryComponent::GetContainerDefinition(Id)` also answers for an open bag's container.

</details>

---

Previous page: [Open World List Inventory](https://rigbak.com/docs/universal-player-combat/inventory-open-world-list). Next page: [Bags and Banks](https://rigbak.com/docs/universal-player-combat/inventory-bags)
