- Options window in three tabs; the auto-pickup settings move to Beute; sliders move with their page; black sides like the save game screen. - Tastenbelegung: every binding settable (click, press key; Esc cancels, Backspace unbinds), "Alle zurücksetzen" as a game button, saved on OK. - Potions bindable (default unbound), named by the game's potion texts; the game's own potion hotkeys are off; bar tooltips show the bound key. - Map (M), overview map (Tab, held) and labels (Alt, held) bindable; the game's own M / Tab / Alt handling is switched off. - Save game key calls the game's save window code instead of a posted key. - Teleportationstrank: fixed text replacement from startup (also the Ausdauertrank items, potion kind 5 as well). Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
90 lines
3.7 KiB
C++
90 lines
3.7 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);
|
|
}
|
|
|
|
constexpr size_t kTabControlActive = 0x84; // u16
|
|
|
|
inline uint16_t ActiveTab(void* sheet) {
|
|
const uint8_t* control = TabControl(sheet);
|
|
return control ? *reinterpret_cast<const uint16_t*>(control + kTabControlActive) : 0;
|
|
}
|
|
|
|
// 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
|