The chest is inventory 0x11 and already saved as JSON; stacking now applies to all inventories below 0x12. Traders keep selling single potions. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
70 lines
3.6 KiB
Markdown
70 lines
3.6 KiB
Markdown
# 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).
|