From 9fb6c6b406e7af8524edd5ff21b3449665f48d6b Mon Sep 17 00:00:00 2001 From: Torhan Bartel Date: Wed, 14 Oct 2026 23:48:11 +0200 Subject: [PATCH] docs: map inventory weapon sets and combat-art slots; function names Groundwork for 7 weapon sets / 7 combat-art slots (docs/skill-slots.md). Co-Authored-By: Claude Opus 5.5 (1M context) --- docs/skill-slots.md | 91 +++++++++++++++++++++++++++++++++++++++++++++ tools/names.txt | 27 +++++++++++++- 2 files changed, 117 insertions(+), 1 deletion(-) create mode 100644 docs/skill-slots.md diff --git a/docs/skill-slots.md b/docs/skill-slots.md new file mode 100644 index 0000000..6910393 --- /dev/null +++ b/docs/skill-slots.md @@ -0,0 +1,91 @@ +# 7 weapon sets and 7 combat-art slots (planned) + +Goal (user request 2026-10-14): 7 weapon sets and 7 combat-art slots instead +of 5 each; skills on 1-7, weapon sets on F1-F7; old saves keep loading +(migration on read). Status: mapping, nothing changed yet. + +## Where the slots live + +### `cInventoryEntry` (one per player, no vtable) + +All 32 inventories are one block from `cInventoryManager::Instance` +(`0x5deb80`, 32 x 0x1180 + 8 bytes at `*0xad23c8`); `GetInventory` +(`0x5dec50`) hardcodes the stride 0x1180. An inventory's index is therefore +`(inventory - block) / 0x1180`. + +| Offset | Size | Content | +|---|---|---| +| +0x18 | 0x100 x 0xc | item grid | +| +0xc18 | 5 x 0x18 | weapon sets: 2 hands x (item id, 2 dwords) | +| +0xc90 | 5 x 2 x 0x14 | art slots: 2 variants (bit 2 of +0x1162, maybe mounted) x {u16 type 2/3/4, u16, id, 3 dwords} | +| +0xd58 | 2 x u16 | selected slot: [0] weapon set, [1] art slot | +| +0xd5c | 0x400 | (next field, unrelated) | +| +0x115c / +0x115e | u16 | grid width 0x14 / height 8 | +| +0x1160 | u16 | player index | +| +0x1162 | u16 | flags | + +The three slot arrays are packed together, so there is no room for slots +6 and 7 in the object. + +Methods (names in `tools/names.txt`): `GetWeaponSetItem` `0x5d86c0`, +`SetWeaponSetItem` `0x5d86f0`, `SetWeaponSet` `0x5d8930`, +`TakeWeaponSetItem` `0x5d8be0`, `GetWeaponSetItemPos` `0x5d8d00`, +`GetArtSlotType` `0x5d93e0`, `GetArtSlotRef` `0x5d9420`, `SetArtSlot` +`0x5d9480`, `ClearArtSlot` `0x5d9680`, `SelectSlot` `0x5d9820`, +`GetSelectedSlot` `0x5d9b60`, `SetArtVariant` `0x5d9200`; loops over the 5 +weapon sets in `Clear` `0x5d7d30`, `ReplaceItemId` `0x5d80e0`, +`FixInventory` `0x5de8a0` and the load path of `Serialize`. + +Accesses outside the class found so far: none to these offsets (searched +`+0xc18..+0xca0`, `+0xd58/+0xd5a`, `(x+0x102)*0xc`, `(x+0xa1)*0x14`, +`(x*3+0x183)*8`). The compiler also spells addresses in other ways, so the +list is a lower bound until the callers of the accessors are checked. + +### Save format (`cInventoryEntry::Serialize` `0x5dd9f0`) + +`(stream, write)`; stream vf04 read, vf08 write, vf14 position. Raw blocks in +this order, no version field: + +flags +0x1162 (2), +0x1164 (2), +0x1166 (2), width (2), height (2), ++0xd5c (0x400), grid (0xc00), **weapon sets (0x78)**, **art slots (0xc8)**, +**selected (4)**, +0x1168 (4), quest items (count + 8 each), scrolls +(count + 4 each). + +Returns the number of bytes processed. Called from `0x5dbd76`, `0x5df00c`, +`0x5df0e5`, `0x5df391`, `0x5df47e`, `0x604a26`, `0x604a7d`, `0x605cee`. + +### Slot count by level + +`SlotCountForLevel` (`0x57f750`): table at `0x95503c`, (level, count) pairs, +at most 5. Used by the taskbar (`+0x15c`). + +### Taskbar (`cUI_Taskbar2`) + +Slot controls: weapon sets at +0x164 (5), art slots at +0x178 (5), slot count +at +0x15c; selection highlight written into the controls (+0x54..+0x60, ++0x78) from `0x9ed058`. Layout, rendering (`0x6e3ac0`), hit test (`0x6dfb10`) +and drag & drop of the slots: not mapped yet. + +### Network + +Slot changes send network events 299 (`SetWeaponSetItem`), 300 +(`SetWeaponSet`), 0x129 (`SetArtSlot`), 0x12a (`ClearArtSlot`), 0x130 +(`SelectSlot`), 0x123 (`SetArtVariant`) with the slot index. A server or +client running the original only knows 5 slots: slots 6-7 are single player +only (or disabled in multiplayer). + +## Plan + +1. Slots 6-7 in a DLL table per inventory index (2 weapon sets, 2 x 2 art + slot variants); the original object keeps slots 1-5 unchanged. +2. Hook the accessors above: index >= 5 goes to the table. Extend the + 5-slot loops (`Clear`, `ReplaceItemId`, `FixInventory`, load fix-up). +3. Save: after the original blocks, `Serialize` writes an extension block + (magic + version + slots 6-7). Reading checks for the magic; a save + without it (old save) gets empty slots 6-7 = the migration. Open: whether + the stream can peek / seek back, and whether the caller stores the + returned length. +4. Slot count table: 7 entries (unlock levels for slots 6 and 7 to choose). +5. Taskbar: 7 controls each (arrays inside the object are fixed at 5: own + table for the extra controls), layout, rendering, hit tests, drag & drop. +6. Keys: 1-7 select and cast art slots, F1-F7 select weapon sets. diff --git a/tools/names.txt b/tools/names.txt index c3477ae..7a8e701 100644 --- a/tools/names.txt +++ b/tools/names.txt @@ -75,6 +75,31 @@ 0x0075c200 cUI_Manager::DrawMessage 0x00731d40 cUI_Window2::HitTest 0x006dfb10 cUI_Taskbar2::HitTest -0x006e1970 cUI_Taskbar2::HandleEvent # digit keys: belt / skill slots +0x006e1970 cUI_Taskbar2::HandleEvent # digit keys: 1-5 weapon sets, 6-0 combat-art slots +0x006e1440 cUI_Taskbar2::SelectWeaponSet # digits 1-5 +0x006e17d0 cUI_Taskbar2::SelectSkillSlot # digits 6-0: right mouse button combat art 0x006e3ac0 cUI_Taskbar2::Render 0x006e7300 cUI_Tooltip::Render +# cInventoryEntry (32 x 0x1180 in one block, see docs/skill-slots.md) +0x005deb80 cInventoryManager::Instance # allocates 32 inventories (0x23008 bytes) +0x005dec50 cInventoryManager::GetInventory # index * 0x1180 +0x005d7a10 cInventoryEntry::Construct +0x005d7bf0 cInventoryEntry::Destruct +0x005d7d30 cInventoryEntry::Clear # zeroes grid, weapon sets, art slots +0x005d80e0 cInventoryEntry::ReplaceItemId # grid + weapon sets +0x005d86c0 cInventoryEntry::GetWeaponSetItem # (set, hand) +0x005d86f0 cInventoryEntry::SetWeaponSetItem # (set, hand, id, notify) -> network 299 +0x005d8930 cInventoryEntry::SetWeaponSet # (set, left, right, notify) -> network 300 +0x005d8be0 cInventoryEntry::TakeWeaponSetItem +0x005d8d00 cInventoryEntry::GetWeaponSetItemPos +0x005d9200 cInventoryEntry::SetArtVariant # 0x1162 bit 2: second art slot set (mounted?) +0x005d93e0 cInventoryEntry::GetArtSlotType +0x005d9420 cInventoryEntry::GetArtSlotRef +0x005d9480 cInventoryEntry::SetArtSlot # -> network 0x129 +0x005d9680 cInventoryEntry::ClearArtSlot # -> network 0x12a +0x005d9820 cInventoryEntry::SelectSlot # (slot, kind 0 weapons / 1 arts) -> +0xd58 +0x005d9b60 cInventoryEntry::GetSelectedSlot # (kind) +0x005dd9f0 cInventoryEntry::Serialize # (stream, write) +0x005de8a0 cInventoryEntry::FixInventory +0x005da880 cInventoryEntry::GetPotionRef +0x0057f750 SlotCountForLevel # table 0x95503c, max 5