# Inventory Screens

> Each ready inventory style ships its own inventory screen, opened with I or a tap of View. Copy one and restyle it, or build your own on the checks and requests the shipped screens use.

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

## Set it up (3 minutes)

1. **Use the open world list**

   Open `BP_UPC_Character`, select **InventoryComponent**, and set **Config** to `InventoryConfig_UPC_OpenWorldList` from `Demo/Items/Inventory`.
2. **Take the chest's loot**

   Press Play in `LVL_UPC_Demo`, walk down the hallway to the loot chest and press F. Its three potions, the ring and the necklace move into your satchel.
3. **Drink a potion**

   Press I, or tap View. Click **Consumables** in the category column, or move to it and press A. Point at the potions and click them, press E, or press A: the stack drops to two, and Health rises when it is below full (`UPC.Debug.Vitals 1` shows it). Press I to close.

---

## Keys

| To | Keyboard and mouse | Gamepad |
| --- | --- | --- |
| Open your inventory | I | Tap View (holding it a second respawns) |
| Close it | I or Escape | View or B |
| Open it at a stash box or a loot chest | E | A |

**On the open world list:**

| To | Keyboard and mouse | Gamepad |
| --- | --- | --- |
| Open a category | Click it, or Enter or Right on it | A, or Right |
| Highlight an item; its card follows | Point at it, or Up and Down | D-pad or stick |
| Run its main action; at a chest or the stash, Take or Store | Click it, right click it, or E | A |
| Pick it for Combine | C, or click the Combine prompt | Right trigger |
| Drop it; at a chest, take everything | R | X |
| Put it on a belt slot (a quick-use slot), when the config has one | F, or 1 to 4 for that slot | Y |
| Step through the categories of the panel you are in |  | LB and RB |
| Cross to the chest or stash panel and back | Arrows | D-pad |
| Back to the categories, then close | Left, or Escape | Left, or B |

**On the survival grid and party RPG screens:**

| To | Keyboard and mouse | Gamepad |
| --- | --- | --- |
| Select an item and show its actions | Click it | D-pad |
| Move an item | Drag it | A to pick it up, A where it goes |
| Put a picked-up item back | Escape | B |
| Run its main action; with a chest open, store your own item | Right click it |  |
| Focus its actions | X | X |
| Turn a picked-up item in a grid | R | Y |
| Move between panels | Q and E | LB and RB |
| Put the picked-up or selected item on a belt slot | 1 to 4 |  |

A prompt or button grays out while it cannot run. An item dragged out of the panel drops to the ground. The open world list pauses a solo game; disconnect **Pause For Screen** in the screens component's **Open Inventory** to keep it running.

---

## The three screens

`BPC_UPC_InventoryScreens`, on the player controller, opens the screen its **Inventory Screen Classes** names for the character's config; a config with no row gets the **Fallback Inventory Screen**, the open world list, and a row naming no screen opens none, as for the demo player's `InventoryConfig_UPC_Simple`.

| Config | Screen | Shows |
| --- | --- | --- |
| `InventoryConfig_UPC_OpenWorldList`, unlisted configs, no config | `WBP_UPC_InventoryScreen_OpenWorldList` | Category column, one sorted list, the highlighted item's card with prompts, weight bar |
| `InventoryConfig_UPC_SurvivalGrid` | `WBP_UPC_InventoryScreen_SurvivalGrid` | Grid case of turning items, open pouches' cells under it, key items, Hands doll, Sort button |
| `InventoryConfig_UPC_PartyRPG` | `WBP_UPC_InventoryScreen_PartyRPG` | Backpack with Sort button, one pouch's slots at a time, paper doll, belt row, weight bar |

Each screen also shows the belt when the config has one, and a stash's or chest's items beside yours. [Survival Grid](https://rigbak.com/docs/universal-player-combat/inventory-survival-grid), [Party RPG](https://rigbak.com/docs/universal-player-combat/inventory-party-rpg) and [Open World List](https://rigbak.com/docs/universal-player-combat/inventory-open-world-list) cover each config.

### Item actions

An item's actions follow its fragments ([Items](https://rigbak.com/docs/universal-player-combat/items#what-an-item-is)).

| Action | Works on | Sends |
| --- | --- | --- |
| **Equip**, **Unequip** | An item with an Equippable fragment | **Request Equip Item**, **Request Unequip Item** |
| **Consume** | Demo `BP_UPC_ItemFragment_UseEffect` (potion heals 40, mixed herb 50) | **Request Use Item**, answered by `GA_UPC_UseItem` |
| **Combine** | An item a carried item combines with | **Request Combine** |
| **Drop** | An item with a World Item fragment | `UPC.Event.DropItem`, answered by `GA_UPC_DropFromScreen` |
| **Add to belt** | An item a press of the slot would draw or use | **Request Assign Slot** |
| **Split** (grid, party RPG) | A stack: half moves to the first free place of its container | **Request Move** |
| **Take**, **Store** (chest or stash box) | An item in the chest or stash, or yours while one is open | **Request Transfer** at a chest, **Request Move** at the stash |

The main action is the first that applies: Take, Store, Unequip, Equip, Consume. Consume and Drop need `GA_UPC_UseItem` and `GA_UPC_DropFromScreen`, which the demo's `AbilitySet_UPC_Default` grants; add both to your character's **Starting Ability Set** ([Input](https://rigbak.com/docs/universal-player-combat/input#abilities-that-answer-a-key)).

---

## Combine

Pick **Combine** on an item (C or the right trigger on the open world list, the item's actions elsewhere), then pick the other item with its main action. An item in hand counts, so poison coats the sword in hand. A line with a Cancel button names the picked item; Cancel, Back, a right click, closing the screen or a count change lets it go. On the grid and party screens, dropping one item on another also combines them. [Combines](https://rigbak.com/docs/universal-player-combat/inventory-combines) covers recipes.

---

## Open it at a box or a chest

On the actor's **UPC Interactable**, an **Options** entry with **Option Id** `OpenInventory` opens the screen as its payload starts, with the actor's **UPC World Inventory** beside your bag when it has one. An option with no payload opens nothing, so give it one that ends at once. Closing the screen brings the prompt back.

In **Interaction Option**, under Option, set:

| Property | Value |
| --- | --- |
| Option Id | OpenInventory |
| Payload Spec | Delay |
| Delay Seconds | 0 |

- **Stash:** `BP_UPC_StorageBox` gives the character its storage container's Access Tag while it stands in the box's zone, so any inventory screen opened there shows the stash beside your items. A project that wants the stash only through the box's Open option grants the Access Tag when that option runs instead of on entering the zone. Take and Store move as many units as fit, to the place where most fit; a drag moves them where you drop them.
- **Loot chest:** `BP_UPC_LootChest`'s E opens the screen and F takes everything without one ([Loot Chests](https://rigbak.com/docs/universal-player-combat/loot-chests)).

An item in the stash or chest also takes **Equip**, **Add to belt** and a drag onto the belt or paper doll: one step brings it into your inventory and hand or belt, under a Take's checks (reach, access, weight). A refusal shows on the message line (Too Heavy, Full). On the survival grid an item on the belt or in hand takes no cell.

---

## Copy a screen into your game

The screens are standard-UMG Widget Blueprints in `Demo/UI/Widgets/Inventory`.

1. **Duplicate the screen** and `BPC_UPC_InventoryScreens` into your folder, and put the component copy on your player controller in place of the demo's. It toggles the screen on `IA_UPC_Inventory` (mapped to I and a tap of View in the demo's `IMC_UPC_Default`); a controller of your own needs a mapping context with that action.
2. **Register your config:** add a row to **Inventory Screen Classes**, a map in the component copy's Class Defaults (not on the config), pairing your config with your screen; without one the copy opens the fallback.

**Details panel: Class Defaults** (Blueprint, in BPC_UPC_InventoryScreens)

**Category: Inventory Screens**

| Property | Value |
| --- | --- |
| Inventory Screen Classes | 3 Map elements |
| Inventory Screen Classes > key InventoryConfig_UPC_OpenWorldList | WBP_UPC_InventoryScreen_OpenWorldList |
| Inventory Screen Classes > key InventoryConfig_UPC_SurvivalGrid | WBP_UPC_InventoryScreen_SurvivalGrid |
| Inventory Screen Classes > key InventoryConfig_UPC_PartyRPG | WBP_UPC_InventoryScreen_PartyRPG |
| Fallback Inventory Screen | WBP_UPC_InventoryScreen_OpenWorldList |
| Inventory Screen Context | IMC_UPC_InventoryScreen |
| Inventory Screen Context Priority | 100 |
| Open Inventory Option Id | OpenInventory |

*The screen each inventory config opens. A config with no row, and an inventory with no config, open the fallback.*

3. **Restyle the copy** in the Widget Blueprint editor. Most games change these:

| Setting | On | Holds |
| --- | --- | --- |
| **Category Rows** | Open world list | Each category's label and item kinds; **Other Kinds** for what no row names, **Belt Only** for the belt's items |
| **Places** | `WBP_UPC_PaperDoll` | Each body place, its label and tile position |
| **Refusal Words** | Message line | Words per refusal reason; a reason with no row shows the last part of its tag |

`WBP_UPC_ListPanel` draws one container as a category column beside a sorted list; place one per inventory shown. **Mirrored** puts the column on the right, **Neighbor** lets the arrows cross to the next panel.

A copy keeps using the `Common` blocks (tiles, views, panels, paper doll, message line) and the carry flow in `BFL_UPC_InventoryScreens` (pick up, put down or back, send to belt), so keep the demo in your project.

**Rearrange freely.** The screen finds each piece by its variable, so move or wrap any panel. The weight bar, belt panel, hint bar and item details can go; the list, grid and slot views, message line and actions are its core.

---

## Restyle everything from one asset

Change **Colors**, **Fonts**, **Surfaces** (including **Extra Cells**, the frame around a pouch's cells) and **Sizes** in `Demo/UI/Theme/UITheme_UPC_Default`; screens (copies too), HUD, interaction prompts and showcase key hints follow. To theme a widget you add, give it a row in the **Theme Roles** map in its containing Widget Blueprint's Class Defaults: the widget's name and a role, such as `InfoBox` with Panel for a Border named InfoBox. Rename the key with the widget, or that part keeps its own look and the Output Log names the old key.

---

## Build your own screen

A screen of your own reads the inventory on the player's machine and sends requests; only the server changes it:

1. **Draw** each container **Get Containers** lists, from **Get Items in Container** (it leaves out an item that gave up its place while on the belt or in hand), on the pawn's **UPC Inventory**.
2. **Bind** **On Layout Changed** to redraw the container it names, and **On Capacity Changed** to redraw one that grew, shrank, opened or closed.
3. **Act** through a request: ask its check (table below), then send it. A Take or Store button picks no place, so it first asks a finder where the most units fit, then sends the finder's **Out Destination**:

| Button | Ask | Then send |
| --- | --- | --- |
| Take from a chest, or Store in one | **Find Transfer Destination**, with the chest's World Inventory | **Request Transfer** |
| Store in the stash | **Find Move Destination**, with the stash's container | **Request Move** |
| Take out of the stash | **Find Add Destination** | **Request Move** |

The server makes the change; On Layout Changed redraws it.

### Read the inventory

The smallest read side prints a container on every change:

Blueprint graph, nodes in reading order:

- **Comment box: BP_UPC_Character · print a container whenever it changes**

  - **On Layout Changed (InventoryComponent)** (event); outputs: Container
  - **Get Items in Container** (pure function); inputs: Target, Container; outputs: Return Value
  - **For Each Loop** (macro); inputs: Array; outputs: Loop Body, Array Element, Array Index, Completed
  - **Get Item Def** (pure function); inputs: Target; outputs: Return Value
  - **Display Name** (pure function); inputs: Target; outputs: Display Name
  - **Get Item Stack Count** (pure function); inputs: Target, Instance; outputs: Return Value
  - **Format Text** (pure function); inputs: Format = {Name} x{Count}, Name, Count; outputs: Result
  - **Print Text** (function); inputs: In Text

<details>
<summary>Every read node and event (Advanced)</summary>

| Node | Answers |
| --- | --- |
| **Get Containers** | Every container in the order adds fill them, open bags included. |
| **Get Container Definition** | **Display Name**, **Icon**, **Layout**. |
| **Get Container Size** | Slots by 1, columns by rows, or 0 by 0 for a list. |
| **Get Items in Container** | Items in place order. |
| **Get Items in Sort Order** | Items in the order **Request Sort** would lay them out, moving nothing. |
| **Get Item At** | The item in a slot (a grid cell included) or at a list position. |
| **Get Item Placement** | **Container**, **Position** (-1 for no place) and **Rotated**. |
| **Get Item Cells**, **Get Position Of Cell** | An item's top-left cell and size as it lies; the Position a cell stands for. |
| **Get Item Stack Count** | The count to print. |
| **Get Weight**, **Get Effective Limit** | The load; the Weight Limit rule's limit with its bonus. |
| **Get Item Footprint** | Grid size, for a drag picture or tile. |
| **Is Held By** | Whether the belt or a hand holds the item. |

| Event | Fires |
| --- | --- |
| **On Layout Changed** | Once per changed container, after the change settles. |
| **On Capacity Changed** | A container's size changes (capacity bonus, bag opening or closing). |
| **On Carry Changed** | A change that can move the load or a rule's answer: reread Get Weight. |
| **On Item Count Changed** | With an item and the units the character carries. |
| **On Combined** | As a combine's units land, once per group landing together. |

</details>

### Ask before you send

The server runs each request's check too; ask it first so a button grays out.

| Before you send | Ask |
| --- | --- |
| **Request Move** | **Can Place** |
| **Request Transfer** (chest) | **Can Transfer** |
| **Request Assign Slot** (belt) | **Can Assign Slot** |
| **Request Equip Item** (equipment manager) | **Can Equip Item** |
| **Request Unequip Item** | **Can Unequip Item** |
| **Request Use Item** | **Is Item Carried And In Reach** |
| **Request Combine** | **Can Combine** (UPC Inventory Statics) |
| A Drop button | **Can Item Leave** |
| A bank panel's "go to the bank" state | **Is Container In Reach** |

<details>
<summary>Move, sort, Take and Store (Advanced)</summary>

**Can Place** answers what moving **Count** units to a **Destination** would do, with **Out Units** the units that move:

| Answer | The drop |
| --- | --- |
| **Place** | Moves into a free place; part of a stack splits off there. |
| **Merge** | Joins a stack of the same item, as many units as fit (5 of 15). |
| **Swap** | Trades places with the one item there. |
| **Combine** | Runs a Combine Set recipe or combine ([Combines](https://rigbak.com/docs/universal-player-combat/inventory-combines)). |
| **Into Bag** | Goes inside the open bag there ([Bags and Banks](https://rigbak.com/docs/universal-player-combat/inventory-bags)). |
| **Refused** | Moves nothing; **Out Reason** says why. |

**Request Move** moves the units as Can Place answered. A held item moves where it is dropped: Request Move lets go of it first (belt clear, or put-away for an item in hand alone), then places it, and refuses when letting go leaves it no place. A screen's drop onto a place sends the move first, then clears the belt slot or sends Unequip (sent first, an Unequip can start a timed put-away that refuses the move). Where **Belt Space** or **Equipped Space** frees an item's place, as on the survival grid, one request takes the whole stack off the belt or out of the hand. **Find First Fit** answers the first free place a new stack would take, for a "move to" button.

**Request Sort** tidies one container: same-item stacks join, then items follow the config's **Sort Order**, then name, then larger stacks (a grid places larger items first). A container it cannot lay out whole stays as it was. Call both requests on the player's machine. A finder prefers a stack with room over a free place, and answers a refusal with its reason when nothing fits.

</details>

<details>
<summary>Why a move is refused (Advanced)</summary>

Each reason is a tag under `UPC.Inventory.Refused`, worded for the player by the demo's **Refusal Words**:

| Reason | Means |
| --- | --- |
| `Full` | No free place, or the stack to join is full. |
| `TooHeavy`, `CategoryFull`, `NotAdmitted` | A Weight Limit, Category Limit or Item Filter refused it. |
| `NoAccess` | Missing a container's or chest's Access Tag. |
| `OutOfReach` | A chest beyond its Access Radius. |
| `OutOfBounds` | A place outside the container, a disallowed turn, a container the inventory lacks, or a bag's own container. |
| `Occupied` | Items there the moved item can neither join nor swap with. |
| `Held` | A stack on the belt or in hand would leave what the character carries, or empty into another stack. A finder answers Held only when more would land once the belt or hand let go; a full chest answers Full. |
| `CapacityInUse` | An item giving extra slots or rows leaves while items lie there (the demo says Empty the extra slots first). |
| `Split` | Part of a stack whose units carry their own state, such as charges; it moves whole. |
| `BagNotEmpty` | A bag holding items would go inside another bag. |
| `NoCombine` | **Request Combine** named two items no Combine Set takes. |
| `NotEnough` | A recipe needs more units than the stack holds. |
| `Locked` | Missing the recipe's Required Tags. |

</details>

<details>
<summary>Equip from the inventory (Advanced)</summary>

| Request | Does |
| --- | --- |
| **Request Equip Item** | Draws or puts on an owned item, putting away whatever holds its places. **Place** names the body place; empty takes the places a press would. |
| **Request Unequip Item** | Puts a drawn or worn item away. |
| **Request Cancel Sequence** | Stops the running change while a pending step names the item, as closing a screen does. |

The config's **Equip At Once** and **Put Away At Once** pick instant landing or **Draw Timing** and **Stow Timing**, each with optional start and land sounds and **Cancel on Move** ([Containers and Rules](https://rigbak.com/docs/universal-player-combat/inventory-containers#combine-sets-and-timing)). A belt press is not timed this way.

**Can Equip Item** wants the item equippable, out of hand and takeable (**Can Take To Hold**: carried and in reach, or in reach in the stash or a chest with a carried container that takes the whole stack), the equipment action's **Plan Draw** to agree, a place to return to under **Equipped Space**, and no running change or action holding equipment back. **Can Unequip Item** wants it in hand with a place to go back to, and **Plan Stow** to agree ([Equipment](https://rigbak.com/docs/universal-player-combat/equipment) covers both plans).

A progress bar listens to the equipment manager's **On Equip Step Started** (the step's **Source Item** and **Timing** from **Start Time**) and **On Equip Sequence Ended** (a stop's **Reason** under `UPC.Equipment.Cancelled`: Moved, Asked, Blocked, Item Left or Interrupted; steps that landed stay), and reads **Get Playing Step** when it opens partway through.

A paper doll lists its places, asks **Get Instance In Place** for each (skipping the item with **Is Default Item** true) and redraws on **On Drawn State Changed**. A dragged item lights a place where **Can Equip Item** with that **Place** says yes, and the drop sends **Request Equip Item** with it. [Equipment](https://rigbak.com/docs/universal-player-combat/equipment) covers worn gear and places.

</details>

<details>
<summary>The belt from a screen (Advanced)</summary>

| Request | Does |
| --- | --- |
| **Request Assign Slot** | Puts an item in a belt slot, as a belt drop does. Empty clears it; an item from another slot trades places; an inventory item takes the slot from the item there. An item in hand is let go at once, with no animation. |
| **Can Assign Slot** | Whether it would land: Filter, copy limit, reach, and a place for the item the belt lets go. A stash or chest item passes when **Can Take To Hold** does. |

**Find Quick Bar For Pawn** finds a belt, **Get Slot Of Item** an item's slot, and **Equip Item If Free** draws an item from code at once when it is undrawn, carried, in reach and its places are free.

The demo screens and HUD draw the belt with **Get Belt Layout**: a diamond for four slots that each name an item kind, a row otherwise, None (hiding every belt part) for no slots. They offer only items **Can Put On Belt** allows (Equippable or Use Effect fragment). Both live in `BFL_UPC_InventoryScreens`; [Quick Bar](https://rigbak.com/docs/universal-player-combat/quick-bar) owns the belt's rules.

</details>

<details>
<summary>Use, drop and move sounds from a screen (Advanced)</summary>

**Request Use Item** uses an item, as a belt slot does ([Inventory](https://rigbak.com/docs/universal-player-combat/inventory#use-an-item)). A Drop button asks **Can Item Leave** (false out of reach; a bag leaves with its items), then sends `UPC.Event.DropItem`, answered by a **UPC Drop Ability** with **Item Selection** **From Event** and an **Ability Trigger** on that event, as `GA_UPC_DropFromScreen` ([Pickups, Drops and Holders](https://rigbak.com/docs/universal-player-combat/pickups-drops-holders#dropping)).

**Get Inventory Move Sound**, on the equipment manager, gives the pick-up or put-down sound, or None when the item's own draw or put-away sound plays.

</details>

---

## Debug it

`Log LogUPCInventory Verbose` names refused inventory requests, `Log LogUPCEquipment Verbose` equipment ones.

<details>
<summary>What the screens show (Advanced)</summary>

- **A tile** shows the icon, count (×4), belt slot in a key-cap badge, an equipped mark, and a holder's load (6/15 on a magazine). A timed equip or combine draws a progress bar along it; closing the screen stops it.
- **A dragged item** stays at the spot you pressed. On the survival grid its picture covers its cells and the case lights them. A line names the put-down (Put it here, Swap places, Combine) or, in **Refusal Words**, why not. Let go inside the panel away from any tile, it stays put.
- **The paper doll** shows head, neck, shoulders, chest, hands, feet, both hands and both rings. A drop on a place puts back what held it (a spare sword on the shield's place swaps the two); a worn tile dragged off comes off. A place lights green where **Can Equip Item** takes the item, red where not; the off hand grays out while a two-handed weapon holds both hands.
- **The open world list** shows icon, name, count, weight and gold value, and refuses a reorder (it keeps its sort order).
- **An open screen** stops move, look and combat input; the HUD stays and interaction prompts hide. The screens component reads **Pauses Game** from **Get Screen Rules** on opening; while paused, the screen's keys keep working and an equipped item shows at once.
- The Inter and Cinzel licenses ship beside their fonts in `Demo/UI/Fonts`.

</details>

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

- A screen opens only for its controller's local player and reads that player's inventory.
- In split screen each screen sits on its player's part (scaled down when too wide) and only the first player has the mouse. Input mode is **Game and UI**, never UI Only, which would freeze the other player.
- Every request is a reliable server call; the server runs the same check and drops a refusal silently. Nothing is predicted, so a change (or another player's chest take) arrives about a round trip later.
- **Request Use Item** and a belt use both send `UPC.Event.UseItem`, so one Server Only ability answers both. A timed equip or combine plays on the player's machine about half a round trip after the server and stops with the server's reason.

</details>

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

- `UUPCInventoryComponent::CanPlace` and `RequestMove` share one check, answering `EUPCPlaceResult`; `GetItemsInSortOrder` and `RequestSort` share one comparator.
- `RequestUseItem` refuses a world inventory, asks `IsItemCarriedAndInReach` and sends `UPC.Event.UseItem`, the event `UUPCQuickBarComponent` sends for a slot holding an item that is not equippable.
- `RequestEquipItem(Item, Place)` and `RequestUnequipItem(Item)` ask `CanEquipItem` or `CanUnequipItem`, then run `DrawWithReach` and `StowWithReach`, or `DrawAtOnce` and `StowAtOnce` under the config's `bEquipAtOnce` and `bPutAwayAtOnce`. The equipment action's `PlanDraw` and `PlanStow` decide what a draw plays.
- `RequestCombine(Item, Target)` runs `CanCombine`, then one equipment change through `StartCombine`; `bCombineAtOnce` lands every unit in that call.
- `FUPCItemActionTiming` holds Seconds, the two sounds and Cancel on Move, on the config and on the Equippable fragment.
- The screens add no C++ widget class: each derives from User Widget, apart from the hint bar and its row, which derive from `UUPCInputHintListWidget` and `UUPCInputHintWidget`.

</details>

<details>
<summary>Troubleshooting (Advanced)</summary>

- **I opens no screen.** The player controller carries no `BPC_UPC_InventoryScreens`, or its mapping context lacks `IA_UPC_Inventory`.
- **I opens the open world list under another style.** **Inventory Screen Classes** has no row for the character's config.
- **Consume is missing or does nothing.** The item has no Use Effect fragment, the ability set lacks `GA_UPC_UseItem`, or your own use ability is not Server Only.
- **The storage panel never shows at a box.** The box's Access Tag differs from the Access Tag of the config's storage container.
- **Combine does nothing.** No recipe or combine in the config's Combine Sets takes the pair ([Combines](https://rigbak.com/docs/universal-player-combat/inventory-combines)).

</details>

---

Previous page: [Loot Chests](https://rigbak.com/docs/universal-player-combat/loot-chests). Next page: [Saving the Inventory](https://rigbak.com/docs/universal-player-combat/inventory-saving)
