Files
sacred_k/docs/potion-stacks.md
T
khallaandClaude Opus 5.5 13b91cdd3d Potion counts on the bottom bar and potion stacks in the inventory
- potioncounts.cpp: each potion slot shows how many potions of its kind the
  hero carries (stacks added up)
- potionstack.cpp: potions of one type stack up to 20 per cell; every
  potion entering the hero's grid pours into stacks with room, the sort
  button stacks first, drinking takes one off a stack, counts drawn on the
  cells and saved in the JSON inventories
- game/engine/items.h: potion kinds and grid helpers; ObjectManager and
  DestroyObject in objects.h
- auto-attack: the projectile-weapon target radius is a design value
- docs/potion-stacks.md: measured paths and the design

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
2026-10-17 01:31:01 +02:00

3.1 KiB

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).