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>
This commit is contained in:
1 parent
b2e886c7f5
commit
13b91cdd3d
13 files changed
+612
-10
No files matched your search
@@ -0,0 +1,73 @@
|
||||
// Potion counts on the potion slots of the bottom bar.
|
||||
//
|
||||
// Request (2026-10-17): the potion selector always shows how many potions of
|
||||
// each kind the hero carries (only when there are any).
|
||||
//
|
||||
// The bar shows 5 potion kinds: cUI_Taskbar2::RenderPotionSlots (0x6e39e0)
|
||||
// draws control k-1 (embedded at +0x258, stride 0xbc) when
|
||||
// cInventoryEntry::GetPotionRef(k) finds a potion of kind k, else the empty
|
||||
// control behind it (+0x3ac). GetPotionRef walks the inventory grid and asks
|
||||
// ItemPotionKind for each item's kind; the count here does the same and adds
|
||||
// up the potion stacks (potionstack.cpp).
|
||||
|
||||
#include <cstdint>
|
||||
#include <cwchar>
|
||||
|
||||
#include "game/engine/items.h"
|
||||
#include "game/engine/objects.h"
|
||||
#include "game/ui/text.h"
|
||||
#include "mods/potionstack.h"
|
||||
#include "mods/skillslots.h"
|
||||
#include "re/hook.h"
|
||||
|
||||
namespace mods::potioncounts {
|
||||
namespace {
|
||||
|
||||
// cUI_Taskbar2 fields.
|
||||
constexpr size_t kInventoryIndex = 0x158; // u16: the hero's inventory
|
||||
constexpr size_t kPotionSlots = 0x258; // game::kPotionKinds embedded controls
|
||||
constexpr size_t kPotionSlotSize = 0xbc;
|
||||
|
||||
constexpr uint16_t kCountFont = 1; // as the art cooldown labels (skillbar.cpp)
|
||||
constexpr uint32_t kCountColor = 0xffffffff;
|
||||
constexpr int kCountInset = 3; // from the slot's bottom-right corner
|
||||
|
||||
void RenderCounts(uint8_t* taskbar, void* renderer) {
|
||||
const uint8_t* inventory =
|
||||
skillslots::Inventory(*reinterpret_cast<const uint16_t*>(taskbar + kInventoryIndex));
|
||||
if (!inventory || !game::GetPlayerHero()) {
|
||||
return;
|
||||
}
|
||||
unsigned counts[game::kPotionKinds + 1] = {};
|
||||
game::ForEachGridItem(inventory, [&](uint32_t id) {
|
||||
const int kind = game::PotionKindOf(id);
|
||||
if (kind >= 1 && kind <= game::kPotionKinds) {
|
||||
counts[kind] += potionstack::StackCount(id);
|
||||
}
|
||||
});
|
||||
const int lineHeight = game::FontLineHeight(kCountFont);
|
||||
for (int kind = 1; kind <= game::kPotionKinds; ++kind) {
|
||||
if (counts[kind] == 0) {
|
||||
continue;
|
||||
}
|
||||
game::UiRect rect = game::ControlScreenRect(taskbar + kPotionSlots + (kind - 1) * kPotionSlotSize);
|
||||
rect.y += rect.h - lineHeight - kCountInset;
|
||||
rect.w = static_cast<int16_t>(rect.w - kCountInset);
|
||||
wchar_t text[8];
|
||||
swprintf_s(text, L"%u", counts[kind]);
|
||||
game::DrawText(renderer, kCountFont, rect, text, kCountColor, game::kTextRight);
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace
|
||||
} // namespace mods::potioncounts
|
||||
|
||||
// cUI_Taskbar2::RenderPotionSlots (0x6e39e0, ret 4): then the counts.
|
||||
void __fastcall UiTaskbar_RenderPotionSlots(void* self, void* edx, void* renderer);
|
||||
RE_HOOK(0x006e39e0, UiTaskbar_RenderPotionSlots);
|
||||
void __fastcall UiTaskbar_RenderPotionSlots(void* self, void* edx, void* renderer) {
|
||||
UiTaskbar_RenderPotionSlots_original(self, edx, renderer);
|
||||
if (self) {
|
||||
mods::potioncounts::RenderCounts(static_cast<uint8_t*>(self), renderer);
|
||||
}
|
||||
}
|
||||
Reference in new issue
Block a user