Files
sacred_k/src/game/ui/tabs.h
T
khallaandClaude Opus 5.5 6ca96d54b4 Shared chest tabs, rune stacks and rune master, Q pickup, Kettenblitz tooltip and range
- Shared chest: tabs "Truhe"/"Gemeinsam" as a column left of the grid
  (game tab sheet), grids placed every tick, persistent across heroes
- Inventory tab texts capitalized (RegisterText / CapitalizeText)
- Combat-art runes stack like potions (itemstack, renamed from potionstack)
- Rune master: any rune for any number of runes, price by rune count
  (4 runes = 1,000, x10 per missing rune), bought rune goes into the
  backpack, Buy disabled without runes, gold or room, last rune remembered
  per hero (saved), the chosen rune's name below its icon, dropping a
  stack gives up one rune
- Keys: the old key handling no longer takes over after the save screen
  (text field focus only counts while its dialog is shown)
- Esc crash: tooltips forgotten when the game destroys them
- Pick up (Q) sends the pickup order directly; search reach doubled
- Kettenblitz: tooltip shows hits per chain, chains, cast and jump range;
  cast range 900 (longer ray segments), jumps half of that

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

83 lines
3.4 KiB
C++

#pragma once
// cUI_TabSheet (0x80 bytes, vtable 0x895258): a control with tab headers
// (the inventory's "Rucksack" / "Kampfkünste" / "Combos"). Its cUI_TabControl
// at +0x78 (0x98 bytes, constructor 0x7278f0) holds the tabs: a vector of
// 0x18-byte entries at +0x78/+0x7c {text id, rect (+4 x, +8 y, +0xc w|h),
// header control (+0x10), page (+0x14)}, the active index at +0x84 (u16).
// Header controls: +0x24 x, +0x28 y, +0x2c w|h (relative to the sheet).
// Layout (0x729210) puts the headers in a row above the sheet; a click on a
// header reaches SetActive, which hides the old page and shows the new one
// (page vf24(show)). Selected / hover / normal look is the game's own
// (cUI_TabControl::Render 0x728090).
#include <cstddef>
#include <cstdint>
#include "game/ui/text.h"
namespace game {
constexpr size_t kTabSheetSize = 0x80;
constexpr size_t kTabSheetControl = 0x78; // cUI_TabControl*
constexpr size_t kTabControlTabs = 0x78; // entries begin; +0x7c end
constexpr size_t kTabEntrySize = 0x18;
constexpr size_t kTabEntryRect = 0x4;
constexpr size_t kTabEntryHeader = 0x10;
constexpr size_t kControlRect = 0x24; // a control's rect (x, y, w|h), relative to its parent
// The header art's height (left piece; static data filled when the UI loads).
constexpr uintptr_t kTabHeaderArtHeight = 0x009ed17c;
// The game's operator new (0x8485e2, cdecl): controls the UI deletes itself
// must come from it.
inline void* GameNew(size_t size) {
return reinterpret_cast<void*(__cdecl*)(size_t)>(0x008485e2)(size);
}
// cUI_TabSheet::cUI_TabSheet (0x728ed0, ret 0x18): (name, rect by value,
// parent, 5); the inventory passes 5 as the last argument.
inline void* NewTabSheet(const char* name, UiRect rect, void* parent) {
void* sheet = GameNew(kTabSheetSize);
using ConstructFn = void*(__fastcall*)(void*, void*, const char*, UiRect, void*, uint32_t);
return sheet ? reinterpret_cast<ConstructFn>(0x00728ed0)(sheet, nullptr, name, rect, parent, 5) : nullptr;
}
// cUI_TabSheet::AddTab (0x7290d0, ret 8): (text id, page control).
inline void AddTab(void* sheet, uint32_t textId, void* page) {
using AddFn = char(__fastcall*)(void*, void*, uint32_t, void*);
reinterpret_cast<AddFn>(0x007290d0)(sheet, nullptr, textId, page);
}
// cUI_TabSheet::SetActive (0x7291d0, ret 4).
inline void SetActiveTab(void* sheet, uint16_t index) {
using SetFn = void(__fastcall*)(void*, void*, uint32_t);
reinterpret_cast<SetFn>(0x007291d0)(sheet, nullptr, index);
}
inline uint8_t* TabControl(void* sheet) {
return *reinterpret_cast<uint8_t**>(static_cast<uint8_t*>(sheet) + kTabSheetControl);
}
// The tab entries of a cUI_TabControl.
inline uint8_t* TabEntries(uint8_t* control) {
return *reinterpret_cast<uint8_t**>(control + kTabControlTabs);
}
inline size_t TabCount(uint8_t* control) {
uint8_t* begin = TabEntries(control);
uint8_t* end = *reinterpret_cast<uint8_t**>(control + kTabControlTabs + 4);
return begin ? static_cast<size_t>(end - begin) / kTabEntrySize : 0;
}
} // namespace game
namespace game {
// cUI_Window2::AddControl (0x727120, ret 4): the window renders the controls
// in its list (+0x78) and hands them its events (cUI_Window2::Render 0x727040,
// HandleEvent 0x726880). A control's parent alone doesn't do that.
inline void AddWindowControl(void* window, void* control) {
using AddFn = void(__fastcall*)(void*, void*, void*);
reinterpret_cast<AddFn>(0x00727120)(window, nullptr, control);
}
} // namespace game