Files
sacred_k/docs/shared-chest.md
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

4.0 KiB

Shared chest

Request (2026-10-17)

The chest gets a second tab that belongs to no single hero: a chest shared by all characters. Decided: stored in one file in the save folder (save\shared_chest.json), two tabs ("Truhe" / "Gemeinsam"), same size as the chest (20 x 10). Potions stack in it like in every player inventory (docs/item-stacks.md). Follow-up (same day): text tabs were barely visible; use the inventory's Rucksack / Kampfkünste / Combos header look with its selected state, stacked as a column from the grid's top-left. The shared chest was empty after loading another character (in-game saves don't call saveHero).

Measured / read

  • The chest window cUI_Chest (constructor ends 0x6ac899): +0x158 = inventory 0x11 (the hero's chest), grid 20 x 10 from (window x, 20). Render 0x6ac8b0 (vf14) draws +0x158 with DrawItems; HandleEvent 0x6acc70 (vf10) does hit test, fit, place, swap and take via +0x158. Only Shift+click uses the index: cInventoryManager::MoveItem 0x5dec80 (from, to, id, ?, ret 0x10) from 0x11 to the hero.
  • Chest saving: inventory 0x11 is chunk 0xc6 of the hero file and part of save games, both through the JSON inventories already (diagnostic log).
  • Items in hero files (ItemDataMgr::saveHero 0x6046f0, chunk 0xc2): the ids of both inventories, equipment, weapon sets; per item its type (+0x10) and the object's serializer vf1c(stream, 1, 0) (ret 0xc).
  • Loading (loadHero 0x605900, chunk 0xc2): cObjectManager::Create(type, 0, 0, 0) 0x5fb590, vf1c(stream, 0, version) (version = header byte, 0x1b), then the saved id (read into +0xc) is replaced by the new one (ReplaceItemId), flags +0x14: clear 0x200000, 0x30 if bit 2, 0x10; +0x39 = owner hero id.
  • cEngine::~cEngine 0x60d5e0 (plain ret) runs before the object manager is destroyed: game::OnGameEnd.

Mod (src/mods/sharedchest.cpp)

  • An inventory of our own (cInventoryEntry::Construct 0x5d7a10, owner 0x11 so it counts as a player inventory).
  • Tabs: a cUI_TabSheet (constructor 0x728ed0, AddTab 0x7290d0) built right after the chest window (cUI_Chest::cUI_Chest 0x6ac7f0), the same control as the inventory's Rucksack / Kampfkünste / Combos headers, so the selected / hover look is the game's. Its layout (0x729210, headers in a row above the sheet) is followed by ours: a column left of the grid's top-left corner. Labels "Truhe" / "Gemeinsam" through game::RegisterText (src/game/ui/texts.cpp, an override of GetText 0x672f70). Switching (cUI_TabControl::SetActive 0x728af0) sets window +0x158 to inventory 0x11 or the shared one (origin and size copied from the chest). Pages are empty controls.
  • The tab sheet is added to the window's control list (cUI_Window2::AddControl 0x727120); only those controls are drawn and get events (a parent alone isn't enough).
  • Grid place: the constructor sets inventory 0x11 to (window x, 20), 20 x 10 once, but loads overwrite it (the game's inventory read 0x5df09b resets some inventories to 0/0; the JSON inventories restore the saved place), so the chest drew at the wrong spot after some loads. Both tabs' grids are put back to the constructor's values every tick and on each tab switch.
  • MoveItem from/to 0x11 while the shared tab is open moves from/to it.
  • File: {"format": "sacred_re.shared_chest", "version": 1, "items": [{cell, w, h, type, data (hex of vf1c), count}]}; written after each successful saveHero and after each save-game write (in-game saves don't call saveHero; via a temp file), read on the first engine tick with a hero after a session start (game::OnGameStart, cEngine::cEngine 0x60ac70) or a save-game read with a hero; the grid is cleared when the session ends.

Open / to check

  • Whether save games (PAK) also store the shared chest's item objects (they live in the object manager outside the 32 inventories).
  • loadHero's extra fix-up for some item classes (0x5beaa0 / 0x5d3a20, item classes 5, 6, 8, 0xd, 0x11..0x19, 0x1b, 0x1d) is not repeated.
  • Multiplayer: not supported.