# Potion counts and potion stacks ## Requests (2026-10-17) 1. The potion selector on the bottom bar always shows how many potions of each kind the hero carries (only when there are any). 2. Potions of the same type stack in one inventory cell, up to 20 per stack. Every potion entering the inventory tries to stack. Drag, sell and drop move a whole stack. The inventory's sort button stacks first, then sorts. A stack dropped on the ground splits into single potions (agreed for now). ## Measured (diagnostic log, 2026-10-17) | Action | Calls | |---|---| | Drink (potion key) | `cEngine::UseActionSlot` `0x613040` → `cCreature::UseItem` `0x54a8f0` → `RemoveItem` (from `0x54aa20`) → `DestroyObject` (from `0x54aa30`); then `UseActionSlot` calls `RemoveItem` again (`0x6130d8`, not found) | | Drag in the inventory | `RemoveAt` from `0x6c06fb` (cell → cursor), `PlaceItem` from `0x6c0583` (cursor → cell) | | Buy | trader grid (inventory 22) `RemoveItem` `0x6d96f5` → hero grid `PlaceItem` `0x6d98e8` | | Pick up from the ground | `PlaceItem` from `0x558db6` | | Trader restock | `RemoveItem` `0x6d9973` + `DestroyObject` `0x6d99cc`, new items `PlaceItem` `0x6d9bdf` | | Sort | `cInventoryEntry::Sort` `0x5db670`: all items removed (`0x5db8a5`) and placed again (`0x5dbb4c`, notify 0) | Not seen yet: a sale, a right-click drink. ## Game side - Potion kinds: `ItemPotionKind` `0x43f630` (ecx = item type table `*0xaa9564`) maps an item type to kind 1..5 (the bottom bar's potion slots); `GetPotionRef` `0x5da880` picks the potion a slot drinks. - Bottom bar: `cUI_Taskbar2::RenderPotionSlots` `0x6e39e0` draws the 5 slot controls (embedded at +0x258, stride 0xbc). - Inventory grid (`cInventoryEntry`, docs/skill-slots.md): cells of 0xc bytes at +0x18; an item's id only in its first cell, covered cells flagged. `CellRect` `0x5dd530` gives a cell's screen rect (32x32 from the origin +0x1164 / +0x1166, which the window sets before `DrawItems` `0x5dc3f0`). - Drinking: `cPotion3D::vf18` `0x5ca9d0` applies the effect and sets object flag +0x14 bit `0x8000000` (used up); `UseItem` then removes and destroys. - Sort button: `cUI_Inventory3::HandleEvent` `0x6c5f40`, button control at +0x158, mode from bit 4 of +0x168. - Hero files map saved item ids to new objects with `ReplaceItemId` `0x5d80e0`. ## Mods - `src/mods/potioncounts.cpp`: counts per kind (stacks added up), drawn bottom-right on each potion slot after `RenderPotionSlots`. - `src/mods/potionstack.cpp`: stack counts by item id (with the item type), saved as `"count"` on the grid cell in the JSON inventories (`inventory_save.cpp`); entry pours into stacks with room on the next tick; `Sort` stacks the hero's potions first; a drink from a stack of more than one takes one off the count and keeps the object; the count is drawn on the cell after `DrawItems`. ## Open - Selling a stack: the price is for one potion so far (sale path not measured). - Dropping a stack on the ground: it should split into single potions; for now the count stays with the object while the game runs, but a save keeps only the object (one potion). ## Chest and other inventories (2026-10-17) Asked: potions stack in every kind of inventory; traders only sell single potions. Measured: the chest is inventory 0x11 (`cUI_Chest` draws window +0x158), saved with the hero as chunk 0xc6 and in save games, both through the JSON path already (stack sizes survived a reload). Stacking now applies to all inventories below 0x12 (players and the chest); trader stock (0x12 and up) never stacks. Selling a stack to a trader still has to be handled (pay count x price, the trader keeps singles).