diff --git a/D2Editor.exe b/D2Editor.exe index ada8dc47..bdd7a8b1 100644 Binary files a/D2Editor.exe and b/D2Editor.exe differ diff --git a/d2s_File_Format.md b/d2s_File_Format.md index dd4836d8..d59eb398 100644 --- a/d2s_File_Format.md +++ b/d2s_File_Format.md @@ -15,44 +15,68 @@ is based on. Each .d2s file starts with a 765 byte header, after which data is of variable length. -|Byte | Length | Desc -|-----|--------|------------ -|0 | 4 | Signature (0xaa55aa55) -|4 | 4 | [Version ID](#versions) -|8 | 4 | File size -|12 | 4 | [Checksum](#checksum) -|16 | 4 | [Active Weapon](#active-weapon) -|20 | 16 | [Character Name](#character-name) -|36 | 1 | [Character Status](#character-status) -|37 | 1 | [Character Progression](#Character-progression) -|38 | 2 | ? -|40 | 1 | [Character Class](#character-class) -|41 | 2 | ? -|43 | 1 | [Level](#level) -|44 | 4 | Created [unix timestamp](https://en.wikipedia.org/wiki/Unix_time)? -|48 | 4 | Last Played [unix timestamp](https://en.wikipedia.org/wiki/Unix_time) -|52 | 4 | ? -|56 | 64 | [Assigned Skills](#AssignedSkills) -|120 | 4 | Left Mouse -|124 | 4 | Right Mouse -|128 | 4 | Left Mouse (weapon switch) -|132 | 4 | Right Mouse (weapon switch) -|136 | 32 | [Character Menu Appearance](#character-menu-appearance) -|168 | 3 | [Difficulty](#difficulty) -|171 | 4 | Map ID -|175 | 2 | ? -|177 | 2 | Merc dead? -|179 | 4 | Merc seed? -|183 | 2 | Merc Name ID -|185 | 2 | Merc Type -|187 | 4 | Merc Experience -|191 | 144 | ? -|335 | 298 | [Quest](#quest) -|633 | 80 | [Waypoint](#waypoint) -|713 | 52 | [NPC](#npc) -|765 | | [Attributes](#attributes) -| | 30 | [Skills](#skills) -| | | [Items](#items) +|Byte | Byte | Byte | +|'71' |'87' - '89'|'92' - '96'|Byte | Length | Desc +|-----|-----------|-----------|-----|--------|------------ +| 0 | 0 | 0 | 0 | 4 | Signature (0xaa55aa55) +| 4 | 4 | 4 | 4 | 4 | [Version ID](#versions) +| | | 8 | 8 | 4 | File size +| | | 12 | 12 | 4 | [Checksum](#checksum) +| | | 16 | 16 | 4 | [Active Weapon](#active-weapon) +| 8 | 8 | 20 | 20 | 16 | [Character Name](#character-name) for versions '71' - '97', otherwise 0x00 +| 24 | 24 | 36 | 36 | 1 | [Character Status](#character-status) +| 25 | 25 | 37 | 37 | 1 | [Character Progression](#Character-progression) +| 26 | 26 | | | 1 | [Active Weapon](#active-weapon) for versions '71' - '89' +| 27 | 27 | 38 | 38 | 1 | ? always zero +| 28 | 28 | | | 1 | ? 0x3F for versions '87' - '89', otherwise 0xDD for version '71' +| 29 | 29 | | | 1 | ? 0x00 for versions '87' - '89', otherwise 0x01 for version '71' +| 30 | 30 | | | 1 | ? 0x10 for versions '71' - '89' +| 31 | 31 | | | 1 | ? 0x00 for versions '71' - '89' +| 32 | 32 | | | 1 | ? 0x82 for versions '71' - '89' +| 33 | 33 | 39 | 39 | 1 | ? always zero +| 34 | 34 | 40 | 40 | 1 | [Character Class](#character-class) +| 35 | 35 | 41 | 41 | 1 | ? 0x10 for versions '92"+, otherwise 0x00 for versions '71' - '89' +| | | 42 | 42 | 1 | ? 0x1E for versions '92"+ +| 36 | 36 | 43 | 43 | 1 | [Level](#level) +| 37 | 37 | | | 1 | ? 0x00 for versions '71' - '89' +| | | 44 | 44 | 4 | Created [unix timestamp](https://en.wikipedia.org/wiki/Unix_time)? +| | | 48 | 48 | 4 | Last Played [unix timestamp](https://en.wikipedia.org/wiki/Unix_time) +| | | 52 | 52 | 4 | ? 0xFF all bytes for versions '92"+ +| 38 | 38 | | | 32 | [Character Menu Appearance](#character-menu-appearance) for versions '71' - '89' +| | | 56 | 56 | 64 | [Assigned Skills](#AssignedSkills) for versions '92"+ +| 70 | 70 | | | 16 | [Assigned Skills](#AssignedSkills) for versions '71' - '89' +| 86 | 86 | | | 1 | Left Mouse for versions '71' - '89' +| | |120 |120 | 4 | Left Mouse for versions '92"+ +| 87 | 87 | | | 1 | Right Mouse for versions '71' - '89' +| | |124 |124 | 4 | Right Mouse for versions '92"+ +| | |128 |128 | 4 | Left Mouse (weapon switch) for versions '92"+ +| | |132 |132 | 4 | Right Mouse (weapon switch) for versions '92"+ +| | |136 |136 | 32 | [Character Menu Appearance](#character-menu-appearance) for versions '92"+ +| 88 | 88 | | | 1 | first 4 bits difficulty, last 4 bits starting act for versions '71' - '89' +| 89 | 89 | | | 36 | ? 0x00 for versions '71' - '89' +| | |168 |168 | 3 | [Difficulty](#difficulty) +|126 |126 |171 |171 | 4 | Map ID +| | |175 |175 | 2 | ? 0x00 for versions '92"+ +| | |177 |177 | 2 | Merc dead? for versions '92"+ +| | |179 |179 | 4 | Merc seed? for versions '92"+ +| | |183 |183 | 2 | Merc Name ID for versions '92"+ +| | |185 |185 | 2 | Merc Type for versions '92"+ +| | |187 |187 | 4 | Merc Experience for versions '92"+ +| | |191 | | 140 | ? 0x00 for versions '92' - '96' +| | | |191 | 28 | ? 0x00 for versions '97"+ +| | | |219 | 48 | [D2R Character Menu Appearance](#d2r-character-menu-appearance) for versions '97"+ +| | | |267 | 16 | [Character Name](#character-name) for versions '98'+, otherwise 0x00 for version '97' +| | | |283 | 48 | ? 0x00 for versions '97"+ +| | |331 |331 | 1 | ? 0x00 for versions '97"+, otherwise 0x01 for versions '92' - '96' +| | |332 |332 | 3 | ? 0x00 for versions '92"+ +|130 | | | | 286 | [Quest](#quest) for version '71" +|416 | | | | 12 | ? 0x00 for version '71" +| |130 |335 |335 | 298 | [Quest](#quest) for versions '87"+ +|428 |428 |633 |633 | 80 | [Waypoint](#waypoint) +|508 |508 |713 |713 | 52 | [NPC](#npc) +|560 |560 |765 |765 | | [Attributes](#attributes) +| | | | | 30 | [Skills](#skills) +| | | | | | [Items](#items) ### Versions @@ -63,7 +87,9 @@ File version. The following values are known: * `89` is standard game v1.08 * `92` is v1.09 (both the standard game and the Expansion Set.) * `96` is v1.10 - v1.14d -* `96` is v1.15+ (D2R) +* `97` is v1.15 (D2R 1.0.x - 1.1.x) +* `98` is v1.16 (D2R 1.2.x+) + ### Checksum @@ -242,6 +268,9 @@ Assigned skills section is a an array of 16 skill ids mapped to a hotkey, each a 32 byte structure which defines how the character looks in the menu Does not change in-game look +### D2R Character Menu Appearance +32 byte structure which defines how the character looks in the menu +Does not change in-game look ### Difficulty 3 bytes of data that indicates which of the three difficulties the character has unlocked. @@ -301,7 +330,7 @@ This structure repeats it self 3 times, once for Normal, Nightmare and Hell. The | 70 | `[6]quest` | All six quests for Act V. | | 82 | `1` | Set to 1 if you went to Akara to reset your stats already | | 83 | `1` | Seems to be set to 0x80 after completing the Difficulty Level | -| 84 | `12` | Some kind of padding after all the quest data. | +| 84 | `12` | Some kind of padding after all the quest data. | ### Waypoint @@ -310,7 +339,7 @@ Waypoint data starts with 2 chars "WS" and 6 unknown bytes, always = {0x01, 0x00, 0x00, 0x00, 0x50, 0x00} Three structures are in place for each difficulty, -at offsets 641, 665 and 689. +at offsets 641, 665 and 689. (436, 460 and 484 for versions '71' - '89') The contents of this structure are as follows @@ -417,35 +446,201 @@ After this come N items. Each item starts with a basic 14-byte structure. Many fields in this structure are not "byte-aligned" and are described by their bit position and sizes. -Bit | Size | Desc -----|------|------ -0 | 16 | "JM" (separate from the list header) -16 | 4 | ? -20 | 1 | Identified -21 | 6 | ? -27 | 1 | Socketed -28 | 1 | ? -29 | 1 | Picked up since last save -30 | 2 | ? -32 | 1 | Ear -33 | 1 | Starter Gear -34 | 3 | ? -37 | 1 | Compact -38 | 1 | Ethereal -39 | 1 | ? -40 | 1 | Personalized -41 | 1 | ? -42 | 1 | [Runeword](#runeword) -43 | 15 | ? -58 | 3 | [Parent](#parent) -61 | 4 | [Equipped](#equipped) -65 | 4 | Column -69 | 3 | Row -72 | 1 | ? -73 | 3 | [Stash](#parent) -76 | 4 | ? -80 | 24 | Type code (3 letters) -108 | | [Extended Item Data](#extended-item-data) + Bit | Bit | Bit | Bit | + '71' | '71' | '71' | '71' | Bit | +15 bytes|26 bytes|27 bytes|31 bytes|'87' - '96'|Bit | Size | Desc +--------|--------|--------|--------|-----------|----|------|------ + 0 | 0 | 0 | 0 | 0 | | 16 | "JM" (separate from the list header) + 16 | 16 | 16 | 16 | 16 | 0 | 4 | ? 0x00 + 20 | 20 | 20 | 20 | 20 | 4 | 1 | Identified + 21 | 21 | 21 | 21 | 21 | 5 | 6 | ? 0x00 + 27 | 27 | 27 | 27 | 27 | 11 | 1 | Socketed + 28 | 28 | 28 | 28 | 28 | 12 | 1 | ? 0x00 + 29 | 29 | 29 | 29 | 29 | 13 | 1 | Picked up since last save + 30 | 30 | 30 | 30 | 30 | 14 | 2 | ? 0x00 + | 32 | 32 | | 32 | 16 | 1 | Ear, 0x01 always for version '71' with 26 bytes + 32 | | | 32 | | | 1 | ? 0x00 + 33 | 33 | 33 | 33 | 33 | 17 | 1 | Starter Gear + 34 | 34 | 34 | 34 | 34 | 18 | 1 | ? 0x00 + 35 | 35 | | 35 | | | 2 | ? 0x03 + | | 35 | | 35 | 19 | 2 | ? 0x00 + 37 | 37 | | 37 | 37 | 21 | 1 | Compact, 0x01 always for version '71' with 15 bytes + | | 37 | | | | 1 | ? 0x00 + 38 | 38 | 38 | 38 | 38 | 22 | 1 | Ethereal + 39 | 39 | 39 | 39 | 39 | 23 | 1 | ? 0x01 for versions '87'+, otherwise 0x00 + | | | | 40 | 24 | 1 | Personalized + 40 | 40 | 40 | 40 | | | 1 | ? 0x00 + 41 | 41 | 41 | 41 | 41 | 25 | 1 | ? 0x00 + | | | | 42 | 26 | 1 | [Runeword](#runeword) + 41 | 41 | 41 | 41 | 41 | 25 | 1 | ? 0x00 + 43 | 43 | 43 | 43 | 43 | 27 | 5 | ? 0x00 + + +#### Ear Item: + Bit | Bit | + '71' | '71' | +26 bytes|27 bytes| Size | Desc +--------|--------|------|------ + 48 | 48 | 5 | ? 0x00 + 53 | | 10 | ? 0x00 + | 53 | 10 | 0x13B always, Ear Type code + 63 | 63 | 3 | ? 0x00 + 66 | 66 | 5 | Column + 71 | 71 | 2 | Row + 73 | 73 | 1 | ? 0x00 + 74 | | 3 | [Stash](#parent) + 77 | | 5 | ? 0x00 + 82 | 74 | 3 | Opponent Class + | 77 | 8 | ? 0x00 + | 85 | 3 | [Stash](#parent) + | 88 | 2 | ? 0x00 + 85 |100 | 8 | Opponent Level + 93 |108 |105 | Opponent Name +198 | | 10 | ? 0x00 + |213 | 3 | ? 0x00 + + + Bit | +'87' - '96'|Bit | Size | Desc +-----------|----|------|------ + | 32 | 3 | ? 0x00 + 48 | | 10 | ? 0x00 + 58 | 35 | 3 | [Parent](#parent), always 0x00 + 61 | 38 | 4 | [Equipped](#equipped), always 0x00 + 65 | 42 | 4 | Column + 69 | 46 | 3 | Row + 72 | 49 | 1 | ? 0x00 + 73 | 50 | 3 | [Stash](#parent) + 76 | 53 | 3 | Opponent Class + 79 | 56 | 7 | Opponent Level + | 63 |120 | Opponent Name + 86 | |105 | Opponent Name + |183 | 1 | ? 0x00 +191 | | 7 | ? 0x00 + +#### Simple Item: + Bit | Bit | + '71' | '71' | +15 bytes|27 bytes| Size | Desc +--------|--------|------|------ + 48 | | 18 | ? 0x00 + | 48 | 20 | ? 0x00 + 66 | | 5 | Column, if socketed, 0x00 always, if stored in belt 4 bits used, 2 belt row and 2 for belt column) + | 68 | 10 | Type code, 10 bit integer + 71 | | 3 | Row, if socketed, 3 bits used other wise 2 bits, 0x00 always if stored in belt. + 74 | | 3 | [Stash](#parent) + 77 | | 3 | ? 0x00 + | 78 | 1 | 0x01 socket or belt if potion + | 79 | 42 | ? 0x00 + 80 | | 2 | ? 0x03 + 82 | | 30 | Type code (3 letters) +112 | | 8 | ? 0x00 to pad to 120 bits + |121 | 5 | Column, if socketed, 0x00 always, if stored in belt 4 bits used, 2 belt row and 2 for belt column) + |126 | 3 | Row, if socketed, 3 bits used other wise 2 bits, 0x00 always if stored in belt. + |127 | 76 | ? 0x00 to pad to 120 bits + |203 | 8 | [Parent](#parent), if bits 4-8 are 0, then stored and bits 0-3 are for [Stash](#parent) + |211 | 5 | ? 0x00 to pad to 216 bits + + Bit | +'87' - '96'|Bit | Size | Desc +-----------|---------|------|------ + | 32 | 3 | ? 0x00 + 48 | | 10 | ? 0x00 + 58 | 35 | 3 | [Parent](#parent) + 61 | 38 | 4 | [Equipped](#equipped), always 0x00 + 65 | 42 | 4 | Column + 69 | 46 | 3 | Row + 72 | 49 | 1 | ? 0x00 + 73 | 50 | 3 | [Stash](#parent) + | 53 | 8-30 | Type code (3 letters) + 76 | | 30 | Type code (3 letters) +106 | 61 - 83 |1 or 3| if quest item, then 2 bits for quest and 1 bit for num sockets, otherise 1 bit for sockets + | 62 - 86 | 0-4 | ? 0x00 to pad to 64 or 88 bits +107 or 109 | | 3-5 | ? 0x00 to pad to 112 bits + + +#### Gold Item (unused): + Bit | Bit | + '71' | '71' | +27 bytes|31 bytes| Size | Desc +--------|--------|------|------ + | 48 | 10 | ? 0x00 + | 58 | 30 | Type code (3 letters) + 48 | 90 | 16 | ? 0x00 + 64 | | 4 | ? 0x00 + 68 | | 10 | Type code, 10 bit integer + 78 | | 3 | ? 0x00 + | 106 | 7 | ? 0x00 + 81 | 113 | 4 | ? 0x00 + 85 | 117 | 12 | 12 bit integer holding gold amount + 97 | 129 | 24 | ? 0x00 +121 | 153 | 5 | Column +126 | 158 | 3 | Row +129 | 161 | 72 | ? 0x00 +203 | 235 | 8 | [Parent](#parent), if bits 4-8 are 0, then stored and bits 0-3 are for [Stash](#parent) +211 | 243 | 5 | ? 0x00 to pad to 216/248 bits + + + Bit | +'87' - '96'|Bit | Size | Desc +-----------|---------|------|------ + | 32 | 3 | ? 0x00 + 48 | | 10 | ? 0x00 + 58 | 35 | 3 | [Parent](#parent) + 61 | 38 | 4 | [Equipped](#equipped), always 0x00 + 65 | 42 | 4 | Column + 69 | 46 | 3 | Row + 72 | 49 | 1 | ? 0x00 + 73 | 50 | 3 | [Stash](#parent) + | 53 | 8-30 | Type code (3 letters) + 76 | | 30 | Type code (3 letters) +106 | 61 - 83 |1 or 3| if quest item, then 2 bits for quest and 1 bit for num sockets, otherise 1 bit for sockets + | 62 - 86 | 0-4 | ? 0x00 to pad to 64 or 88 bits +107 or 109 | | 3-5 | ? 0x00 to pad to 112 bits + +#### Extended items: + Bit | Bit | + '71' | '71' | +27 bytes|31 bytes| Size | Desc +--------|--------|------|------ + | 48 | 10 | ? 0x00 + | 58 | 30 | Type code (3 letters) + 48 | 90 | 4 | [Equipped](#equipped) + 52 | 94 | 1 | ? 0x00 + 53 | 95 | 3 | number of socketed items + 56 | 98 | 8 | Item Level + 64 | | 4 | ? 0x00 + 68 | | 10 | Type code, 10 bit integer + 78 | | 3 | ? 0x00 + | 106 | 7 | ? 0x00 + 81 | 113 | 4 | [Quality](#quality) + 85 | 117 | 9 | number items stacked + 94 | 126 | 11 | ? 0x00 +105 | 137 | 16 | Durability +121 | 153 | 5 | Column, if socketed, then 0x00 always, if stored in belt, then 4 bits used, 2 for belt row and 2 for belt column) +126 | 158 | 3 | Row, if socketed, then 3 bits used otherwise 2 bits, 0x00 always if stored in belt. +129 | 161 | 8 | Set ID, Unique ID, or 0x00 if not part of a Set or Unique +139 | 171 | 32 | DWA +171 | 203 | 32 | DWB +203 | 235 | 8 | [Parent](#parent), if bits 4-8 are 0, then stored and bits 0-3 are for [Stash](#parent) +211 | 243 | 5 | ? 0x00 to pad to 216/248 bits + + Bit | +'87' - '96'|Bit | Size | Desc +-----------|---------|------|------ + | 32 | 3 | ? 0x00 + 48 | | 10 | ? 0x00 + 58 | 35 | 3 | [Parent](#parent) + 61 | 38 | 4 | [Equipped](#equipped), always 0x00 + 65 | 42 | 4 | Column + 69 | 46 | 3 | Row + 72 | 49 | 1 | ? 0x00 + 73 | 50 | 3 | [Stash](#parent) + | 53 | 8-30 | Type code (3 letters) + 76 | | 30 | Type code (3 letters) +106 | | 2 | ? 0x00 +108 | 61 - 83 | | [Extended Item Data](#extended-item-data) + ### Extended Item Data @@ -456,7 +651,7 @@ Items with extended information store bits based on information in the item head extra 3-bit integer encoding how many sockets the item has. |Bit | Size | Desc -----|------|------- +|----|------|------- |108 | | [Sockets](#sockets) | | | [Custom Graphics](#custom-graphics) | | | [Class Specific](#class-specific) diff --git a/readme.md b/readme.md index 24603f5c..85fe6f95 100644 --- a/readme.md +++ b/readme.md @@ -1,4 +1,4 @@ -# Diablo II Character Editor +# Diablo II Character Editor Copyright (c) 2000-2003 By Burton Tsang
Copyright (c) 2021-2022 By Walter Couto
@@ -77,7 +77,7 @@ Check the following site for updates at https://github.com/WalterCouto/D2CE
* [d2s Binary File Format](d2s_File_Format.md)
### Revision History -**Version 2.16 (May 20, 2022)** +**Version 2.16 (June 5, 2022)** - Updated: fix up mercenary for PTR 2.4 changes to Barbarian
- Updated: reorganized item context menu
- Updated: fixed "reload" issue with mercenary data that would not read the items.
@@ -87,6 +87,8 @@ Check the following site for updates at https://github.com/WalterCouto/D2CE
- Added: add support for dragging and dropping items.
- Added: add d2i item files and support for import/export of items. The application supports the standard d2i files that exists today but if the item being exported is a D2R PTR 2.4 ear or personalized item that contains utf-8 characters outside the ASCII range, it will export the d2i file as a v1.16 item which is not the same as the format of existing d2i files.
- Added: add ability to socket and unsocket items
+- Added: add ability to convert character file to a different version via the "Change Version" menu item.
+- Added: add ability to apply runewords to item via the "Apply Runeword" context menu item.

**Version 2.15 (April 26, 2022)** diff --git a/source/D2Editor.cpp b/source/D2Editor.cpp index 48aacf10..eee29d32 100644 --- a/source/D2Editor.cpp +++ b/source/D2Editor.cpp @@ -18,7 +18,7 @@ Revision History ================ -Version 2.16 (May 24, 2022) +Version 2.16 (June 5, 2022) - Updated: fix up mercenary for PTR 2.4 changes to Barbarian - Updated: reorganized item context menu - Updated: fixed "reload" issue with mercenary data that would @@ -38,6 +38,8 @@ Version 2.16 (May 24, 2022) - Added: add ability to socket and unsocket items - Added: add ability to convert character file to a different version via the "Change Version" menu item. + - Added: add ability to apply runewords to item via the + "Apply Runeword" context menu item. Version 2.15 (April 26, 2022) - Updated: Reorganize resources and add txt file to allow for diff --git a/source/D2Editor.rc b/source/D2Editor.rc index bd5c9d6b..d8e18a6a 100644 Binary files a/source/D2Editor.rc and b/source/D2Editor.rc differ diff --git a/source/D2Editor.vcxproj b/source/D2Editor.vcxproj index 754c1bb2..1a46d3c6 100644 --- a/source/D2Editor.vcxproj +++ b/source/D2Editor.vcxproj @@ -249,7 +249,9 @@ + + @@ -258,7 +260,7 @@ - + @@ -332,7 +334,9 @@ + + diff --git a/source/D2Editor.vcxproj.filters b/source/D2Editor.vcxproj.filters index 187aed83..73e6c3df 100644 --- a/source/D2Editor.vcxproj.filters +++ b/source/D2Editor.vcxproj.filters @@ -150,7 +150,7 @@ Header Files - + Header Files @@ -291,6 +291,12 @@ Header Files\d2ce\Helpers + + Header Files + + + Header Files + @@ -464,6 +470,12 @@ Source Files\d2ce\Helpers + + Source Files + + + Source Files + diff --git a/source/D2ItemsForm.cpp b/source/D2ItemsForm.cpp index 7548262f..a518d644 100644 --- a/source/D2ItemsForm.cpp +++ b/source/D2ItemsForm.cpp @@ -26,6 +26,7 @@ #include "D2AddGemsForm.h" #include "D2MercenaryForm.h" #include "D2SharedStashForm.h" +#include "D2RunewordForm.h" #include "d2ce/helpers/ItemHelpers.h" #include #include @@ -3470,6 +3471,28 @@ d2ce::ItemFilter CD2ItemsForm::GetCurrItemFilter() const return filter; } //--------------------------------------------------------------------------- +bool CD2ItemsForm::setItemRuneword(d2ce::Item& item, std::uint16_t id) +{ + auto preLocationId = item.getLocation(); + auto preAltPositionId = item.getAltPositionId(); + auto preEquipId = item.getEquippedId(); + if (MainForm.setItemRuneword(item, id)) + { + if (preEquipId != d2ce::EnumEquippedId::NONE) + { + refreshEquipped(preEquipId); + } + else + { + refreshGrid(preLocationId, preAltPositionId); + } + + return true; + } + + return false; +} +//--------------------------------------------------------------------------- const d2ce::Item* CD2ItemsForm::GetInvItem(UINT id, UINT offset) const { // Make sure we have hit an item @@ -4190,11 +4213,6 @@ void CD2ItemsForm::OnContextMenu(CWnd* /*pWnd*/, CPoint point) auto filter(GetCurrItemFilter()); if (CurrItem == nullptr) { - if (filter.LocationId == d2ce::EnumItemLocation::EQUIPPED) - { - return; - } - CMenu menu; VERIFY(menu.LoadMenu(IDR_ITEM_MENU)); @@ -4225,6 +4243,14 @@ void CD2ItemsForm::OnContextMenu(CWnd* /*pWnd*/, CPoint point) } } } + else if (filter.LocationId == d2ce::EnumItemLocation::EQUIPPED) + { + auto pos = FindPopupPosition(*pPopup, ID_ITEM_CONTEXT_GPS_CREATOR); + if (pos >= 0) + { + pPopup->RemoveMenu(pos, MF_BYPOSITION); + } + } pPopup->TrackPopupMenu(TPM_LEFTALIGN | TPM_RIGHTBUTTON, point.x, point.y, this); return; @@ -4839,6 +4865,14 @@ void CD2ItemsForm::OnItemContextRemovePersonalization() //--------------------------------------------------------------------------- void CD2ItemsForm::OnItemContextApplyruneword() { + if (CurrItem == nullptr) + { + return; + } + + CD2RunewordForm dlg(*this); + dlg.DoModal(); + SetFocus(); } //--------------------------------------------------------------------------- void CD2ItemsForm::OnItemContextImportitem() diff --git a/source/D2ItemsForm.h b/source/D2ItemsForm.h index 173870f6..33f47c62 100644 --- a/source/D2ItemsForm.h +++ b/source/D2ItemsForm.h @@ -173,6 +173,7 @@ class CD2ItemsForm : public CDialogEx, public CD2ItemToolTipCtrlCallback, public friend class CD2GemsForm; friend class CD2AddGemsForm; friend class CD2SharedStashForm; + friend class CD2RunewordForm; DECLARE_DYNAMIC(CD2ItemsForm) public: @@ -351,6 +352,8 @@ class CD2ItemsForm : public CDialogEx, public CD2ItemToolTipCtrlCallback, public d2ce::ItemFilter GetCurrItemFilter() const; + bool setItemRuneword(d2ce::Item& item, std::uint16_t id); + // Inherited via CD2ItemToolTipCtrlCallback const d2ce::Item* GetInvItem(UINT id, UINT offset) const override; const d2ce::Item* InvHitTest(UINT id, CPoint point, TOOLINFO* pTI = nullptr) const override; diff --git a/source/D2LevelInfoForm.cpp b/source/D2LevelInfoForm.cpp index 9086ec34..1d8a88df 100644 --- a/source/D2LevelInfoForm.cpp +++ b/source/D2LevelInfoForm.cpp @@ -93,7 +93,7 @@ CD2LevelInfoForm::~CD2LevelInfoForm() //--------------------------------------------------------------------------- void CD2LevelInfoForm::DoDataExchange(CDataExchange* pDX) { - CDialogEx::DoDataExchange(pDX); + __super::DoDataExchange(pDX); DDX_Control(pDX, IDC_LEVELINFO_GRID, LevelInfoGrid); } //--------------------------------------------------------------------------- diff --git a/source/D2MainForm.cpp b/source/D2MainForm.cpp index 5646a321..7beb8892 100644 --- a/source/D2MainForm.cpp +++ b/source/D2MainForm.cpp @@ -5670,6 +5670,18 @@ bool CD2MainForm::setItemLocation(d2ce::Item& item, d2ce::EnumEquippedId equippe return false; } //--------------------------------------------------------------------------- +bool CD2MainForm::setItemRuneword(d2ce::Item& item, std::uint16_t id) +{ + if (CharInfo.setItemRuneword(item, id)) + { + ItemsChanged = true; + StatsChanged(); + return true; + } + + return false; +} +//--------------------------------------------------------------------------- size_t CD2MainForm::getNumberOfEquippedItems() const { return CharInfo.getNumberOfEquippedItems(); diff --git a/source/D2MainForm.h b/source/D2MainForm.h index 23384993..c024ba0b 100644 --- a/source/D2MainForm.h +++ b/source/D2MainForm.h @@ -21,7 +21,7 @@ #pragma once #include "d2ce/Character.h" -#include "MainFormConstants.h" +#include "D2MainFormConstants.h" #include "resource.h" #include #include @@ -439,6 +439,8 @@ class CD2MainForm : public CDialogEx bool setItemLocation(d2ce::Item& item, d2ce::EnumAltItemLocation altPositionId, std::uint16_t positionX, std::uint16_t positionY, d2ce::EnumItemInventory invType, const d2ce::Item*& pRemovedItem); bool setItemLocation(d2ce::Item& item, d2ce::EnumEquippedId equippedId, d2ce::EnumItemInventory invType, const d2ce::Item*& pRemovedItem); + bool setItemRuneword(d2ce::Item& item, std::uint16_t id); + size_t getNumberOfEquippedItems() const; const std::vector>& getEquippedItems() const; diff --git a/source/MainFormConstants.h b/source/D2MainFormConstants.h similarity index 97% rename from source/MainFormConstants.h rename to source/D2MainFormConstants.h index 927dab2a..56636c60 100644 --- a/source/MainFormConstants.h +++ b/source/D2MainFormConstants.h @@ -1,35 +1,35 @@ -/* - Diablo II Character Editor - Copyright (C) 2021-2022 Walter Couto - - This program is free software: you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation, either version 3 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program. If not, see . -*/ -//--------------------------------------------------------------------------- - -#pragma once - -#include "d2ce/Constants.h" -#include "d2ce/ExperienceConstants.h" -#include "d2ce/CharacterStatsConstants.h" - -constexpr COLORREF EDITED_COLOUR = 0x00FFFF00; -const COLORREF NORMAL_COLOUR = GetSysColor(COLOR_WINDOW); - -constexpr std::uint32_t NORMAL = static_cast>(d2ce::EnumDifficulty::Normal); -constexpr std::uint32_t NIGHTMARE = static_cast>(d2ce::EnumDifficulty::Nightmare); -constexpr std::uint32_t HELL = static_cast>(d2ce::EnumDifficulty::Hell); - -static const CString SettingsSection("Settings"); -static const CString BackupCharacterOption("Backup Character"); -//--------------------------------------------------------------------------- +/* + Diablo II Character Editor + Copyright (C) 2021-2022 Walter Couto + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . +*/ +//--------------------------------------------------------------------------- + +#pragma once + +#include "d2ce/Constants.h" +#include "d2ce/ExperienceConstants.h" +#include "d2ce/CharacterStatsConstants.h" + +constexpr COLORREF EDITED_COLOUR = 0x00FFFF00; +const COLORREF NORMAL_COLOUR = GetSysColor(COLOR_WINDOW); + +constexpr std::uint32_t NORMAL = static_cast>(d2ce::EnumDifficulty::Normal); +constexpr std::uint32_t NIGHTMARE = static_cast>(d2ce::EnumDifficulty::Nightmare); +constexpr std::uint32_t HELL = static_cast>(d2ce::EnumDifficulty::Hell); + +static const CString SettingsSection("Settings"); +static const CString BackupCharacterOption("Backup Character"); +//--------------------------------------------------------------------------- diff --git a/source/D2MultiLineListCtrl.cpp b/source/D2MultiLineListCtrl.cpp new file mode 100644 index 00000000..9132b083 --- /dev/null +++ b/source/D2MultiLineListCtrl.cpp @@ -0,0 +1,1007 @@ +/* + Diablo II Character Editor + Copyright (C) 2022 Walter Couto + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . +*/ +//--------------------------------------------------------------------------- + +#include "pch.h" +#include "D2MultiLineListCtrl.h" + +// CD2MultiLineListCtrl + +IMPLEMENT_DYNAMIC(CD2MultiLineListCtrl, CListCtrl) + +//--------------------------------------------------------------------------- +CD2MultiLineListCtrl::CD2MultiLineListCtrl() +{ +} +//--------------------------------------------------------------------------- +CD2MultiLineListCtrl::~CD2MultiLineListCtrl() +{ +} + +BEGIN_MESSAGE_MAP(CD2MultiLineListCtrl, CListCtrl) + ON_NOTIFY_REFLECT(LVN_ITEMCHANGED, &CD2MultiLineListCtrl::OnLvnItemchanged) + ON_NOTIFY_REFLECT(NM_CUSTOMDRAW, &CD2MultiLineListCtrl::OnCustomDraw) + ON_WM_KILLFOCUS() + ON_WM_SETFOCUS() +END_MESSAGE_MAP() + +//--------------------------------------------------------------------------- +DWORD CD2MultiLineListCtrl::SetExtendedStyle(DWORD dwNewStyle) +{ + if (dwNewStyle & LVS_EX_GRIDLINES) + { + m_bDrawGrid = TRUE; + dwNewStyle &= ~LVS_EX_GRIDLINES; + } + else + { + m_bDrawGrid = FALSE; + } + + return __super::SetExtendedStyle(dwNewStyle);; +} +//--------------------------------------------------------------------------- +DWORD CD2MultiLineListCtrl::GetExtendedStyle() const +{ + auto flags = __super::GetExtendedStyle(); + if (m_bDrawGrid) + { + flags |= LVS_EX_GRIDLINES; + } + else + { + flags &= ~LVS_EX_GRIDLINES; + } + + return flags; +} +//--------------------------------------------------------------------------- +BOOL CD2MultiLineListCtrl::GetItem(LVITEM* pItem) const +{ + if (pItem == nullptr) + { + return FALSE; + } + + auto nItem = pItem->iItem; + if (nItem >= 0 && nItem < (int)m_rowData.size()) + { + LVITEM lvItem = *pItem; + const auto& rowData = m_rowData[nItem]; + lvItem.iItem = (int)rowData.startRow; + auto numRows = rowData.numRows; + if (!__super::GetItem(&lvItem)) + { + return FALSE; + } + + *pItem = lvItem; + pItem->iItem = nItem; + if (((pItem->mask & LVIF_TEXT) != 0) && (pItem->pszText != LPSTR_TEXTCALLBACK)) + { + if (numRows > 1) + { + const auto& colData = rowData.colData[pItem->iSubItem]; + _tcsncpy_s(pItem->pszText, pItem->cchTextMax, colData.text.GetString(), colData.text.GetLength()); + } + } + + if ((pItem->mask & LVIF_PARAM) != 0) + { + pItem->lParam = LPARAM(rowData.dwData); + } + return TRUE; + } + + return __super::GetItem(pItem); +} +//--------------------------------------------------------------------------- +BOOL CD2MultiLineListCtrl::SetItem(const LVITEM* pItem) +{ + if (pItem == nullptr) + { + return FALSE; + } + + auto nItem = pItem->iItem; + if (nItem < 0 || nItem >= (int)m_rowData.size()) + { + return FALSE; + } + + if ((pItem->mask & LVIF_PARAM) != 0) + { + m_rowData[nItem].dwData = pItem->lParam; + } + + if (((pItem->mask & LVIF_TEXT) != 0) && (pItem->pszText != LPSTR_TEXTCALLBACK)) + { + SetItemText(nItem, pItem->iSubItem, pItem->pszText); + } + return TRUE; +} +//--------------------------------------------------------------------------- +BOOL CD2MultiLineListCtrl::SetItem(int nItem, int nSubItem, UINT nMask, LPCTSTR lpszItem, int /*nImage*/, UINT /*nState*/, UINT /*nStateMask*/, LPARAM lParam) +{ + if (nItem < 0 || nItem >= (int)m_rowData.size()) + { + return FALSE; + } + + if ((nMask & LVIF_PARAM) != 0) + { + m_rowData[nItem].dwData = lParam; + } + + if (((nMask & LVIF_TEXT) != 0) && (lpszItem != LPSTR_TEXTCALLBACK)) + { + SetItemText(nItem, nSubItem, lpszItem); + } + + return TRUE; +} +//--------------------------------------------------------------------------- +BOOL CD2MultiLineListCtrl::SetItem(int nItem, int nSubItem, UINT nMask, LPCTSTR lpszItem, int /*nImage*/, UINT /*nState*/, UINT /*nStateMask*/, LPARAM lParam, int /*nIndent*/) +{ + if (nItem < 0 || nItem >= (int)m_rowData.size()) + { + return FALSE; + } + + if ((nMask & LVIF_PARAM) != 0) + { + m_rowData[nItem].dwData = lParam; + } + + if (((nMask & LVIF_TEXT) != 0) && (lpszItem != LPSTR_TEXTCALLBACK)) + { + SetItemText(nItem, nSubItem, lpszItem); + } + + return TRUE; +} +//--------------------------------------------------------------------------- +void CD2MultiLineListCtrl::ShowGridLines(BOOL bShow) +{ + DWORD flags = GetExtendedStyle(); + if (bShow) + { + flags |= LVS_EX_GRIDLINES; + } + else + { + flags &= ~LVS_EX_GRIDLINES; + } + SetExtendedStyle(flags); +} +//--------------------------------------------------------------------------- +int CD2MultiLineListCtrl::GetItemCount() const +{ + return (int)m_rowData.size(); +} +//--------------------------------------------------------------------------- +POSITION CD2MultiLineListCtrl::GetFirstSelectedItemPosition() const +{ + return __super::GetFirstSelectedItemPosition(); +} +//--------------------------------------------------------------------------- +int CD2MultiLineListCtrl::GetNextSelectedItem(POSITION& pos) const +{ + int nItem = __super::GetNextSelectedItem(pos); + auto rowPos = int(__super::GetItemData(nItem)); + if (rowPos < 0) + { + // only the top row is allowed to be selected + rowPos = (int)__super::GetItemData(nItem + rowPos); + } + + return rowPos; +} +//--------------------------------------------------------------------------- +BOOL CD2MultiLineListCtrl::GetItemRect(int nItem, LPRECT lpRect, UINT nCode) const +{ + if (nItem < 0 || nItem >= (int)m_rowData.size() || lpRect == nullptr) + { + return FALSE; + } + + auto& rowData = m_rowData[nItem]; + auto numRows = int(rowData.numRows); + nItem = int(rowData.startRow); + + CRect bounds; + __super::GetItemRect(nItem, lpRect, nCode); + if (numRows > 1) + { + __super::GetItemRect(nItem + (numRows - 1), &bounds, nCode); + lpRect->bottom = bounds.bottom; + } + + return TRUE; +} +//--------------------------------------------------------------------------- +BOOL CD2MultiLineListCtrl::InvalidateItemRect(int nItem, BOOL bErase) +{ + CRect bounds; + if (!GetItemRect(nItem, &bounds, LVIR_BOUNDS)) + { + return FALSE; + } + + InvalidateRect(&bounds, bErase); + return true; +} +//--------------------------------------------------------------------------- +void CD2MultiLineListCtrl::OnLvnItemchanged(NMHDR* pNMHDR, LRESULT* pResult) +{ + NM_LISTVIEW* pNMListView = reinterpret_cast(pNMHDR); + + *pResult = 0; + + // forget messages that don't change the state + if (pNMListView->uOldState == pNMListView->uNewState) + { + return; + } + + if ((pNMListView->uNewState ^ pNMListView->uOldState) & LVIS_SELECTED) + { + // selection state changing + auto rowPos = int(__super::GetItemData(pNMListView->iItem)); + if (rowPos < 0) + { + // should not happen as only top guy should be selected + rowPos = int(__super::GetItemData(pNMListView->iItem + rowPos)); + } + + InvalidateItemRect(rowPos, FALSE); + return; + } +} +//--------------------------------------------------------------------------- +void CD2MultiLineListCtrl::OnCustomDraw(NMHDR* pNMHDR, LRESULT* pResult) +{ + *pResult = CDRF_DODEFAULT; + LPNMLVCUSTOMDRAW lplvcd = (LPNMLVCUSTOMDRAW)pNMHDR; + + int nItem = int(lplvcd->nmcd.dwItemSpec); + int nSubItem = lplvcd->iSubItem; + int nRowPos = (int)__super::GetItemData(nItem); + int nFirstItemRow = nRowPos; + int nLastItemRow = nRowPos; + size_t nNumLines = 1; + int nCurrentSelection = -1; + BOOL isSelected = FALSE; + POSITION posSelection; + HDC hdc = lplvcd->nmcd.hdc; + CString str; + CRect boxRect, bounds, rect; + CDC* pDC = CDC::FromHandle(hdc); + //BOOL wndFocused = (GetFocus() == this); + + switch (lplvcd->nmcd.dwDrawStage) + { + case CDDS_PREPAINT: + *pResult = CDRF_NOTIFYITEMDRAW; + return; + + case CDDS_ITEMPREPAINT: + if (lplvcd->nmcd.uItemState & CDIS_FOCUS) + { + lplvcd->nmcd.uItemState &= ~CDIS_FOCUS; + } + *pResult = CDRF_NOTIFYSUBITEMDRAW | CDRF_NOTIFYPOSTPAINT; + return; + + case CDDS_ITEMPREERASE: + *pResult = CDRF_NOTIFYSUBITEMDRAW; + return; + + case CDDS_ITEMPOSTPAINT: + *pResult = CDRF_SKIPDEFAULT; + return; + + case CDDS_SUBITEM | CDDS_PREPAINT | CDDS_ITEM: + if (nRowPos < 0) + { + const auto& rowData = m_rowData[__super::GetItemData(nItem + nRowPos)]; + nFirstItemRow = int(rowData.startRow); + nNumLines = rowData.numRows; + nLastItemRow = int(nFirstItemRow + nNumLines - 1); + } + else + { + const auto& rowData = m_rowData[nRowPos]; + nFirstItemRow = int(rowData.startRow); + nNumLines = rowData.numRows; + nLastItemRow = int(nFirstItemRow + nNumLines - 1); + } + + // Get background box + boxRect = lplvcd->nmcd.rc; + __super::GetItemRect(int(lplvcd->nmcd.dwItemSpec), &bounds, LVIR_BOUNDS); + boxRect.top = bounds.top; + boxRect.bottom = bounds.bottom; + if (nSubItem == 0) + { + CRect lrect; + __super::GetItemRect(int(lplvcd->nmcd.dwItemSpec), &lrect, LVIR_LABEL); + boxRect.left = lrect.left; + boxRect.right = lrect.right; + } + else + { + boxRect.right += bounds.left; + boxRect.left += bounds.left; + } + + // Get selection + posSelection = __super::GetFirstSelectedItemPosition(); + if (posSelection) + { + nCurrentSelection = __super::GetNextSelectedItem(posSelection); + if ((nCurrentSelection >= nFirstItemRow) && (nCurrentSelection <= nLastItemRow)) + { + isSelected = true; + } + } + else + { + nCurrentSelection = -1; + } + + if (isSelected) + { + lplvcd->clrTextBk = ::GetSysColor(COLOR_HIGHLIGHT); + lplvcd->clrText = ::GetSysColor(COLOR_HIGHLIGHTTEXT); + } + else + { + lplvcd->clrTextBk = ::GetSysColor(COLOR_WINDOW); + lplvcd->clrText = ::GetSysColor(COLOR_WINDOWTEXT); + } + + // Get text string + str = __super::GetItemText(nItem, nSubItem); + + // Get text box + rect = boxRect; + rect.left += nSubItem ? 6 : 2; + + // Fill background box + { + CBrush brush(lplvcd->clrTextBk); + pDC->FillRect(boxRect, &brush); + } + + // Draw text + { + auto oldTextColor = pDC->SetTextColor(lplvcd->clrText); + pDC->DrawText(str, rect, DT_SINGLELINE | DT_NOPREFIX | DT_LEFT | DT_VCENTER | DT_END_ELLIPSIS); + pDC->SetTextColor(oldTextColor); + } + + if (m_bDrawGrid) + { + // Draw grid + CPen gridline(PS_SOLID, 1, ::GetSysColor(COLOR_BTNFACE)); + pDC->SelectObject(gridline); + if (nSubItem > 0) + { + pDC->MoveTo(boxRect.left, boxRect.top); + pDC->LineTo(boxRect.left, boxRect.bottom); + } + + if (nItem == nLastItemRow) + { + pDC->MoveTo(boxRect.left, boxRect.bottom - 1); + pDC->LineTo(boxRect.right, boxRect.bottom - 1); + } + } + *pResult = CDRF_SKIPDEFAULT; + return; + } +} +//--------------------------------------------------------------------------- +int CD2MultiLineListCtrl::InsertItem(const LVITEM* pItem) +{ + if (pItem == nullptr) + { + return -1; + } + + size_t colCount = 1; + CHeaderCtrl* pHeader = GetHeaderCtrl(); + if (pHeader != nullptr) + { + auto headerCount = pHeader->GetItemCount(); + if (headerCount > 0) + { + colCount = size_t(headerCount); + } + } + + int result = -1; + if (pItem->iItem >= 0 && pItem->iItem < (int)m_rowData.size()) + { + auto row = int(m_rowData[pItem->iItem].startRow); + LVITEM newItem = *pItem; + newItem.iItem = row; + result = __super::InsertItem(&newItem); + if (result == -1) + { + return result; + } + __super::SetItemData(result, pItem->iItem); + + auto iter = m_rowData.begin(); + std::advance(iter, pItem->iItem); + RowData rowData; + rowData.startRow = result; + rowData.colData.resize(colCount); + rowData.colData[0].text = pItem->pszText; + m_rowData.insert(iter, rowData); + + // adjust row offsets + for (size_t i = size_t(pItem->iItem + 1); i < m_rowData.size(); ++i) + { + ++m_rowData[i].startRow; + __super::SetItemData(int(m_rowData[i].startRow), i); + } + } + else + { + LVITEM lvItem = *pItem; + lvItem.iItem = __super::GetItemCount(); + result = __super::InsertItem(&lvItem); + if (result == -1) + { + return result; + } + __super::SetItemData(result, m_rowData.size()); + + RowData rowData; + rowData.startRow = result; + rowData.colData.resize(colCount); + rowData.colData[0].text = pItem->pszText; + m_rowData.push_back(rowData); + } + + SetMultilineText(pItem->iItem, pItem->pszText); + return result; +} +//--------------------------------------------------------------------------- +int CD2MultiLineListCtrl::InsertItem(int nItem, LPCTSTR lpszItem) +{ + size_t colCount = 1; + CHeaderCtrl* pHeader = GetHeaderCtrl(); + if (pHeader != nullptr) + { + auto headerCount = pHeader->GetItemCount(); + if (headerCount > 0) + { + colCount = size_t(headerCount); + } + } + + int result = -1; + if (nItem >= 0 && nItem < (int)m_rowData.size()) + { + auto row = int(m_rowData[nItem].startRow); + result = __super::InsertItem(row, lpszItem); + if (result == -1) + { + return result; + } + __super::SetItemData(result, nItem); + + auto iter = m_rowData.begin(); + std::advance(iter, nItem); + RowData rowData; + rowData.startRow = result; + rowData.colData.resize(colCount); + rowData.colData[0].text = lpszItem; + m_rowData.insert(iter, rowData); + + // adjust row offsets + for (size_t i = size_t(nItem + 1); i < m_rowData.size(); ++i) + { + ++m_rowData[i].startRow; + __super::SetItemData(int(m_rowData[i].startRow), i); + } + } + else + { + result = __super::InsertItem(nItem, lpszItem); + if (result == -1) + { + return result; + } + __super::SetItemData(result, m_rowData.size()); + + RowData rowData; + rowData.startRow = result; + rowData.colData.resize(colCount); + rowData.colData[0].text = lpszItem; + m_rowData.push_back(rowData); + } + + SetMultilineText(nItem, lpszItem); + return result; +} +//--------------------------------------------------------------------------- +int CD2MultiLineListCtrl::InsertItem(int nItem, LPCTSTR lpszItem, int nImage) +{ + size_t colCount = 1; + CHeaderCtrl* pHeader = GetHeaderCtrl(); + if (pHeader != nullptr) + { + auto headerCount = pHeader->GetItemCount(); + if (headerCount > 0) + { + colCount = size_t(headerCount); + } + } + + int result = -1; + if (nItem >= 0 && nItem < (int)m_rowData.size()) + { + auto row = int(m_rowData[nItem].startRow); + result = __super::InsertItem(row, lpszItem, nImage); + if (result == -1) + { + return result; + } + __super::SetItemData(result, nItem); + + auto iter = m_rowData.begin(); + std::advance(iter, nItem); + RowData rowData; + rowData.startRow = result; + rowData.colData.resize(colCount); + rowData.colData[0].text = lpszItem; + m_rowData.insert(iter, rowData); + + // adjust row offsets + for (size_t i = size_t(nItem + 1); i < m_rowData.size(); ++i) + { + ++m_rowData[i].startRow; + __super::SetItemData(int(m_rowData[i].startRow), i); + } + } + else + { + result = __super::InsertItem(nItem, lpszItem, nImage); + if (result == -1) + { + return result; + } + __super::SetItemData(result, m_rowData.size()); + + RowData rowData; + rowData.startRow = result; + rowData.colData.resize(colCount); + rowData.colData[0].text = lpszItem; + m_rowData.push_back(rowData); + } + + SetMultilineText(nItem, lpszItem); + return result; +} +//--------------------------------------------------------------------------- +BOOL CD2MultiLineListCtrl::DeleteItem(int nItem) +{ + if (nItem >= 0 && nItem < (int)m_rowData.size()) + { + auto rowStart = int(m_rowData[nItem].startRow); + auto numRows = m_rowData[nItem].numRows; + auto iter = m_rowData.begin(); + std::advance(iter, nItem); + m_rowData.erase(iter); + + // adjust row offsets + for (size_t i = size_t(nItem); i < m_rowData.size(); ++i) + { + --m_rowData[i].startRow; + __super::SetItemData(int(m_rowData[i].startRow), i); + } + + for (size_t i = 0; i < numRows; ++i) + { + if (!__super::DeleteItem(rowStart)) + { + return FALSE; + } + } + + return TRUE; + } + + return __super::DeleteItem(nItem); +} +//--------------------------------------------------------------------------- +BOOL CD2MultiLineListCtrl::DeleteAllItems() +{ + m_rowData.clear(); + return __super::DeleteAllItems(); +} +//--------------------------------------------------------------------------- +int CD2MultiLineListCtrl::GetTopIndex() const +{ + auto idx = __super::GetTopIndex(); + if (idx < 0) + { + return idx; + } + + + return 0; +} +//--------------------------------------------------------------------------- +CString CD2MultiLineListCtrl::GetItemText(int nItem, int nSubItem) const +{ + if (nSubItem < 0 || nItem < 0 || nItem >= (int)m_rowData.size()) + { + return FALSE; + } + + auto& rowData = m_rowData[nItem]; + if (rowData.colData.size() <= size_t(nSubItem)) + { + return FALSE; + } + + return rowData.colData[nSubItem].text; +} +//--------------------------------------------------------------------------- +int CD2MultiLineListCtrl::GetItemText(int nItem, int nSubItem, LPTSTR lpszText, int nLen) const +{ + if (nSubItem < 0 || nItem < 0 || nItem >= (int)m_rowData.size() || nLen <= 0) + { + return 0; + } + + auto& rowData = m_rowData[nItem]; + if (rowData.colData.size() <= size_t(nSubItem)) + { + return 0; + } + + auto maxSize = min(rowData.colData[nSubItem].text.GetLength(), nLen); + _tcsncpy_s(lpszText, nLen, rowData.colData[nSubItem].text.GetString(), rowData.colData[nSubItem].text.GetLength()); + return maxSize; +} +//--------------------------------------------------------------------------- +BOOL CD2MultiLineListCtrl::SetItemText(int nItem, int nSubItem, LPCTSTR lpszText) +{ + if (nSubItem < 0 || nItem < 0 || nItem >= (int)m_rowData.size()) + { + return FALSE; + } + + return SetMultilineText(nItem, lpszText, nSubItem); +} +//--------------------------------------------------------------------------- +BOOL CD2MultiLineListCtrl::SetItemData(int nItem, DWORD_PTR dwData) +{ + if (nItem < 0 || nItem >= (int)m_rowData.size()) + { + return FALSE; + } + + m_rowData[nItem].dwData = dwData; + return TRUE; +} +//--------------------------------------------------------------------------- +DWORD_PTR CD2MultiLineListCtrl::GetItemData(int nItem) const +{ + if (nItem < 0 || nItem >= (int)m_rowData.size()) + { + return 0; + } + + return m_rowData[nItem].dwData; +} +//--------------------------------------------------------------------------- +BOOL CD2MultiLineListCtrl::EnsureVisible(int nItem, BOOL bPartialOK) +{ + if (nItem < 0 || nItem >= (int)m_rowData.size()) + { + return FALSE; + } + + auto& rowData = m_rowData[nItem]; + if (bPartialOK || rowData.numRows <= 1) + { + return __super::EnsureVisible(int(rowData.startRow), bPartialOK); + } + + __super::EnsureVisible(int(rowData.startRow + rowData.numRows - 1), bPartialOK); + return __super::EnsureVisible(int(rowData.startRow), bPartialOK); +} +//--------------------------------------------------------------------------- +BOOL CD2MultiLineListCtrl::RedrawItems(int nFirst, int nLast) +{ + if (m_rowData.empty() || (nFirst > nLast)) + { + return FALSE; + } + + if (nFirst < 0) + { + nFirst = 0; + } + + if (nLast >= (int)m_rowData.size()) + { + nLast = int(m_rowData.size() - 1); + } + + auto& rowDataFirst = m_rowData[nFirst]; + auto& rowDataLast = m_rowData[nLast]; + nFirst = int(rowDataFirst.startRow); + nLast = int(rowDataLast.startRow + rowDataLast.numRows - 1); + return __super::RedrawItems(nFirst, nLast); +} +//--------------------------------------------------------------------------- +BOOL CD2MultiLineListCtrl::Update(int nItem) +{ + if (nItem < 0 || nItem >= (int)m_rowData.size()) + { + return FALSE; + } + + auto& rowData = m_rowData[nItem]; + nItem = int(rowData.startRow); + int nLastItem = int(nItem + (rowData.numRows - 1)); + BOOL bRet = TRUE; + for (auto i = nItem; i <= nLastItem; ++i) + { + if (!__super::Update(nItem)) + { + bRet = false; + } + } + + return bRet; +} +//--------------------------------------------------------------------------- +void CD2MultiLineListCtrl::AdjustColumnWidths() +{ + SetRedraw(FALSE); + CHeaderCtrl* pHeaderCtrl = GetHeaderCtrl(); + int nColumnCount = pHeaderCtrl->GetItemCount(); + for (int i = 0; i < nColumnCount; i++) + { + SetColumnWidth(i, LVSCW_AUTOSIZE); + int nColumnWidth = GetColumnWidth(i); + SetColumnWidth(i, LVSCW_AUTOSIZE_USEHEADER); + int nHeaderWidth = GetColumnWidth(i); + SetColumnWidth(i, max(nColumnWidth, nHeaderWidth)); + } + SetRedraw(TRUE); +} +//--------------------------------------------------------------------------- +BOOL CD2MultiLineListCtrl::SetMultilineText(int nItem, LPCTSTR lpszText, int nSubItem) +{ + if (nItem < 0 || nItem >= (int)m_rowData.size()) + { + return FALSE; + } + + BOOL bInsert = (nSubItem < 0) ? true : false; + + size_t colCount = 1; + CHeaderCtrl* pHeader = GetHeaderCtrl(); + if (pHeader != nullptr) + { + auto headerCount = pHeader->GetItemCount(); + if (headerCount > 0) + { + colCount = size_t(headerCount); + } + } + + if (nSubItem >= (int)colCount) + { + return FALSE; + } + + auto& rowData = m_rowData[nItem]; + auto& colData = rowData.colData[bInsert ? 0 : nSubItem]; + colData.text = lpszText; + + CString str(lpszText); + str.Replace(_T("\r\n"), _T("\n")); + str.Replace(_T("\r"), _T("\n")); + + CString s; + int pos = -1; + std::vector strings; + while (!str.IsEmpty()) + { + pos = str.Find('\n'); + if (pos == -1) + { + s = str; + str.Empty(); + } + else + { + s = str.Left(pos); + str = str.Right(str.GetLength() - pos - 1); + } + strings.push_back(s); + } + + auto row = int(rowData.startRow); + auto existingNumLines = rowData.numRows; + auto existingNumColLines = colData.numRows; + if (strings.empty()) + { + colData.numRows = 1; + size_t numRows = 0; + for (const auto& col : rowData.colData) + { + numRows = max(numRows, col.numRows); + } + rowData.numRows = numRows; + + if (!__super::SetItemText(row, nSubItem, _T(""))) + { + return FALSE; + } + + // make sure the other lines are blank + for (size_t i = 1; i < existingNumColLines; ++i) + { + __super::SetItemText(int(row + i), nSubItem, _T("")); + } + + for (auto i = rowData.numRows; i < existingNumLines; ++i) + { + __super::DeleteItem(int(row + rowData.numRows)); + + // adjust row offsets + for (size_t j = row + 1; j < m_rowData.size(); ++j) + { + --m_rowData[j].startRow; + } + } + return TRUE; + } + + size_t numLines = strings.size(); + colData.numRows = numLines; + size_t line = 1; + int newRowNum = row; + for (const auto& lineStr : strings) + { + if (line > existingNumLines) + { + if (bInsert || (nSubItem == 0)) + { + auto idx = __super::InsertItem(newRowNum, lineStr); + if (idx == -1) + { + return FALSE; + } + } + else + { + auto idx = __super::InsertItem(newRowNum, _T("")); + if (idx == -1) + { + return FALSE; + } + + if (!__super::SetItemText(newRowNum, nSubItem, lineStr)) + { + return FALSE; + } + } + __super::SetItemData(newRowNum, -std::int64_t(line - 1)); + + // adjust row offsets + for (size_t i = row + 1; i < m_rowData.size(); ++i) + { + ++m_rowData[i].startRow; + } + ++rowData.numRows; + } + else if (bInsert) + { + if (__super::SetItemText(newRowNum, 0, lineStr) == -1) + { + return FALSE; + } + } + else + { + if (__super::SetItemText(newRowNum, nSubItem, lineStr) == -1) + { + return FALSE; + } + } + + ++line; + ++newRowNum; + } + + // make sure the other lines are blank + for (auto i = line; i < existingNumColLines; ++i) + { + __super::SetItemText(int(row + i), nSubItem, _T("")); + } + + size_t numRows = 0; + for (const auto& col : rowData.colData) + { + numRows = max(numRows, col.numRows); + } + rowData.numRows = numRows; + + for (auto i = rowData.numRows; i < existingNumLines; ++i) + { + __super::DeleteItem(int(row + rowData.numRows)); + + // adjust row offsets + for (size_t j = row + 1; j < m_rowData.size(); ++j) + { + --m_rowData[j].startRow; + } + } + return TRUE; +} +//--------------------------------------------------------------------------- +void CD2MultiLineListCtrl::OnKillFocus(CWnd* pNewWnd) +{ + __super::OnKillFocus(pNewWnd); + + auto posSelection = GetFirstSelectedItemPosition(); + if (posSelection) + { + CRect clean; + CRect bounds; + auto rowPos = GetNextSelectedItem(posSelection); + if (rowPos >= 0) + { + // make sure to invalidate all rows + InvalidateItemRect(rowPos, FALSE); + } + } +} +//--------------------------------------------------------------------------- +void CD2MultiLineListCtrl::OnSetFocus(CWnd* pOldWnd) +{ + CListCtrl::OnSetFocus(pOldWnd); + + auto posSelection = GetFirstSelectedItemPosition(); + if (posSelection) + { + CRect clean; + CRect bounds; + auto rowPos = GetNextSelectedItem(posSelection); + if (rowPos >= 0) + { + // make sure to invalidate all rows + InvalidateItemRect(rowPos, FALSE); + } + } +} +//--------------------------------------------------------------------------- diff --git a/source/D2MultiLineListCtrl.h b/source/D2MultiLineListCtrl.h new file mode 100644 index 00000000..9b72093b --- /dev/null +++ b/source/D2MultiLineListCtrl.h @@ -0,0 +1,128 @@ +/* + Diablo II Character Editor + Copyright (C) 2022 Walter Couto + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . +*/ +//--------------------------------------------------------------------------- +#pragma once + +// CD2MultiLineListCtrl +#include +#include + +class CD2MultiLineListCtrl : public CListCtrl +{ + DECLARE_DYNAMIC(CD2MultiLineListCtrl) + +public: + CD2MultiLineListCtrl(); + virtual ~CD2MultiLineListCtrl(); + + void ShowGridLines(BOOL bShow); + DWORD SetExtendedStyle(DWORD dwNewStyle); + DWORD GetExtendedStyle() const; + + // Retrieves a description of a particular item in the control. + BOOL GetItem(LVITEM* pItem) const; + + // Sets information to an existing item in the control. + BOOL SetItem(const LVITEM* pItem); + BOOL SetItem(int nItem, int nSubItem, UINT nMask, LPCTSTR lpszItem, + int nImage, UINT nState, UINT nStateMask, LPARAM lParam); + BOOL SetItem(int nItem, int nSubItem, UINT nMask, LPCTSTR lpszItem, + int nImage, UINT nState, UINT nStateMask, LPARAM lParam, int nIndent); + + // Retrieves the number of items in the control. + int GetItemCount() const; + + // Gets first item selected in the control and prepares for + // finding other selected items (if the control has the multiple + // selection style). + POSITION GetFirstSelectedItemPosition() const; + + // Finds the next selected item, after a previous call + // to GetFirstSelectedItemPosition(). + int GetNextSelectedItem( POSITION& pos) const; + + // Retrieves the bounding rectangle for a particular item. + BOOL GetItemRect(int nItem, LPRECT lpRect, UINT nCode) const; + + BOOL InvalidateItemRect(int nItem, BOOL bErase); + + // Adds an item to the control. + int InsertItem(const LVITEM* pItem); + int InsertItem(int nItem, LPCTSTR lpszItem); + int InsertItem(int nItem, LPCTSTR lpszItem, int nImage); + + // Removes a single item from the control. + BOOL DeleteItem(int nItem); + + // Removes all items from the control. + BOOL DeleteAllItems(); + + // Retrieves the index of the topmost visible item in the control. + int GetTopIndex() const; + + // Retrieves the text associated with a particular item. + CString GetItemText(int nItem, int nSubItem) const; + int GetItemText(int nItem, int nSubItem, LPTSTR lpszText, int nLen) const; + + // Sets the text associated with a particular item. + BOOL SetItemText(int nItem,int nSubItem,LPCTSTR lpszText); + + // Sets the data (lParam) associated with a particular item. + BOOL SetItemData(int nItem, DWORD_PTR dwData); + + // Retrieves the data (lParam) associated with a particular item. + DWORD_PTR GetItemData(int nItem) const; + + // Causes the control to scroll its content so the specified item + // is completely (or at least partially, depending on the + // bPartialOK parameter) visible. + BOOL EnsureVisible(int nItem, BOOL bPartialOK); + + // Forces the control to repaint a specific range of items. + BOOL RedrawItems(int nFirst, int nLast); + + // Forces the control to repaint a specific item. + BOOL Update(int nItem); + + void AdjustColumnWidths(); + +protected: + DECLARE_MESSAGE_MAP() + + struct ColData + { + size_t numRows = 1; + CString text; + }; + + struct RowData + { + size_t startRow = 0; + size_t numRows = 1; // max of colData + std::vector colData; + DWORD_PTR dwData = 0; + }; + std::vector m_rowData; + BOOL m_bDrawGrid = TRUE; + + afx_msg void OnCustomDraw(NMHDR* pNMHDR, LRESULT* pResult); + afx_msg void OnKillFocus(CWnd* pNewWnd); + afx_msg void OnSetFocus(CWnd* pOldWnd); + afx_msg void OnLvnItemchanged(NMHDR* pNMHDR, LRESULT* pResult); + BOOL SetMultilineText(int nItem, LPCTSTR lpszText, int nSubItem = -1); +}; diff --git a/source/D2RunewordForm.cpp b/source/D2RunewordForm.cpp new file mode 100644 index 00000000..dde7af78 --- /dev/null +++ b/source/D2RunewordForm.cpp @@ -0,0 +1,214 @@ +/* + Diablo II Character Editor + Copyright (C) 2022 Walter Couto + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . +*/ +//--------------------------------------------------------------------------- + +#include "pch.h" +#include "D2Editor.h" +#include "D2RunewordForm.h" +#include "afxdialogex.h" +#include "d2ce/helpers/ItemHelpers.h" +#include + +namespace +{ + void AddListColData(CD2MultiLineListCtrl& ctrl, std::uint32_t row, std::uint32_t col, const std::string& u8string) + { + std::u16string uText = utf8::utf8to16(u8string); + CString str(reinterpret_cast(uText.c_str())); + LVITEM lv; + lv.iItem = row; + lv.iSubItem = col; + lv.pszText = (LPTSTR)(LPCTSTR)str; + lv.mask = LVIF_TEXT; + if (col == 0) + { + ctrl.InsertItem(&lv); + } + else + { + ctrl.SetItem(&lv); + } + } +} + +//--------------------------------------------------------------------------- +// CD2RunewordForm dialog + +IMPLEMENT_DYNAMIC(CD2RunewordForm, CDialogEx) + +//--------------------------------------------------------------------------- +CD2RunewordForm::CD2RunewordForm(CD2ItemsForm& form) + : CDialogEx(CD2RunewordForm::IDD, (CWnd*)&form), MainForm(form.MainForm), ItemsFormPtr(&form), ItemPtr(form.CurrItem) +{ +} +//--------------------------------------------------------------------------- +CD2RunewordForm::CD2RunewordForm(CD2SharedStashForm& form) + : CDialogEx(CD2RunewordForm::IDD, (CWnd*)&form), MainForm(form.MainForm), SharedStashFormPtr(&form), ItemPtr(form.CurrItem) +{ +} +//--------------------------------------------------------------------------- +CD2RunewordForm::~CD2RunewordForm() +{ +} +//--------------------------------------------------------------------------- +void CD2RunewordForm::DoDataExchange(CDataExchange* pDX) +{ + __super::DoDataExchange(pDX); + DDX_Control(pDX, IDC_RUNEWORD_LIST, RunewordGrid); +} +//--------------------------------------------------------------------------- +BEGIN_MESSAGE_MAP(CD2RunewordForm, CDialogEx) + ON_BN_CLICKED(IDOK, &CD2RunewordForm::OnBnClickedOk) +END_MESSAGE_MAP() + +// CD2RunewordForm message handlers + +//--------------------------------------------------------------------------- +BOOL CD2RunewordForm::OnInitDialog() +{ + __super::OnInitDialog(); + + RunewordGrid.SendMessage(LVM_SETEXTENDEDLISTVIEWSTYLE, 0, LVS_EX_FULLROWSELECT); + RunewordGrid.InsertColumn(0, _T("Runeword"), LVCFMT_RIGHT, LVSCW_AUTOSIZE_USEHEADER); + RunewordGrid.InsertColumn(1, _T("Runes"), LVCFMT_RIGHT, LVSCW_AUTOSIZE_USEHEADER); + RunewordGrid.InsertColumn(2, _T("Attributes"), LVCFMT_CENTER, LVSCW_AUTOSIZE_USEHEADER); + + FillCells(); + return 0; +} +//--------------------------------------------------------------------------- +void CD2RunewordForm::OnBnClickedOk() +{ + if (ItemPtr != nullptr) + { + auto posSelection = RunewordGrid.GetFirstSelectedItemPosition(); + if (posSelection) + { + auto nCurrentSelection = RunewordGrid.GetNextSelectedItem(posSelection); + auto runwordId = std::uint16_t(RunewordGrid.GetItemData(nCurrentSelection)); + if (SharedStashFormPtr != nullptr) + { + SharedStashFormPtr->setItemRuneword(*ItemPtr, runwordId); + } + else if (ItemsFormPtr != nullptr) + { + ItemsFormPtr->setItemRuneword(*ItemPtr, runwordId); + } + } + } + __super::OnOK(); +} +//--------------------------------------------------------------------------- +void CD2RunewordForm::FillCells() +{ + if (ItemPtr == nullptr) + { + return; + } + + auto charLevel = MainForm.getCharacterLevel(); + + TCHAR name[255]; + LVCOLUMN col; + col.mask = LVCF_TEXT; + col.pszText = name; + col.cchTextMax = sizeof(name) / sizeof(TCHAR); + + std::u16string uText; + std::uint32_t row = 0; + for (auto& runeword : ItemPtr->getPossibleRunewords()) + { + row = RunewordGrid.GetItemCount(); + AddListColData(RunewordGrid, row, 0, runeword.name); + + { + std::stringstream ss; + bool bFirstItem = true; + std::string quoteStr; + d2ce::LocalizationHelpers::GetStringTxtValue("RuneQuote", quoteStr, "'"); + for (const auto& runeCode : runeword.runeCodes) + { + const auto& item = d2ce::ItemHelpers::getItemTypeHelper(runeCode); + if (!item.isRune()) + { + continue; + } + + if (bFirstItem) + { + ss << quoteStr; + bFirstItem = false; + } + + ss << item.getRuneLetter(); + } + + if (!bFirstItem) + { + ss << quoteStr; + } + + AddListColData(RunewordGrid, row, 1, ss.str()); + } + + std::vector attribs; + for (const auto& runeCode : runeword.runeCodes) + { + const auto& runeItemType = d2ce::ItemHelpers::getItemTypeHelper(runeCode); + if (runeItemType.getRuneMagicalAttributes(*ItemPtr, attribs)) + { + runeword.attribs.reserve(std::max(runeword.attribs.capacity(), runeword.attribs.size() + attribs.size())); + for (auto& value : attribs) + { + runeword.attribs.emplace_back(std::move(value)); + } + } + } + + d2ce::ItemHelpers::formatMagicalAttributes(runeword.attribs, charLevel); + { + std::stringstream ss; + bool bFirstItem = true; + for (const auto& attrib : runeword.attribs) + { + if (!attrib.Visible) + { + continue; + } + + if (!bFirstItem) + { + ss << "\n"; + } + bFirstItem = false; + + ss << attrib.Desc; + } + + AddListColData(RunewordGrid, row, 2, ss.str()); + } + + RunewordGrid.SetItemData(row, runeword.id); + } + + if (RunewordGrid.GetItemCount() > 0) + { + RunewordGrid.AdjustColumnWidths(); + RunewordGrid.SetItemState(0, LVIS_SELECTED, LVIS_SELECTED); + } +} diff --git a/source/D2RunewordForm.h b/source/D2RunewordForm.h new file mode 100644 index 00000000..37e36b2d --- /dev/null +++ b/source/D2RunewordForm.h @@ -0,0 +1,60 @@ +/* + Diablo II Character Editor + Copyright (C) 2022 Walter Couto + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . +*/ +//--------------------------------------------------------------------------- + +#pragma once + +//--------------------------------------------------------------------------- +#include "D2ItemsForm.h" +#include "D2SharedStashForm.h" +#include "D2MultiLineListCtrl.h" + +//--------------------------------------------------------------------------- +class CD2RunewordForm : public CDialogEx +{ + DECLARE_DYNAMIC(CD2RunewordForm) + +public: + CD2RunewordForm(CD2ItemsForm& form); + CD2RunewordForm(CD2SharedStashForm& form); + virtual ~CD2RunewordForm(); + + // Dialog Data + enum { IDD = IDD_RUNEWORD_DIALOG }; + +protected: + virtual void DoDataExchange(CDataExchange* pDX); // DDX/DDV support + + // Implementation +protected: + // Generated message map functions + virtual BOOL OnInitDialog(); + afx_msg void OnBnClickedOk(); + + DECLARE_MESSAGE_MAP() + + void FillCells(); + +private: + CD2MainForm& MainForm; + CD2ItemsForm* ItemsFormPtr = nullptr; + CD2SharedStashForm* SharedStashFormPtr = nullptr; + d2ce::Item* ItemPtr = nullptr; + CD2MultiLineListCtrl RunewordGrid; +}; +//--------------------------------------------------------------------------- diff --git a/source/D2SharedStashForm.cpp b/source/D2SharedStashForm.cpp index a5d488a9..b3498827 100644 --- a/source/D2SharedStashForm.cpp +++ b/source/D2SharedStashForm.cpp @@ -1106,6 +1106,16 @@ const d2ce::Item* CD2SharedStashForm::PlaceItem(UINT id, d2ce::Item& item, CPoin return false; } //--------------------------------------------------------------------------- +bool CD2SharedStashForm::setItemRuneword(d2ce::Item& item, std::uint16_t id) +{ + if (Stash.setItemRuneword(item, id)) + { + refreshGrid(); + return true; + } + return false; +} +//--------------------------------------------------------------------------- const d2ce::Item* CD2SharedStashForm::GetInvItem(UINT id, UINT offset) const { // Make sure we have hit an item diff --git a/source/D2SharedStashForm.h b/source/D2SharedStashForm.h index 9f89c54b..dc5ee037 100644 --- a/source/D2SharedStashForm.h +++ b/source/D2SharedStashForm.h @@ -28,7 +28,8 @@ class CD2SharedStashForm : public CDialogEx, public CD2ItemToolTipCtrlCallback, { friend class CD2ItemsGrid; friend class CD2GemsForm; - friend class CD2AddGemsForm; + friend class CD2AddGemsForm; + friend class CD2RunewordForm; DECLARE_DYNAMIC(CD2SharedStashForm) public: @@ -160,6 +161,8 @@ class CD2SharedStashForm : public CDialogEx, public CD2ItemToolTipCtrlCallback, bool CanPlaceItem(UINT id, const d2ce::Item& item, CPoint point); const d2ce::Item* PlaceItem(UINT id, d2ce::Item& item, CPoint point, CBitmap& bitmap); + bool setItemRuneword(d2ce::Item& item, std::uint16_t id); + // Inherited via CD2ItemToolTipCtrlCallback const d2ce::Item* GetInvItem(UINT id, UINT offset) const override; const d2ce::Item* InvHitTest(UINT id, CPoint point, TOOLINFO* pTI = nullptr) const override; diff --git a/source/D2WaypointsForm.cpp b/source/D2WaypointsForm.cpp index 46d09884..d67dafd3 100644 --- a/source/D2WaypointsForm.cpp +++ b/source/D2WaypointsForm.cpp @@ -21,7 +21,7 @@ #include "pch.h" #include "D2Editor.h" #include "D2WaypointsForm.h" -#include "MainFormConstants.h" +#include "D2MainFormConstants.h" #include "d2ce/helpers/ItemHelpers.h" #include #include "afxdialogex.h" diff --git a/source/d2ce/ActsInfo.cpp b/source/d2ce/ActsInfo.cpp index 0d5e49b3..febf3f07 100644 --- a/source/d2ce/ActsInfo.cpp +++ b/source/d2ce/ActsInfo.cpp @@ -31,17 +31,20 @@ namespace d2ce constexpr std::array QUESTS_SIZE_MARKER = { 0x2A, 0x01 }; constexpr std::uint32_t MIN_START_QUEST_POS = 335; + constexpr std::uint32_t MIN_START_QUEST_POS_v100 = 130; constexpr std::array WAYPOINTS_MARKER = { 0x57, 0x53 }; // alternatively "WS" constexpr std::array WAYPOINTS_VERSION = { 0x01, 0x00, 0x00, 0x00 }; constexpr std::array WAYPOINTS_SIZE_MARKER = { 0x50, 0x00 }; constexpr std::uint32_t MIN_START_WAYPOINTS_POS = 633; + constexpr std::uint32_t MIN_START_WAYPOINTS_POS_v100 = 428; constexpr std::array NPC_MARKER = { 0x01, 0x77 }; constexpr std::array NPC_SIZE_MARKER = { 0x34, 0x00 }; constexpr std::uint32_t MIN_START_NPC_POS = 713; + constexpr std::uint32_t MIN_START_NPC_POS_v100 = 508; constexpr std::uint16_t questNotStarted = 0x0000; constexpr std::uint16_t questStarted = 0x0004; @@ -103,9 +106,9 @@ bool d2ce::ActsInfo::readQuests(std::FILE* charfile) } else { - if (cur_pos < MIN_START_POS) + if (cur_pos < MIN_START_QUEST_POS_v100) { - cur_pos = MIN_START_POS; + cur_pos = MIN_START_QUEST_POS_v100; std::fseek(charfile, cur_pos, SEEK_SET); } } @@ -566,9 +569,9 @@ bool d2ce::ActsInfo::readWaypoints(std::FILE* charfile) } else { - if (cur_pos < MIN_START_POS) + if (cur_pos < MIN_START_WAYPOINTS_POS_v100) { - cur_pos = MIN_START_POS; + cur_pos = MIN_START_WAYPOINTS_POS_v100; std::fseek(charfile, cur_pos, SEEK_SET); } } @@ -854,9 +857,9 @@ bool d2ce::ActsInfo::readNPC(std::FILE* charfile) } else { - if (cur_pos < MIN_START_POS) + if (cur_pos < MIN_START_NPC_POS_v100) { - cur_pos = MIN_START_POS; + cur_pos = MIN_START_NPC_POS_v100; std::fseek(charfile, cur_pos, SEEK_SET); } } diff --git a/source/d2ce/Character.cpp b/source/d2ce/Character.cpp index 1933e76d..25133502 100644 --- a/source/d2ce/Character.cpp +++ b/source/d2ce/Character.cpp @@ -40,14 +40,14 @@ namespace d2ce }; constexpr std::array UNKNOWN_01C_v100 = { 0xDD, 0x00, 0x10, 0x00, 0x82, 0x00 }; constexpr std::array UNKNOWN_01C_v107 = { 0x3F, 0x01, 0x10, 0x00, 0x82, 0x00 }; - constexpr std::array UNKNOWN_026 = { 0x00, 0x00 }; - constexpr std::array UNKNOWN_029 = { 0x10, 0x1E }; + constexpr std::array UNKNOWN_01A = { 0x00, 0x00 }; + constexpr std::array UNKNOWN_01D = { 0x10, 0x1E }; constexpr std::array UNKNOWN_034 = { 0xFF, 0xFF, 0xFF, 0xFF }; - constexpr std::array UNKNOWN_05A_v100 = { + constexpr std::array UNKNOWN_05A_v100 = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }; constexpr std::array UNKNOWN_0AF = { 0x00, 0x00 }; constexpr std::array UNKNOWN_0BF = { @@ -989,15 +989,8 @@ void d2ce::Character::readBasicInfo() if (Bs.Version < EnumCharVersion::v109) { - if (Bs.Version < EnumCharVersion::v107) - { - m_starting_location = 38; - std::fseek(m_charfile, m_starting_location, SEEK_SET); - } - else - { - m_starting_location = std::ftell(m_charfile); - } + m_starting_location = 38; + std::fseek(m_charfile, m_starting_location, SEEK_SET); m_appearances_location = m_starting_location; std::fread(Appearances.data(), Appearances.size(), 1, m_charfile); @@ -1028,8 +1021,6 @@ void d2ce::Character::readBasicInfo() StartingAct[static_cast>(Bs.DifficultyLastPlayed)] = 0x80 | static_cast>(Bs.StartingAct); m_mapid_location = 126; - auto diff = m_mapid_location -std::ftell(m_charfile); - diff; std::fseek(m_charfile, m_mapid_location, SEEK_SET); std::fread(&MapID, sizeof(MapID), 1, m_charfile); } @@ -1339,7 +1330,7 @@ bool d2ce::Character::readBasicInfo(const Json::Value& root) } else { - std::fwrite(UNKNOWN_026.data(), UNKNOWN_026.size(), 1, m_charfile); + std::fwrite(UNKNOWN_01A.data(), UNKNOWN_01A.size(), 1, m_charfile); } m_class_location = std::ftell(m_charfile); @@ -1352,7 +1343,7 @@ bool d2ce::Character::readBasicInfo(const Json::Value& root) } else { - std::fwrite(UNKNOWN_029.data(), UNKNOWN_029.size(), 1, m_charfile); + std::fwrite(UNKNOWN_01D.data(), UNKNOWN_01D.size(), 1, m_charfile); } // Level can be retrieved from the attributes section @@ -1363,7 +1354,7 @@ bool d2ce::Character::readBasicInfo(const Json::Value& root) DisplayLevel = std::uint8_t(jsonValue.asInt()); } std::fwrite(&DisplayLevel, sizeof(DisplayLevel), 1, m_charfile); - if (Bs.Version < EnumCharVersion::v107) + if (Bs.Version < EnumCharVersion::v109) { value = 0; std::fwrite(&value, sizeof(value), 1, m_charfile); @@ -4161,6 +4152,11 @@ bool d2ce::Character::setItemLocation(d2ce::Item& item, EnumEquippedId equippedI return m_items.setItemLocation(item, *this, equippedId, invType, pRemovedItem); } //--------------------------------------------------------------------------- +bool d2ce::Character::setItemRuneword(d2ce::Item& item, std::uint16_t id) +{ + return m_items.setItemRuneword(item, id); +} +//--------------------------------------------------------------------------- size_t d2ce::Character::getNumberOfStackables() const { return m_items.getNumberOfStackables(); diff --git a/source/d2ce/Character.h b/source/d2ce/Character.h index 693e2daa..b78d2ea8 100644 --- a/source/d2ce/Character.h +++ b/source/d2ce/Character.h @@ -324,6 +324,8 @@ namespace d2ce bool setItemLocation(d2ce::Item& item, EnumAltItemLocation altPositionId, std::uint16_t positionX, std::uint16_t positionY, d2ce::EnumItemInventory invType, const d2ce::Item*& pRemovedItem); bool setItemLocation(d2ce::Item& item, EnumEquippedId equippedId, d2ce::EnumItemInventory invType, const d2ce::Item*& pRemovedItem); + bool setItemRuneword(d2ce::Item& item, std::uint16_t id); + size_t getNumberOfStackables() const; size_t fillAllStackables(d2ce::ItemFilter filter = d2ce::ItemFilter()); diff --git a/source/d2ce/CharacterStats.cpp b/source/d2ce/CharacterStats.cpp index 965544bc..9307b62d 100644 --- a/source/d2ce/CharacterStats.cpp +++ b/source/d2ce/CharacterStats.cpp @@ -37,9 +37,15 @@ namespace d2ce constexpr std::array V110_BITS_PER_STAT = { 10,10,10,10,10,8,21,21,21,21,21,21,7,32,25,25 }; constexpr std::uint32_t MIN_START_STATS_POS = 765; + constexpr std::uint32_t MIN_START_STATS_POS_v100 = 560; constexpr std::array SKILLS_MARKER = { 0x69, 0x66 }; // alternatively "if" + namespace ItemHelpers + { + void initRunewordData(); + } + std::map> s_MinExpRequired; void InitExperienceData(const ITxtReader& txtReader) { @@ -1025,6 +1031,7 @@ namespace d2ce s_SkillInfoMap.swap(skillInfoMap); InitSkillDescData(txtReader); + ItemHelpers::initRunewordData(); } const std::vector& GetExperienceLevels(EnumCharClass charClass) @@ -1416,9 +1423,9 @@ bool d2ce::CharacterStats::readAllStats(std::FILE* charfile) } else { - if (cur_pos < MIN_START_POS) + if (cur_pos < MIN_START_STATS_POS_v100) { - cur_pos = MIN_START_POS; + cur_pos = MIN_START_STATS_POS_v100; std::fseek(charfile, cur_pos, SEEK_SET); } } diff --git a/source/d2ce/DataTypes.h b/source/d2ce/DataTypes.h index e0c65fb0..262e6fbf 100644 --- a/source/d2ce/DataTypes.h +++ b/source/d2ce/DataTypes.h @@ -1357,6 +1357,7 @@ namespace d2ce bool canEquip(EnumEquippedId equipId, EnumCharClass charClass) const; bool getSocketedMagicalAttributes(const d2ce::Item& item, std::vector& attribs, std::uint8_t parentGemApplyType = 0) const; + bool getRuneMagicalAttributes(const d2ce::Item& parentItem, std::vector& attribs) const; std::string getPotionDesc(EnumCharClass charClass) const; diff --git a/source/d2ce/Item.cpp b/source/d2ce/Item.cpp index dc52ad73..92476bd5 100644 --- a/source/d2ce/Item.cpp +++ b/source/d2ce/Item.cpp @@ -103,18 +103,18 @@ namespace d2ce constexpr std::uint32_t ITEM_V104_EX_CONTAINER_BIT_OFFSET = 232; constexpr std::uint32_t ITEM_V100_ITEMCODE_BIT_OFFSET = 64; - constexpr std::uint32_t ITEM_V100_EAR_TYPECODE_BIT_OFFSET = 74; + constexpr std::uint32_t ITEM_V100_EAR_ITEMCODE_BIT_OFFSET = 48; + constexpr std::uint32_t ITEM_V100_EAR_ATTRIBE_BIT_OFFSET = 74; + constexpr std::uint32_t ITEM_V100_EAR_LEVEL_BIT_OFFSET = 100; constexpr std::uint32_t ITEM_V100_TYPECODE_BIT_OFFSET = 68; constexpr std::uint32_t ITEM_V100_DURABILITY_BIT_OFFSET = 105; constexpr std::uint32_t ITEM_V100_DWA_BIT_OFFSET = 139; - constexpr std::uint32_t ITEM_V100_DWB_BIT_OFFSET = 171; constexpr std::uint32_t ITEM_V104_EX_TYPECODE_BIT_OFFSET = 58; constexpr std::uint32_t ITEM_V104_SM_ITEMCODE_BIT_OFFSET = 80; constexpr std::uint32_t ITEM_V104_SM_TYPECODE_BIT_OFFSET = 82; constexpr std::uint32_t ITEM_V104_EAR_ATTRIBE_BIT_OFFSET = 82; constexpr std::uint32_t ITEM_V104_EX_DURABILITY_BIT_OFFSET = 137; constexpr std::uint32_t ITEM_V104_EX_DWA_BIT_OFFSET = 171; - constexpr std::uint32_t ITEM_V104_EX_DWB_BIT_OFFSET = 203; constexpr std::uint32_t ITEM_V100_BITFIELD3_BIT_OFFSET = 48; constexpr std::uint32_t ITEM_V100_NUM_SOCKETED_BIT_OFFSET = 53; @@ -299,6 +299,7 @@ namespace d2ce bool getUniqueQuestMagicAttribs(const std::array& strcode, std::vector& attribs, EnumItemVersion version, std::uint16_t gameVersion, std::uint16_t level, std::uint32_t dwb = 0); std::uint16_t getSetItemId(std::uint16_t id, const std::array& strcode); + std::uint32_t getSetItemDWBCode(std::uint16_t setItemId); std::uint32_t getSetItemDWBCode(std::uint16_t id, const std::array& strcode); std::uint8_t generateInferiorQualityId(std::uint16_t level, std::uint32_t dwb = 0); bool generateMagicalAffixes(const std::array& strcode, MagicalCachev100& cache, EnumItemVersion version, std::uint16_t gameVersion, std::uint16_t level, std::uint32_t dwb = 0); @@ -671,8 +672,8 @@ d2ce::Item::Item(EnumItemVersion itemVersion, std::array& strco quality_bit_offset = start_bit_offset + QUALITY_BIT_OFFSET_100; quality_attrib_bit_offset = ITEM_V100_SPECIALITEMCODE_BIT_OFFSET; item_level_bit_offset = ITEM_V100_LEVEL_BIT_OFFSET; - dwa_bit_offset = ITEM_V100_DWA_BIT_OFFSET; - dwb_bit_offset = ITEM_V100_DWB_BIT_OFFSET; + item_id_bit_offset = ITEM_V100_DWA_BIT_OFFSET; + dwb_bit_offset = item_id_bit_offset + 32; if (itemCode >= MAXUINT16) { *this = invalidItem; @@ -704,7 +705,7 @@ d2ce::Item::Item(EnumItemVersion itemVersion, std::array& strco } value = ItemHelpers::generarateRandomDW(); - current_bit_offset = dwa_bit_offset; + current_bit_offset = item_id_bit_offset; if (!setBits(current_bit_offset, 32, value)) { *this = invalidItem; @@ -1232,6 +1233,7 @@ d2ce::Item& d2ce::Item::operator=(const Item& other) data = other.data; SocketedItems = other.SocketedItems; + socketedMagicalAttributes = other.socketedMagicalAttributes; cachedCombinedMagicalAttributes = other.cachedCombinedMagicalAttributes; ItemVersion = other.ItemVersion; @@ -1272,7 +1274,6 @@ d2ce::Item& d2ce::Item::operator=(const Item& other) runeword_props_bit_offset = other.runeword_props_bit_offset; item_end_bit_offset = other.item_end_bit_offset; item_current_socket_idx = other.item_current_socket_idx; - dwa_bit_offset = other.dwa_bit_offset; dwb_bit_offset = other.dwb_bit_offset; magic_affixes_v100 = other.magic_affixes_v100; rare_affixes_v100 = other.rare_affixes_v100; @@ -1330,7 +1331,6 @@ d2ce::Item& d2ce::Item::operator=(Item&& other) noexcept runeword_props_bit_offset = std::exchange(other.runeword_props_bit_offset, 0); item_end_bit_offset = std::exchange(other.item_end_bit_offset, 0); item_current_socket_idx = std::exchange(other.item_current_socket_idx, 0); - dwa_bit_offset = std::exchange(other.dwa_bit_offset, 0); dwb_bit_offset = std::exchange(other.dwb_bit_offset, 0); magic_affixes_v100 = std::exchange(other.magic_affixes_v100, MagicalCachev100()); rare_affixes_v100 = std::exchange(other.rare_affixes_v100, RareOrCraftedCachev100()); @@ -2763,6 +2763,7 @@ void d2ce::Item::verifyRuneword() } // add bonus magical attributes from runeword id + cachedCombinedMagicalAttributes.clear(); runeword_props_bit_offset = runeword_props_bit_offset_marker; size_t current_bit_offset = runeword_props_bit_offset; if (!updatePropertyList(current_bit_offset, runeword.attribs)) @@ -2778,6 +2779,7 @@ void d2ce::Item::verifyRuneword() } } + cachedCombinedMagicalAttributes.clear(); if (!isRuneword()) { return; @@ -2906,7 +2908,6 @@ void d2ce::Item::updateOffset(size_t& startOffset, ptrdiff_t diff) CheckOffsetValue(magical_props_bit_offset, startOffset, bFoundMatch, diff); CheckOffsetValue(set_bonus_props_bit_offset, startOffset, bFoundMatch, diff); CheckMarkerOffsetValue(runeword_props_bit_offset_marker, runeword_props_bit_offset, startOffset, bFoundMatch, diff); - CheckOffsetValue(dwa_bit_offset, startOffset, bFoundMatch, diff); CheckOffsetValue(dwb_bit_offset, startOffset, bFoundMatch, diff); } //--------------------------------------------------------------------------- @@ -3757,6 +3758,10 @@ bool d2ce::Item::getEarAttributes(d2ce::EarAttributes& attrib) const switch (getVersion()) { case EnumItemVersion::v100: // v1.00 - v1.03 item + currentOffset = ITEM_V100_EAR_LEVEL_BIT_OFFSET; + levelBits = 8; + break; + case EnumItemVersion::v104: // v1.04 - v1.06 item levelBits = 8; break; @@ -4092,8 +4097,14 @@ std::uint32_t d2ce::Item::getId() const switch (getVersion()) { case EnumItemVersion::v100: // v1.00 - v1.03 item + item_id_bit_offset = ITEM_V100_DWA_BIT_OFFSET; + dwb_bit_offset = item_id_bit_offset + 32; + break; + case EnumItemVersion::v104: // v1.04 - v1.06 item - return 0; + item_id_bit_offset = ITEM_V104_EX_DWA_BIT_OFFSET; + dwb_bit_offset = item_id_bit_offset + 32; + break; case EnumItemVersion::v107: // v1.07 item case EnumItemVersion::v108: // v1.08 item @@ -4112,6 +4123,11 @@ std::uint32_t d2ce::Item::getId() const //--------------------------------------------------------------------------- bool d2ce::Item::randomizeId() { + if (isSimpleItem() || (getVersion() < EnumItemVersion::v107)) + { + return false; + } + if (item_id_bit_offset == 0) { // should not happen @@ -4342,6 +4358,41 @@ std::uint8_t d2ce::Item::getTomeValue() const return std::uint8_t(readBits(tome_bit_offset, 5)); } //--------------------------------------------------------------------------- +std::uint16_t d2ce::Item::getSetItemId() const +{ + if (quality_attrib_bit_offset == 0) + { + return 0; + } + + switch (getQuality()) + { + case EnumItemQuality::SET: + break; + + default: + return 0; + } + + std::array strcode = { 0, 0, 0, 0 }; + std::uint16_t id = 0; + switch (getVersion()) + { + case EnumItemVersion::v100: // v1.00 - v1.03 item + case EnumItemVersion::v104: // v1.04 - v1.06 item + if (!getItemCode(strcode)) + { + // should not happen + return 0; + } + + id = ItemHelpers::getSetItemId((std::uint16_t)readBits(quality_attrib_bit_offset, ITEM_V100_UNIQUE_ID_NUM_BITS), strcode); + return (id >= MAXUINT16) ? 0 : id; + } + + return (std::uint16_t)readBits(quality_attrib_bit_offset, SET_UNIQUE_ID_NUM_BITS); +} +//--------------------------------------------------------------------------- bool d2ce::Item::getSetAttributes(SetAttributes& attrib) const { attrib.clear(); @@ -5685,7 +5736,7 @@ std::uint8_t d2ce::Item::getMaxSocketCount() const break; } - return result.getMaxSockets(level); + return std::max(result.getMaxSockets(level), getSocketCount()); } //--------------------------------------------------------------------------- std::uint8_t d2ce::Item::getMaxSocketedCount() const @@ -6493,7 +6544,10 @@ bool d2ce::Item::setRuneword(std::uint16_t id) for (const auto& runeCode : runeword.runeCodes) { strcode = ItemCodeStringConverter(runeCode); - Item runeItem(version, strcode, isExpansion); + std::list runeItems; + runeItems.push_back(Item(version, strcode, isExpansion)); + auto iter = runeItems.begin(); + auto& runeItem = *iter; if (runeItem.data.empty() || !runeItem.isRune() || !canSocketItem(runeItem)) { // invalid item @@ -6509,7 +6563,7 @@ bool d2ce::Item::setRuneword(std::uint16_t id) const auto& runeItemType = runeItem.getItemTypeHelper(); runeItemType.getSocketedMagicalAttributes(runeItem, runeItem.socketedMagicalAttributes, gemApplyType); - SocketedItems.push_back(runeItem); + SocketedItems.splice(SocketedItems.end(), runeItems, iter); updateSocketedItemCount(); } @@ -7916,18 +7970,7 @@ bool d2ce::Item::getDisplayedMagicalAttributes(std::vector& at AddUndeadBonusMagicalAttribute(getVersion(), getGameVersion(), attribs); } - // check for the "all" cases - ItemHelpers::checkForRelatedMagicalAttributes(attribs); - - bool bFormatted = false; - for (auto& attrib : attribs) - { - bFormatted |= ItemHelpers::formatDisplayedMagicalAttribute(attrib, charLevel); - } - - // Sort display items in proper order - std::sort(attribs.begin(), attribs.end(), ItemHelpers::magicalAttributeSorter); - return bFormatted; + return d2ce::ItemHelpers::formatMagicalAttributes(attribs, charLevel); } //--------------------------------------------------------------------------- bool d2ce::Item::getDisplayedRunewordAttributes(RunewordAttributes& attribs, std::uint32_t charLevel) const @@ -7937,18 +7980,7 @@ bool d2ce::Item::getDisplayedRunewordAttributes(RunewordAttributes& attribs, std return false; } - // check for the "all" cases - ItemHelpers::checkForRelatedMagicalAttributes(attribs.MagicalAttributes); - - bool bFormatted = false; - for (auto& attrib : attribs.MagicalAttributes) - { - bFormatted |= ItemHelpers::formatDisplayedMagicalAttribute(attrib, charLevel); - } - - // Sort display items in proper order - std::sort(attribs.MagicalAttributes.begin(), attribs.MagicalAttributes.end(), ItemHelpers::magicalAttributeSorter); - return bFormatted; + return d2ce::ItemHelpers::formatMagicalAttributes(attribs.MagicalAttributes, charLevel); } //--------------------------------------------------------------------------- bool d2ce::Item::getDisplayedCombinedMagicalAttributes(std::vector& attribs, std::uint32_t charLevel) const @@ -7958,18 +7990,7 @@ bool d2ce::Item::getDisplayedCombinedMagicalAttributes(std::vector 0) { @@ -12261,6 +12305,7 @@ bool d2ce::Item::readItem(const Json::Value& itemRoot, bool bSerializedFormat, E { return false; } + max_bit_offset = std::max(max_bit_offset, current_bit_offset); } } @@ -12304,8 +12349,10 @@ bool d2ce::Item::readItem(const Json::Value& itemRoot, bool bSerializedFormat, E { return false; } + max_bit_offset = std::max(max_bit_offset, current_bit_offset); } - + + item_end_bit_offset = max_bit_offset; if (numSocketed > 0) { node = itemRoot[bSerializedFormat ? "SocketedItems" : "socketed_items"]; @@ -12339,7 +12386,6 @@ bool d2ce::Item::readItem(const Json::Value& itemRoot, bool bSerializedFormat, E } } - item_end_bit_offset = max_bit_offset; return true; } //--------------------------------------------------------------------------- @@ -12598,21 +12644,29 @@ void d2ce::Item::asJson(Json::Value& parent, std::uint32_t charLevel, EnumItemVe item["NumberOfSocketedItems"] = std::uint16_t(socketedItems.size()); item["SocketedItems"] = socketedItems; - item["Id"] = getId(); + auto id = getId(); + auto quality = getQuality(); + item["Id"] = id; item["ItemLevel"] = std::uint16_t(getLevel()); - - if (dwa_bit_offset != 0) + if (dwb_bit_offset != 0) { - if (dwb_bit_offset == 0) + item["Dwa"] = readBits(item_id_bit_offset, 32); + item["Dwb"] = readBits(dwb_bit_offset, 32); + } + else if (version < EnumItemVersion::v107) + { + item["Dwa"] = id == 0 ? ItemHelpers::generarateRandomDW() : id; + if (quality == EnumItemQuality::SET) { - dwb_bit_offset = dwa_bit_offset + 32; + // Find correct DWB value for the SET + item["Dwb"] = ItemHelpers::getSetItemDWBCode(getSetItemId()); + } + else + { + item["Dwb"] = ItemHelpers::generarateRandomDW(); } - - item["Dwa"] = readBits(dwa_bit_offset, 32); - item["Dwb"] = readBits(dwb_bit_offset, 32); } - auto quality = getQuality(); item["Quality"] = std::uint16_t(quality); item["HasMultipleGraphics"] = hasMultipleGraphics(); item["GraphicId"] = std::uint16_t(getPictureId()); @@ -12807,19 +12861,20 @@ void d2ce::Item::asJson(Json::Value& parent, std::uint32_t charLevel, EnumItemVe } else { - item["id"] = getId(); + auto id = getId(); + item["id"] = id; item["level"] = std::uint16_t(getLevel()); - if (dwa_bit_offset != 0) + if (dwb_bit_offset != 0) { - if (dwb_bit_offset == 0) - { - dwb_bit_offset = dwa_bit_offset + 32; - } - - item["dwa"] = readBits(dwa_bit_offset, 32); + item["dwa"] = readBits(item_id_bit_offset, 32); item["dwb"] = readBits(dwb_bit_offset, 32); } + else if (version < EnumItemVersion::v107) + { + item["dwa"] = id == 0 ? ItemHelpers::generarateRandomDW() : id; + item["dwb"] = ItemHelpers::generarateRandomDW(); + } auto quality = getQuality(); item["quality"] = std::uint16_t(quality); @@ -13178,14 +13233,9 @@ void d2ce::Item::asJson(Json::Value& parent, std::uint32_t charLevel, bool bSeri item["Id"] = getId(); item["ItemLevel"] = std::uint16_t(getLevel()); - if (dwa_bit_offset != 0) + if (dwb_bit_offset != 0) { - if (dwb_bit_offset == 0) - { - dwb_bit_offset = dwa_bit_offset + 32; - } - - item["Dwa"] = readBits(dwa_bit_offset, 32); + item["Dwa"] = readBits(item_id_bit_offset, 32); item["Dwb"] = readBits(dwb_bit_offset, 32); } @@ -13390,14 +13440,9 @@ void d2ce::Item::asJson(Json::Value& parent, std::uint32_t charLevel, bool bSeri item["id"] = getId(); item["level"] = std::uint16_t(getLevel()); - if (dwa_bit_offset != 0) + if (dwb_bit_offset != 0) { - if (dwb_bit_offset == 0) - { - dwb_bit_offset = dwa_bit_offset + 32; - } - - item["dwa"] = readBits(dwa_bit_offset, 32); + item["dwa"] = readBits(item_id_bit_offset, 32); item["dwb"] = readBits(dwb_bit_offset, 32); } @@ -14489,7 +14534,6 @@ bool d2ce::Item::updatePropertyList(size_t& current_bit_offset, const std::vecto return false; } - std::advance(iterValue, 1); if (iterValue == iterValueEnd) { return false; @@ -14539,7 +14583,6 @@ bool d2ce::Item::updatePropertyList(size_t& current_bit_offset, const std::vecto return false; } - std::advance(iterValue, 1); if (iterValue == iterValueEnd) { return false; @@ -14602,7 +14645,6 @@ bool d2ce::Item::updatePropertyList(size_t& current_bit_offset, const std::vecto return false; } - std::advance(iterValue, 1); if (iterValue == iterValueEnd) { return false; @@ -14645,7 +14687,6 @@ bool d2ce::Item::updatePropertyList(size_t& current_bit_offset, const std::vecto { if (stat.name.compare("item_addskill_tab") == 0) { - std::advance(iterValue, 1); if (iterValue == iterValueEnd) { return false; @@ -14689,7 +14730,6 @@ bool d2ce::Item::updatePropertyList(size_t& current_bit_offset, const std::vecto } else { - std::advance(iterValue, 1); if (iterValue == iterValueEnd) { return false; @@ -14722,7 +14762,6 @@ bool d2ce::Item::updatePropertyList(size_t& current_bit_offset, const std::vecto } else { - std::advance(iterValue, 1); if (iterValue == iterValueEnd) { return false; @@ -14740,7 +14779,7 @@ bool d2ce::Item::updatePropertyList(size_t& current_bit_offset, const std::vecto nextInChain = stat.nextInChain; while (nextInChain) { - if (iterValue == attrib.Values.end()) + if (iterValue == iterValueEnd) { return false; } @@ -14768,7 +14807,7 @@ bool d2ce::Item::updatePropertyList(size_t& current_bit_offset, const std::vecto std::advance(iterValue, 1); } - if (iterValue != attrib.Values.end()) + if (iterValue != iterValueEnd) { return false; } @@ -15070,7 +15109,7 @@ bool d2ce::Item::updateItemCodev115(std::uint64_t code, size_t numBitsSet) //--------------------------------------------------------------------------- std::uint8_t d2ce::Item::getInferiorQualityIdv100() const { - if (dwa_bit_offset == 0) + if (item_id_bit_offset == 0) { return 0; } @@ -15086,7 +15125,7 @@ std::uint8_t d2ce::Item::getInferiorQualityIdv100() const if (dwb_bit_offset == 0) { - dwb_bit_offset = dwa_bit_offset + 32; + dwb_bit_offset = item_id_bit_offset + 32; } return ItemHelpers::generateInferiorQualityId(getLevel(), readBits(dwb_bit_offset, 32)); @@ -15095,7 +15134,7 @@ std::uint8_t d2ce::Item::getInferiorQualityIdv100() const bool d2ce::Item::getMagicalAffixesv100(MagicalAffixes& affixes) const { affixes.clear(); - if ((dwa_bit_offset == 0) || (quality_attrib_bit_offset == 0) || (type_code_offset == 0)) + if ((item_id_bit_offset == 0) || (quality_attrib_bit_offset == 0) || (type_code_offset == 0)) { return false; } @@ -15117,7 +15156,7 @@ bool d2ce::Item::getMagicalAffixesv100(MagicalAffixes& affixes) const if (dwb_bit_offset == 0) { - dwb_bit_offset = dwa_bit_offset + 32; + dwb_bit_offset = item_id_bit_offset + 32; } std::array strcode = { 0, 0, 0, 0 }; @@ -15185,7 +15224,7 @@ bool d2ce::Item::getMagicalAttributesv100(std::vector& attribs { if (dwb_bit_offset == 0) { - dwb_bit_offset = dwa_bit_offset + 32; + dwb_bit_offset = item_id_bit_offset + 32; } return ItemHelpers::getSetMagicAttribs(setAttrib.Id, attribs, getVersion(), getGameVersion(), getLevel(), readBits(dwb_bit_offset, 32)); @@ -15197,7 +15236,7 @@ bool d2ce::Item::getMagicalAttributesv100(std::vector& attribs { if (dwb_bit_offset == 0) { - dwb_bit_offset = dwa_bit_offset + 32; + dwb_bit_offset = item_id_bit_offset + 32; } return ItemHelpers::getUniqueMagicAttribs(uniqueAttrib.Id, attribs, getVersion(), getGameVersion(), getLevel(), readBits(dwb_bit_offset, 32)); @@ -15231,7 +15270,7 @@ bool d2ce::Item::getMagicalAttributesv100(std::vector& attribs bool d2ce::Item::getRareOrCraftedAttributesv100(RareAttributes& attrib) const { attrib.clear(); - if ((dwa_bit_offset == 0) || (quality_attrib_bit_offset == 0) || (type_code_offset == 0)) + if ((item_id_bit_offset == 0) || (quality_attrib_bit_offset == 0) || (type_code_offset == 0)) { return false; } @@ -15264,7 +15303,7 @@ bool d2ce::Item::getRareOrCraftedAttributesv100(RareAttributes& attrib) const if (dwb_bit_offset == 0) { - dwb_bit_offset = dwa_bit_offset + 32; + dwb_bit_offset = item_id_bit_offset + 32; } std::array strcode = { 0, 0, 0, 0 }; @@ -15336,12 +15375,12 @@ std::uint8_t d2ce::Item::getPictureIdv100() const return 0; } - return std::uint8_t(ItemHelpers::generateDWARandomOffset(readBits(dwa_bit_offset, 32), 1) % modulo); + return std::uint8_t(ItemHelpers::generateDWARandomOffset(getId(), 1) % modulo); } //--------------------------------------------------------------------------- std::uint16_t d2ce::Item::getDefenseRatingv100() const { - if (dwa_bit_offset == 0) + if (item_id_bit_offset == 0) { return 0; } @@ -15352,7 +15391,7 @@ std::uint16_t d2ce::Item::getDefenseRatingv100() const return false; } - return ItemHelpers::generateDefenseRating(strcode, readBits(dwa_bit_offset, 32)); + return ItemHelpers::generateDefenseRating(strcode, getId()); } //--------------------------------------------------------------------------- void d2ce::Items::findItems() @@ -21423,7 +21462,7 @@ bool d2ce::Items::removeSocketedItems(d2ce::Item& item) return true; } //--------------------------------------------------------------------------- -bool d2ce::Items::setRuneword(d2ce::Item& item, std::uint16_t id) +bool d2ce::Items::setItemRuneword(d2ce::Item& item, std::uint16_t id) { if (item.getSocketedItemCount() == 0) { diff --git a/source/d2ce/Item.h b/source/d2ce/Item.h index 68ffd01c..068c6051 100644 --- a/source/d2ce/Item.h +++ b/source/d2ce/Item.h @@ -99,7 +99,6 @@ namespace d2ce size_t runeword_props_bit_offset = 0; size_t item_end_bit_offset = 0; size_t item_current_socket_idx = 0; // temp variable for socketed gem ordering - size_t dwa_bit_offset = 0; mutable size_t dwb_bit_offset = 0; mutable MagicalCachev100 magic_affixes_v100; mutable RareOrCraftedCachev100 rare_affixes_v100; @@ -234,6 +233,7 @@ namespace d2ce bool getRunewordAttributes(RunewordAttributes& attrib) const; std::string getPersonalizedName() const; std::uint8_t getTomeValue() const; // used in serialization + std::uint16_t getSetItemId() const; bool getSetAttributes(SetAttributes& attrib) const; bool getRareOrCraftedAttributes(RareAttributes& attrib) const; bool getUniqueAttributes(UniqueAttributes& attrib) const; @@ -524,7 +524,7 @@ namespace d2ce bool setItemLocation(d2ce::Item& item, const d2ce::Character& charInfo, EnumEquippedId equippedId, d2ce::EnumItemInventory invType, const d2ce::Item* &pRemovedItem); bool removeSocketedItems(d2ce::Item& item); - bool setRuneword(d2ce::Item& item, std::uint16_t id); + bool setItemRuneword(d2ce::Item& item, std::uint16_t id); bool getItemBonuses(std::vector& attribs) const; bool getDisplayedItemBonuses(std::vector& attribs, std::uint32_t charLevel) const; diff --git a/source/d2ce/SharedStash.cpp b/source/d2ce/SharedStash.cpp index f514d299..d61825f1 100644 --- a/source/d2ce/SharedStash.cpp +++ b/source/d2ce/SharedStash.cpp @@ -875,6 +875,22 @@ bool d2ce::SharedStash::removeItem(d2ce::Item& item) return false; } //--------------------------------------------------------------------------- +bool d2ce::SharedStash::setItemRuneword(d2ce::Item& item, std::uint16_t id) +{ + for (auto& page : Pages) + { + auto& pageStash = page.StashItems; + auto& inventory = pageStash.Inventory; + auto iter = std::find_if(inventory.begin(), inventory.end(), ItemPredicate(item)); + if (iter != inventory.end()) + { + return pageStash.setItemRuneword(item, id); + } + } + + return false; +} +//--------------------------------------------------------------------------- bool d2ce::SharedStash::refresh(std::FILE* charfile) { std::uint32_t fileSize = 0; diff --git a/source/d2ce/SharedStash.h b/source/d2ce/SharedStash.h index 3b4d1542..1d1b28b8 100644 --- a/source/d2ce/SharedStash.h +++ b/source/d2ce/SharedStash.h @@ -146,6 +146,7 @@ namespace d2ce bool setItemLocation(d2ce::Item& item, size_t itemPage, std::uint16_t positionX, std::uint16_t positionY, size_t page, const d2ce::Item*& pRemovedItem); bool removeSocketedItems(d2ce::Item& item); bool removeItem(d2ce::Item& item); + bool setItemRuneword(d2ce::Item& item, std::uint16_t id); protected: bool refresh(std::FILE* charfile); diff --git a/source/d2ce/helpers/ItemHelpers.cpp b/source/d2ce/helpers/ItemHelpers.cpp index fdaf9e68..3dec6e1e 100644 --- a/source/d2ce/helpers/ItemHelpers.cpp +++ b/source/d2ce/helpers/ItemHelpers.cpp @@ -48,6 +48,7 @@ namespace d2ce const ItemType& getInvalidItemTypeHelper(); + void initRunewordData(); std::string getRunewordNameFromId(std::uint16_t id); const d2ce::RunewordType& getRunewordFromId(std::uint16_t id); std::vector getPossibleRunewords(const d2ce::Item& item, bool bUseCurrentSocketCount = false, bool bExcludeServerOnly = true); @@ -58,6 +59,7 @@ namespace d2ce bool getUniqueQuestMagicAttribs(const std::array& strcode, std::vector& attribs, EnumItemVersion version, std::uint16_t gameVersion, std::uint16_t level, std::uint32_t dwb = 0); std::uint16_t getSetItemId(std::uint16_t id, const std::array& strcode); + std::uint32_t getSetItemDWBCode(std::uint16_t setItemId); std::uint32_t getSetItemDWBCode(std::uint16_t id, const std::array& strcode); std::uint8_t generateInferiorQualityId(std::uint16_t level, std::uint32_t dwb = 0); bool generateMagicalAffixes(const std::array& strcode, MagicalCachev100& cache, EnumItemVersion version, std::uint16_t gameVersion, std::uint16_t level, std::uint32_t dwb = 0); @@ -1711,10 +1713,11 @@ namespace d2ce break; case 16: // Level [sLvl] [skill] Aura When Equipped - strPos = strValue2.find("%s"); - if (strPos != strValue2.npos) + strPos = descstrpos.find("%s"); + if (strPos != descstrpos.npos) { - strValue2.replace(strPos, 2, "{0}"); + descstrpos.replace(strPos, 2, "{0}"); + descstrneg = descstrpos; ConvertPlaceHolders(descstrpos, descstrneg, bGenerateNeg, 1); } else @@ -1845,6 +1848,7 @@ namespace d2ce if (strPos != descstrpos.npos) { descstrpos.replace(strPos, 2, "{0}"); + descstrneg = descstrpos; ConvertPlaceHolders(descstrpos, descstrneg, false, 1); } else @@ -2728,7 +2732,7 @@ namespace d2ce std::uint16_t s_ItemCurTypeCodeIdx_v100 = 0; std::map s_ItemTypeCodes_v100; std::map s_ItemWeaponType; - const ItemType& GetWeaponItemType(std::string code) + const ItemType& GetWeaponItemType(const std::string& code) { auto iter = s_ItemWeaponType.find(code); if (iter != s_ItemWeaponType.end()) @@ -3293,7 +3297,7 @@ namespace d2ce } std::map s_ItemArmorType; - const ItemType& GetArmorItemType(std::string code) + const ItemType& GetArmorItemType(const std::string& code) { auto iter = s_ItemArmorType.find(code); if (iter != s_ItemArmorType.end()) @@ -4298,7 +4302,7 @@ namespace d2ce s_ItemMiscType.swap(itemMiscType); } - const d2ce::ItemType& GetItemTypeHelper(std::string code) + const d2ce::ItemType& GetItemTypeHelper(const std::string& code) { // Could be armor { @@ -5959,7 +5963,7 @@ namespace d2ce s_ItemSetItemsType.swap(itemSetItemsType); } - void ProcessMagicalProperites(const std::vector& modTypes, std::vector& magicalAttributes, ItemRandStruct& rnd, d2ce::EnumItemVersion version, std::uint16_t gameVersion) + void ProcessMagicalProperites(const std::vector& modTypes, std::vector& magicalAttributes, ItemRandStruct& rnd, d2ce::EnumItemVersion version, std::uint16_t gameVersion, bool bMaxAlways = false) { std::uint16_t func = 0; std::uint16_t val = 0; @@ -6064,6 +6068,10 @@ namespace d2ce { val = std::uint16_t(std::atoi(mod.val.c_str())); } + else + { + val = std::uint16_t(lastParam); + } bool bCalcValue = false; attrib.Id = iterName->second; @@ -6098,7 +6106,14 @@ namespace d2ce case 12: // random selection of parameters for parameter-based stat if (modMax > modMin) { - lastValue = std::uint16_t(GenerateRandom(rnd) % (modMax - modMin) + modMin); + if (bMaxAlways) + { + lastValue = modMax; + } + else + { + lastValue = std::uint16_t(GenerateRandom(rnd) % (modMax - modMin) + modMin); + } --numRndCalls; } else @@ -6171,7 +6186,14 @@ namespace d2ce { if (modMax > modMin) { - lastValue = std::uint16_t(GenerateRandom(rnd) % (modMax - modMin) + modMin); + if (bMaxAlways) + { + lastValue = modMax; + } + else + { + lastValue = std::uint16_t(GenerateRandom(rnd) % (modMax - modMin) + modMin); + } --numRndCalls; } else @@ -6916,6 +6938,18 @@ namespace d2ce strValue = doc.GetCellString(modParam[idx], i); if (!strValue.empty()) { + auto c = strValue[0]; + if ((c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z')) + { + // this must be a skill index name + const auto& skillInfo = CharClassHelper::getSkillByIndex(strValue); + if (skillInfo.id != MAXUINT16) + { + // convert to a skill ID + strValue = std::to_string(skillInfo.id); + } + } + mod.param = strValue; } @@ -6932,7 +6966,7 @@ namespace d2ce } } - ProcessMagicalProperites(mods, itemType.attribs, rnd, APP_ITEM_VERSION, APP_ITEM_GAME_VERSION); + ProcessMagicalProperites(mods, itemType.attribs, rnd, APP_ITEM_VERSION, APP_ITEM_GAME_VERSION, true); itemNumRunesRunewordsMap[std::uint8_t(itemType.runeCodes.size())].push_back(itemType.id); static std::map patchReleaseMap = { @@ -7029,7 +7063,7 @@ namespace d2ce { InitItemStatsData(txtReader); InitItemRarePrefixData(txtReader); - InitRunewordData(txtReader); + InitItemGemsTypeData(txtReader); } const std::map huffmanDecodeMap = { @@ -7783,6 +7817,50 @@ bool d2ce::ItemType::getSocketedMagicalAttributes(const d2ce::Item& item, std::v return false; } //--------------------------------------------------------------------------- +bool d2ce::ItemType::getRuneMagicalAttributes(const d2ce::Item& parentItem, std::vector& attribs) const +{ + attribs.clear(); + std::uint8_t parentGemApplyType = parentItem.getGemApplyType(); + if (!isRune()) + { + return false; + } + + auto iter = s_ItemGemsType.find(code); + if (iter == s_ItemGemsType.end()) + { + // should not happen + return false; + } + switch (parentGemApplyType) + { + case 0: + attribs = iter->second.weaponAttribs; + break; + + case 1: + attribs = iter->second.helmAttribs; + break; + + case 2: + attribs = iter->second.shieldAttribs; + break; + + default: + return false; + } + + auto itemVersion = parentItem.getVersion(); + auto gameVersion = parentItem.getGameVersion(); + for (auto& attrib : attribs) + { + attrib.Version = itemVersion; + attrib.GameVersion = gameVersion; + } + + return attribs.empty() ? false : true; +} +//--------------------------------------------------------------------------- std::string d2ce::ItemType::getPotionDesc(d2ce::EnumCharClass charClass) const { if (!isPotion()) @@ -8399,11 +8477,22 @@ const d2ce::ItemType& d2ce::ItemHelpers::getItemTypeHelper(const std::array d2ce::ItemHelpers::getPossibleRunewords(const d2 continue; } - if (itemVersion > runeword.version) + if (itemVersion < runeword.version) { // skip continue; @@ -8656,6 +8745,17 @@ std::uint16_t d2ce::ItemHelpers::getSetItemId(std::uint16_t id, const std::array return MAXUINT16; } //--------------------------------------------------------------------------- +std::uint32_t d2ce::ItemHelpers::getSetItemDWBCode(std::uint16_t setItemId) +{ + auto iter = s_ItemSetItemsType.find(setItemId); + if (iter == s_ItemSetItemsType.end()) + { + return false; + } + + return iter->second.dwbCode; +} +//--------------------------------------------------------------------------- std::uint32_t d2ce::ItemHelpers::getSetItemDWBCode(std::uint16_t id, const std::array& strcode) { const auto& setItem = GetSetItemType(id, strcode); @@ -9561,6 +9661,22 @@ void d2ce::ItemHelpers::applyMaxMagicalAttributes(CharStats& cs, std::vector& attribs, std::uint32_t charLevel) +{ + // check for the "all" cases + ItemHelpers::checkForRelatedMagicalAttributes(attribs); + + bool bFormatted = false; + for (auto& attrib : attribs) + { + bFormatted |= ItemHelpers::formatDisplayedMagicalAttribute(attrib, charLevel); + } + + // Sort display items in proper order + std::sort(attribs.begin(), attribs.end(), ItemHelpers::magicalAttributeSorter); + return bFormatted; +} +//--------------------------------------------------------------------------- std::string d2ce::ItemHelpers::formatMagicalAttributeValue(MagicalAttribute& attrib, std::uint32_t charLevel, size_t idx, const ItemStat& stat) { std::string strSkill; diff --git a/source/d2ce/helpers/ItemHelpers.h b/source/d2ce/helpers/ItemHelpers.h index 28c5dd51..e64c3f85 100644 --- a/source/d2ce/helpers/ItemHelpers.h +++ b/source/d2ce/helpers/ItemHelpers.h @@ -53,6 +53,7 @@ namespace d2ce const bool hasItemStat(const MagicalAttribute& attrib); const ItemType& getItemTypeHelper(const std::array& strcode); + const ItemType& getItemTypeHelper(const std::string& code); void getValidGPSCodes(std::vector & gpsCodes, bool isExpansion = true); std::uint16_t getGPSSortIndex(const std::array& strcode); @@ -60,6 +61,7 @@ namespace d2ce std::int64_t getMagicalAttributeValue(MagicalAttribute& attrib, std::uint32_t charLevel, size_t idx, const ItemStat& stat); void applyNonMaxMagicalAttributes(CharStats& cs, std::vector& attribs); void applyMaxMagicalAttributes(CharStats& cs, std::vector& attribs); + bool formatMagicalAttributes(std::vector& attribs, std::uint32_t charLevel); } //--------------------------------------------------------------------------- diff --git a/source/examples/chars/71/Amazon.json b/source/examples/chars/71/Amazon.json index 6edf98d8..1482d30c 100644 --- a/source/examples/chars/71/Amazon.json +++ b/source/examples/chars/71/Amazon.json @@ -1690,7 +1690,7 @@ ], "type_id": 3, "nr_of_items_in_sockets": 0, - "id": 0, + "id": 326191941, "level": 1, "dwa": 326191941, "dwb": 1912823919, @@ -1782,7 +1782,7 @@ ], "type_id": 2, "nr_of_items_in_sockets": 0, - "id": 0, + "id": 1351972249, "level": 1, "dwa": 1351972249, "dwb": 791120579, diff --git a/source/examples/chars/71/Barbarian.json b/source/examples/chars/71/Barbarian.json index 58444188..bac02c6d 100644 --- a/source/examples/chars/71/Barbarian.json +++ b/source/examples/chars/71/Barbarian.json @@ -1686,7 +1686,7 @@ ], "type_id": 3, "nr_of_items_in_sockets": 0, - "id": 0, + "id": 532966060, "level": 1, "dwa": 532966060, "dwb": 2119598038, @@ -1777,7 +1777,7 @@ ], "type_id": 2, "nr_of_items_in_sockets": 0, - "id": 0, + "id": 1558746368, "level": 1, "dwa": 1558746368, "dwb": 997894698, diff --git a/source/examples/chars/71/Bow.json b/source/examples/chars/71/Bow.json index 8db91ebb..18cae5e6 100644 --- a/source/examples/chars/71/Bow.json +++ b/source/examples/chars/71/Bow.json @@ -1215,7 +1215,7 @@ ], "type_id": 2, "nr_of_items_in_sockets": 0, - "id": 0, + "id": 404509761, "level": 74, "dwa": 404509761, "dwb": 848522065, @@ -1307,7 +1307,7 @@ ], "type_id": 3, "nr_of_items_in_sockets": 0, - "id": 0, + "id": 616310706, "level": 43, "dwa": 616310706, "dwb": 1229399308, diff --git a/source/examples/chars/71/Necromancer.json b/source/examples/chars/71/Necromancer.json index 4680133b..8ce70631 100644 --- a/source/examples/chars/71/Necromancer.json +++ b/source/examples/chars/71/Necromancer.json @@ -1688,7 +1688,7 @@ ], "type_id": 3, "nr_of_items_in_sockets": 0, - "id": 0, + "id": 1880035393, "level": 1, "dwa": 1880035393, "dwb": 1319183723, diff --git a/source/examples/chars/71/Paladin.json b/source/examples/chars/71/Paladin.json index 47b1ec22..dd080ab9 100644 --- a/source/examples/chars/71/Paladin.json +++ b/source/examples/chars/71/Paladin.json @@ -1687,7 +1687,7 @@ ], "type_id": 3, "nr_of_items_in_sockets": 0, - "id": 0, + "id": 1189196966, "level": 1, "dwa": 1189196966, "dwb": 628345296, @@ -1778,7 +1778,7 @@ ], "type_id": 2, "nr_of_items_in_sockets": 0, - "id": 0, + "id": 67493626, "level": 1, "dwa": 67493626, "dwb": 1654125604, diff --git a/source/examples/chars/71/Sorceress.json b/source/examples/chars/71/Sorceress.json index 4a10f188..d212b770 100644 --- a/source/examples/chars/71/Sorceress.json +++ b/source/examples/chars/71/Sorceress.json @@ -1688,7 +1688,7 @@ ], "type_id": 3, "nr_of_items_in_sockets": 0, - "id": 0, + "id": 1831800845, "level": 1, "dwa": 1831800845, "dwb": 1270949175, diff --git a/source/examples/chars/87/testtt.json b/source/examples/chars/87/testtt.json index 473362d0..54c7c025 100644 --- a/source/examples/chars/87/testtt.json +++ b/source/examples/chars/87/testtt.json @@ -15,6 +15,7 @@ "level": 1, "assigned_skills": [ null, + "Attack", null, "Attack", null, @@ -34,7 +35,7 @@ "right_skill": "Attack", "menu_appearance": { "head": { - "graphic": 0, + "graphic": 255, "tint": 255 }, "torso": { @@ -54,19 +55,19 @@ "tint": 255 }, "right_hand": { - "graphic": 255, + "graphic": 4, "tint": 255 }, "left_hand": { - "graphic": 4, + "graphic": 255, "tint": 255 }, "shield": { - "graphic": 255, + "graphic": 79, "tint": 255 }, "special1": { - "graphic": 79, + "graphic": 255, "tint": 255 }, "special2": { diff --git a/source/examples/chars/89/fddfss.json b/source/examples/chars/89/fddfss.json index 74053e25..dbda45f7 100644 --- a/source/examples/chars/89/fddfss.json +++ b/source/examples/chars/89/fddfss.json @@ -15,6 +15,7 @@ "level": 1, "assigned_skills": [ null, + "Attack", null, "Attack", null, @@ -34,7 +35,7 @@ "right_skill": "Attack", "menu_appearance": { "head": { - "graphic": 0, + "graphic": 255, "tint": 255 }, "torso": { @@ -54,19 +55,19 @@ "tint": 255 }, "right_hand": { - "graphic": 255, + "graphic": 4, "tint": 255 }, "left_hand": { - "graphic": 4, + "graphic": 255, "tint": 255 }, "shield": { - "graphic": 255, + "graphic": 79, "tint": 255 }, "special1": { - "graphic": 79, + "graphic": 255, "tint": 255 }, "special2": { diff --git a/source/examples/chars/96/Blizzard.json b/source/examples/chars/96/Blizzard.json index 8ef89d04..c9e56a35 100644 --- a/source/examples/chars/96/Blizzard.json +++ b/source/examples/chars/96/Blizzard.json @@ -17768,7 +17768,7 @@ 13 ], "name": "item_aura", - "description": "Level {0} {1} Aura When Equipped" + "description": "Level {1} {0} Aura When Equipped" }, { "id": 198, @@ -18331,7 +18331,7 @@ 13 ], "name": "item_aura", - "description": "Level Redemption 13 Aura When Equipped" + "description": "Level 13 Redemption Aura When Equipped" }, { "id": 17, @@ -18408,7 +18408,7 @@ 13 ], "name": "item_aura", - "description": "Level {0} {1} Aura When Equipped" + "description": "Level {1} {0} Aura When Equipped" }, { "id": 198, @@ -18491,7 +18491,7 @@ 13 ], "name": "item_aura", - "description": "Level Redemption 13 Aura When Equipped" + "description": "Level 13 Redemption Aura When Equipped" }, { "id": 17, diff --git a/source/examples/chars/96/BowAma.json b/source/examples/chars/96/BowAma.json index e37faace..ed53cc08 100644 --- a/source/examples/chars/96/BowAma.json +++ b/source/examples/chars/96/BowAma.json @@ -9742,7 +9742,7 @@ 15 ], "name": "item_aura", - "description": "Level {0} {1} Aura When Equipped" + "description": "Level {1} {0} Aura When Equipped" }, { "id": 155, @@ -10311,7 +10311,7 @@ 15 ], "name": "item_aura", - "description": "Level Fanaticism 15 Aura When Equipped" + "description": "Level 15 Fanaticism Aura When Equipped" }, { "id": 127, @@ -10465,7 +10465,7 @@ 15 ], "name": "item_aura", - "description": "Level {0} {1} Aura When Equipped" + "description": "Level {1} {0} Aura When Equipped" }, { "id": 155, @@ -10523,7 +10523,7 @@ 15 ], "name": "item_aura", - "description": "Level Fanaticism 15 Aura When Equipped" + "description": "Level 15 Fanaticism Aura When Equipped" }, { "id": 127, diff --git a/source/examples/chars/96/Fire.json b/source/examples/chars/96/Fire.json index f81c203c..fdb38073 100644 --- a/source/examples/chars/96/Fire.json +++ b/source/examples/chars/96/Fire.json @@ -17373,7 +17373,7 @@ 12 ], "name": "item_aura", - "description": "Level {0} {1} Aura When Equipped" + "description": "Level {1} {0} Aura When Equipped" }, { "id": 198, @@ -18023,7 +18023,7 @@ 12 ], "name": "item_aura", - "description": "Level Holy Freeze 12 Aura When Equipped" + "description": "Level 12 Holy Freeze Aura When Equipped" }, { "id": 127, @@ -18116,7 +18116,7 @@ 12 ], "name": "item_aura", - "description": "Level {0} {1} Aura When Equipped" + "description": "Level {1} {0} Aura When Equipped" }, { "id": 198, @@ -18186,7 +18186,7 @@ 12 ], "name": "item_aura", - "description": "Level Holy Freeze 12 Aura When Equipped" + "description": "Level 12 Holy Freeze Aura When Equipped" }, { "id": 127, diff --git a/source/examples/chars/96/FireClaw.json b/source/examples/chars/96/FireClaw.json index 8c430ed6..2af50284 100644 --- a/source/examples/chars/96/FireClaw.json +++ b/source/examples/chars/96/FireClaw.json @@ -20291,7 +20291,7 @@ 13 ], "name": "item_aura", - "description": "Level {0} {1} Aura When Equipped" + "description": "Level {1} {0} Aura When Equipped" } ], "base_damage": { @@ -20549,7 +20549,7 @@ 13 ], "name": "item_aura", - "description": "Level Sanctuary 13 Aura When Equipped" + "description": "Level 13 Sanctuary Aura When Equipped" }, { "id": 127, @@ -20732,7 +20732,7 @@ 13 ], "name": "item_aura", - "description": "Level {0} {1} Aura When Equipped" + "description": "Level {1} {0} Aura When Equipped" }, { "id": 197, @@ -20779,7 +20779,7 @@ 13 ], "name": "item_aura", - "description": "Level Sanctuary 13 Aura When Equipped" + "description": "Level 13 Sanctuary Aura When Equipped" }, { "id": 127, diff --git a/source/examples/chars/96/Fist_YoU.json b/source/examples/chars/96/Fist_YoU.json index f35c0be9..d3bf2da5 100644 --- a/source/examples/chars/96/Fist_YoU.json +++ b/source/examples/chars/96/Fist_YoU.json @@ -8875,7 +8875,7 @@ 31 ], "name": "item_aura", - "description": "Level {0} {1} Aura When Equipped" + "description": "Level {1} {0} Aura When Equipped" }, { "id": 155, @@ -8947,7 +8947,7 @@ 31 ], "name": "item_aura", - "description": "Level Summon Resist 31 Aura When Equipped" + "description": "Level 31 Summon Resist Aura When Equipped" }, { "id": 156, @@ -9206,7 +9206,7 @@ 31 ], "name": "item_aura", - "description": "Level {0} {1} Aura When Equipped" + "description": "Level {1} {0} Aura When Equipped" }, { "id": 155, @@ -9271,7 +9271,7 @@ 31 ], "name": "item_aura", - "description": "Level Summon Resist 31 Aura When Equipped" + "description": "Level 31 Summon Resist Aura When Equipped" }, { "id": 156, @@ -23304,7 +23304,7 @@ 31 ], "name": "item_aura", - "description": "Level {0} {1} Aura When Equipped" + "description": "Level {1} {0} Aura When Equipped" }, { "id": 151, @@ -23313,7 +23313,7 @@ 31 ], "name": "item_aura", - "description": "Level {0} {1} Aura When Equipped" + "description": "Level {1} {0} Aura When Equipped" }, { "id": 151, @@ -23322,7 +23322,7 @@ 31 ], "name": "item_aura", - "description": "Level {0} {1} Aura When Equipped" + "description": "Level {1} {0} Aura When Equipped" }, { "id": 336, @@ -23347,7 +23347,7 @@ 31 ], "name": "item_aura", - "description": "Level Resist Lightning 31 Aura When Equipped" + "description": "Level 31 Resist Lightning Aura When Equipped" }, { "id": 151, @@ -23356,7 +23356,7 @@ 31 ], "name": "item_aura", - "description": "Level Resist Cold 31 Aura When Equipped" + "description": "Level 31 Resist Cold Aura When Equipped" }, { "id": 151, @@ -23365,7 +23365,7 @@ 31 ], "name": "item_aura", - "description": "Level Resist Fire 31 Aura When Equipped" + "description": "Level 31 Resist Fire Aura When Equipped" }, { "id": 127, @@ -23851,7 +23851,7 @@ 31 ], "name": "item_aura", - "description": "Level {0} {1} Aura When Equipped" + "description": "Level {1} {0} Aura When Equipped" }, { "id": 151, @@ -23860,7 +23860,7 @@ 31 ], "name": "item_aura", - "description": "Level {0} {1} Aura When Equipped" + "description": "Level {1} {0} Aura When Equipped" }, { "id": 151, @@ -23869,7 +23869,7 @@ 31 ], "name": "item_aura", - "description": "Level {0} {1} Aura When Equipped" + "description": "Level {1} {0} Aura When Equipped" }, { "id": 336, @@ -23888,7 +23888,7 @@ 31 ], "name": "item_aura", - "description": "Level Resist Lightning 31 Aura When Equipped" + "description": "Level 31 Resist Lightning Aura When Equipped" }, { "id": 151, @@ -23897,7 +23897,7 @@ 31 ], "name": "item_aura", - "description": "Level Resist Cold 31 Aura When Equipped" + "description": "Level 31 Resist Cold Aura When Equipped" }, { "id": 151, @@ -23906,7 +23906,7 @@ 31 ], "name": "item_aura", - "description": "Level Resist Fire 31 Aura When Equipped" + "description": "Level 31 Resist Fire Aura When Equipped" }, { "id": 127, @@ -31608,7 +31608,7 @@ 31 ], "name": "item_aura", - "description": "Level {0} {1} Aura When Equipped" + "description": "Level {1} {0} Aura When Equipped" }, { "id": 151, @@ -31617,7 +31617,7 @@ 31 ], "name": "item_aura", - "description": "Level {0} {1} Aura When Equipped" + "description": "Level {1} {0} Aura When Equipped" }, { "id": 151, @@ -31626,7 +31626,7 @@ 31 ], "name": "item_aura", - "description": "Level {0} {1} Aura When Equipped" + "description": "Level {1} {0} Aura When Equipped" }, { "id": 151, @@ -31635,7 +31635,7 @@ 31 ], "name": "item_aura", - "description": "Level {0} {1} Aura When Equipped" + "description": "Level {1} {0} Aura When Equipped" }, { "id": 151, @@ -31644,7 +31644,7 @@ 31 ], "name": "item_aura", - "description": "Level {0} {1} Aura When Equipped" + "description": "Level {1} {0} Aura When Equipped" }, { "id": 151, @@ -31653,7 +31653,7 @@ 31 ], "name": "item_aura", - "description": "Level {0} {1} Aura When Equipped" + "description": "Level {1} {0} Aura When Equipped" } ], "base_damage": { @@ -34217,7 +34217,7 @@ 31 ], "name": "item_aura", - "description": "Level Conviction 31 Aura When Equipped" + "description": "Level 31 Conviction Aura When Equipped" }, { "id": 151, @@ -34226,7 +34226,7 @@ 31 ], "name": "item_aura", - "description": "Level Sanctuary 31 Aura When Equipped" + "description": "Level 31 Sanctuary Aura When Equipped" }, { "id": 151, @@ -34235,7 +34235,7 @@ 31 ], "name": "item_aura", - "description": "Level Vigor 31 Aura When Equipped" + "description": "Level 31 Vigor Aura When Equipped" }, { "id": 151, @@ -34244,7 +34244,7 @@ 31 ], "name": "item_aura", - "description": "Level Holy Freeze 31 Aura When Equipped" + "description": "Level 31 Holy Freeze Aura When Equipped" }, { "id": 151, @@ -34253,7 +34253,7 @@ 31 ], "name": "item_aura", - "description": "Level Concentration 31 Aura When Equipped" + "description": "Level 31 Concentration Aura When Equipped" }, { "id": 151, @@ -34262,7 +34262,7 @@ 31 ], "name": "item_aura", - "description": "Level Sacrifice 31 Aura When Equipped" + "description": "Level 31 Sacrifice Aura When Equipped" }, { "id": 127, @@ -34342,7 +34342,7 @@ 31 ], "name": "item_aura", - "description": "Level {0} {1} Aura When Equipped" + "description": "Level {1} {0} Aura When Equipped" }, { "id": 151, @@ -34351,7 +34351,7 @@ 31 ], "name": "item_aura", - "description": "Level {0} {1} Aura When Equipped" + "description": "Level {1} {0} Aura When Equipped" }, { "id": 151, @@ -34360,7 +34360,7 @@ 31 ], "name": "item_aura", - "description": "Level {0} {1} Aura When Equipped" + "description": "Level {1} {0} Aura When Equipped" }, { "id": 151, @@ -34369,7 +34369,7 @@ 31 ], "name": "item_aura", - "description": "Level {0} {1} Aura When Equipped" + "description": "Level {1} {0} Aura When Equipped" }, { "id": 151, @@ -34378,7 +34378,7 @@ 31 ], "name": "item_aura", - "description": "Level {0} {1} Aura When Equipped" + "description": "Level {1} {0} Aura When Equipped" }, { "id": 151, @@ -34387,7 +34387,7 @@ 31 ], "name": "item_aura", - "description": "Level {0} {1} Aura When Equipped" + "description": "Level {1} {0} Aura When Equipped" }, { "id": 7, @@ -34535,7 +34535,7 @@ 31 ], "name": "item_aura", - "description": "Level Conviction 31 Aura When Equipped" + "description": "Level 31 Conviction Aura When Equipped" }, { "id": 151, @@ -34544,7 +34544,7 @@ 31 ], "name": "item_aura", - "description": "Level Sanctuary 31 Aura When Equipped" + "description": "Level 31 Sanctuary Aura When Equipped" }, { "id": 151, @@ -34553,7 +34553,7 @@ 31 ], "name": "item_aura", - "description": "Level Vigor 31 Aura When Equipped" + "description": "Level 31 Vigor Aura When Equipped" }, { "id": 151, @@ -34562,7 +34562,7 @@ 31 ], "name": "item_aura", - "description": "Level Holy Freeze 31 Aura When Equipped" + "description": "Level 31 Holy Freeze Aura When Equipped" }, { "id": 151, @@ -34571,7 +34571,7 @@ 31 ], "name": "item_aura", - "description": "Level Concentration 31 Aura When Equipped" + "description": "Level 31 Concentration Aura When Equipped" }, { "id": 151, @@ -34580,7 +34580,7 @@ 31 ], "name": "item_aura", - "description": "Level Sacrifice 31 Aura When Equipped" + "description": "Level 31 Sacrifice Aura When Equipped" }, { "id": 127, diff --git a/source/examples/chars/96/FukK_U.json b/source/examples/chars/96/FukK_U.json index 76cd2063..d43b230e 100644 --- a/source/examples/chars/96/FukK_U.json +++ b/source/examples/chars/96/FukK_U.json @@ -2512,7 +2512,7 @@ 31 ], "name": "item_aura", - "description": "Level {0} {1} Aura When Equipped" + "description": "Level {1} {0} Aura When Equipped" }, { "id": 156, @@ -2655,7 +2655,7 @@ 31 ], "name": "item_aura", - "description": "Level Fanaticism 31 Aura When Equipped" + "description": "Level 31 Fanaticism Aura When Equipped" }, { "id": 127, @@ -2998,7 +2998,7 @@ 31 ], "name": "item_aura", - "description": "Level {0} {1} Aura When Equipped" + "description": "Level {1} {0} Aura When Equipped" }, { "id": 156, @@ -3134,7 +3134,7 @@ 31 ], "name": "item_aura", - "description": "Level Fanaticism 31 Aura When Equipped" + "description": "Level 31 Fanaticism Aura When Equipped" }, { "id": 127, @@ -8053,7 +8053,7 @@ 31 ], "name": "item_aura", - "description": "Level {0} {1} Aura When Equipped" + "description": "Level {1} {0} Aura When Equipped" }, { "id": 156, @@ -8185,7 +8185,7 @@ 31 ], "name": "item_aura", - "description": "Level Thorns 31 Aura When Equipped" + "description": "Level 31 Thorns Aura When Equipped" }, { "id": 96, @@ -8631,7 +8631,7 @@ 31 ], "name": "item_aura", - "description": "Level {0} {1} Aura When Equipped" + "description": "Level {1} {0} Aura When Equipped" }, { "id": 156, @@ -8758,7 +8758,7 @@ 31 ], "name": "item_aura", - "description": "Level Thorns 31 Aura When Equipped" + "description": "Level 31 Thorns Aura When Equipped" }, { "id": 96, @@ -9246,7 +9246,7 @@ 31 ], "name": "item_aura", - "description": "Level {0} {1} Aura When Equipped" + "description": "Level {1} {0} Aura When Equipped" }, { "id": 156, @@ -9389,7 +9389,7 @@ 31 ], "name": "item_aura", - "description": "Level Concentration 31 Aura When Equipped" + "description": "Level 31 Concentration Aura When Equipped" }, { "id": 83, @@ -9805,7 +9805,7 @@ 31 ], "name": "item_aura", - "description": "Level {0} {1} Aura When Equipped" + "description": "Level {1} {0} Aura When Equipped" }, { "id": 156, @@ -9944,7 +9944,7 @@ 31 ], "name": "item_aura", - "description": "Level Concentration 31 Aura When Equipped" + "description": "Level 31 Concentration Aura When Equipped" }, { "id": 83, @@ -10433,7 +10433,7 @@ 31 ], "name": "item_aura", - "description": "Level {0} {1} Aura When Equipped" + "description": "Level {1} {0} Aura When Equipped" }, { "id": 156, @@ -10576,7 +10576,7 @@ 31 ], "name": "item_aura", - "description": "Level Might 31 Aura When Equipped" + "description": "Level 31 Might Aura When Equipped" }, { "id": 83, @@ -10992,7 +10992,7 @@ 31 ], "name": "item_aura", - "description": "Level {0} {1} Aura When Equipped" + "description": "Level {1} {0} Aura When Equipped" }, { "id": 156, @@ -11131,7 +11131,7 @@ 31 ], "name": "item_aura", - "description": "Level Might 31 Aura When Equipped" + "description": "Level 31 Might Aura When Equipped" }, { "id": 83, @@ -45744,7 +45744,7 @@ 13 ], "name": "item_aura", - "description": "Level {0} {1} Aura When Equipped" + "description": "Level {1} {0} Aura When Equipped" }, { "id": 198, @@ -46307,7 +46307,7 @@ 13 ], "name": "item_aura", - "description": "Level Redemption 13 Aura When Equipped" + "description": "Level 13 Redemption Aura When Equipped" }, { "id": 17, @@ -46384,7 +46384,7 @@ 13 ], "name": "item_aura", - "description": "Level {0} {1} Aura When Equipped" + "description": "Level {1} {0} Aura When Equipped" }, { "id": 198, @@ -46467,7 +46467,7 @@ 13 ], "name": "item_aura", - "description": "Level Redemption 13 Aura When Equipped" + "description": "Level 13 Redemption Aura When Equipped" }, { "id": 17, diff --git a/source/examples/chars/96/Orb.json b/source/examples/chars/96/Orb.json index b5075935..588112aa 100644 --- a/source/examples/chars/96/Orb.json +++ b/source/examples/chars/96/Orb.json @@ -17750,7 +17750,7 @@ 13 ], "name": "item_aura", - "description": "Level {0} {1} Aura When Equipped" + "description": "Level {1} {0} Aura When Equipped" }, { "id": 198, @@ -18313,7 +18313,7 @@ 13 ], "name": "item_aura", - "description": "Level Redemption 13 Aura When Equipped" + "description": "Level 13 Redemption Aura When Equipped" }, { "id": 17, @@ -18390,7 +18390,7 @@ 13 ], "name": "item_aura", - "description": "Level {0} {1} Aura When Equipped" + "description": "Level {1} {0} Aura When Equipped" }, { "id": 198, @@ -18473,7 +18473,7 @@ 13 ], "name": "item_aura", - "description": "Level Redemption 13 Aura When Equipped" + "description": "Level 13 Redemption Aura When Equipped" }, { "id": 17, diff --git a/source/examples/chars/96/Smiter.json b/source/examples/chars/96/Smiter.json index 639de195..30f91c38 100644 --- a/source/examples/chars/96/Smiter.json +++ b/source/examples/chars/96/Smiter.json @@ -18493,7 +18493,7 @@ 14 ], "name": "item_aura", - "description": "Level {0} {1} Aura When Equipped" + "description": "Level {1} {0} Aura When Equipped" }, { "id": 188, @@ -19140,7 +19140,7 @@ 14 ], "name": "item_aura", - "description": "Level Defiance 14 Aura When Equipped" + "description": "Level 14 Defiance Aura When Equipped" }, { "id": 188, @@ -19266,7 +19266,7 @@ 14 ], "name": "item_aura", - "description": "Level {0} {1} Aura When Equipped" + "description": "Level {1} {0} Aura When Equipped" }, { "id": 188, @@ -19347,7 +19347,7 @@ 14 ], "name": "item_aura", - "description": "Level Defiance 14 Aura When Equipped" + "description": "Level 14 Defiance Aura When Equipped" }, { "id": 188, diff --git a/source/examples/chars/96/Summon.json b/source/examples/chars/96/Summon.json index 5ad7b69b..935deaa3 100644 --- a/source/examples/chars/96/Summon.json +++ b/source/examples/chars/96/Summon.json @@ -10052,7 +10052,7 @@ 12 ], "name": "item_aura", - "description": "Level {0} {1} Aura When Equipped" + "description": "Level {1} {0} Aura When Equipped" }, { "id": 198, @@ -10702,7 +10702,7 @@ 12 ], "name": "item_aura", - "description": "Level Holy Freeze 12 Aura When Equipped" + "description": "Level 12 Holy Freeze Aura When Equipped" }, { "id": 127, @@ -10795,7 +10795,7 @@ 12 ], "name": "item_aura", - "description": "Level {0} {1} Aura When Equipped" + "description": "Level {1} {0} Aura When Equipped" }, { "id": 198, @@ -10865,7 +10865,7 @@ 12 ], "name": "item_aura", - "description": "Level Holy Freeze 12 Aura When Equipped" + "description": "Level 12 Holy Freeze Aura When Equipped" }, { "id": 127, @@ -18448,7 +18448,7 @@ 13 ], "name": "item_aura", - "description": "Level {0} {1} Aura When Equipped" + "description": "Level {1} {0} Aura When Equipped" }, { "id": 198, @@ -19011,7 +19011,7 @@ 13 ], "name": "item_aura", - "description": "Level Redemption 13 Aura When Equipped" + "description": "Level 13 Redemption Aura When Equipped" }, { "id": 17, @@ -19088,7 +19088,7 @@ 13 ], "name": "item_aura", - "description": "Level {0} {1} Aura When Equipped" + "description": "Level {1} {0} Aura When Equipped" }, { "id": 198, @@ -19171,7 +19171,7 @@ 13 ], "name": "item_aura", - "description": "Level Redemption 13 Aura When Equipped" + "description": "Level 13 Redemption Aura When Equipped" }, { "id": 17, diff --git a/source/examples/chars/96/TollWut.json b/source/examples/chars/96/TollWut.json index 6663a790..abcf4d0b 100644 --- a/source/examples/chars/96/TollWut.json +++ b/source/examples/chars/96/TollWut.json @@ -17369,7 +17369,7 @@ 15 ], "name": "item_aura", - "description": "Level {0} {1} Aura When Equipped" + "description": "Level {1} {0} Aura When Equipped" }, { "id": 155, @@ -17918,7 +17918,7 @@ 15 ], "name": "item_aura", - "description": "Level Fanaticism 15 Aura When Equipped" + "description": "Level 15 Fanaticism Aura When Equipped" }, { "id": 127, @@ -18062,7 +18062,7 @@ 15 ], "name": "item_aura", - "description": "Level {0} {1} Aura When Equipped" + "description": "Level {1} {0} Aura When Equipped" }, { "id": 155, @@ -18120,7 +18120,7 @@ 15 ], "name": "item_aura", - "description": "Level Fanaticism 15 Aura When Equipped" + "description": "Level 15 Fanaticism Aura When Equipped" }, { "id": 127, diff --git a/source/examples/chars/97/DannyIsGreatIII.json b/source/examples/chars/97/DannyIsGreatIII.json index b277c9f4..bd3ff8c3 100644 --- a/source/examples/chars/97/DannyIsGreatIII.json +++ b/source/examples/chars/97/DannyIsGreatIII.json @@ -3874,7 +3874,7 @@ 31 ], "name": "item_aura", - "description": "Level {0} {1} Aura When Equipped" + "description": "Level {1} {0} Aura When Equipped" }, { "id": 216, @@ -3978,7 +3978,7 @@ 31 ], "name": "item_aura", - "description": "Level Conviction 31 Aura When Equipped" + "description": "Level 31 Conviction Aura When Equipped" }, { "id": 127, @@ -4594,7 +4594,7 @@ 31 ], "name": "item_aura", - "description": "Level {0} {1} Aura When Equipped" + "description": "Level {1} {0} Aura When Equipped" }, { "id": 216, @@ -4693,7 +4693,7 @@ 31 ], "name": "item_aura", - "description": "Level Conviction 31 Aura When Equipped" + "description": "Level 31 Conviction Aura When Equipped" }, { "id": 127, @@ -5385,7 +5385,7 @@ 31 ], "name": "item_aura", - "description": "Level {0} {1} Aura When Equipped" + "description": "Level {1} {0} Aura When Equipped" }, { "id": 216, @@ -5489,7 +5489,7 @@ 31 ], "name": "item_aura", - "description": "Level Conviction 31 Aura When Equipped" + "description": "Level 31 Conviction Aura When Equipped" }, { "id": 127, @@ -6105,7 +6105,7 @@ 31 ], "name": "item_aura", - "description": "Level {0} {1} Aura When Equipped" + "description": "Level {1} {0} Aura When Equipped" }, { "id": 216, @@ -6204,7 +6204,7 @@ 31 ], "name": "item_aura", - "description": "Level Conviction 31 Aura When Equipped" + "description": "Level 31 Conviction Aura When Equipped" }, { "id": 127, @@ -6896,7 +6896,7 @@ 31 ], "name": "item_aura", - "description": "Level {0} {1} Aura When Equipped" + "description": "Level {1} {0} Aura When Equipped" }, { "id": 216, @@ -7000,7 +7000,7 @@ 31 ], "name": "item_aura", - "description": "Level Conviction 31 Aura When Equipped" + "description": "Level 31 Conviction Aura When Equipped" }, { "id": 127, @@ -7616,7 +7616,7 @@ 31 ], "name": "item_aura", - "description": "Level {0} {1} Aura When Equipped" + "description": "Level {1} {0} Aura When Equipped" }, { "id": 216, @@ -7715,7 +7715,7 @@ 31 ], "name": "item_aura", - "description": "Level Conviction 31 Aura When Equipped" + "description": "Level 31 Conviction Aura When Equipped" }, { "id": 127, @@ -8407,7 +8407,7 @@ 31 ], "name": "item_aura", - "description": "Level {0} {1} Aura When Equipped" + "description": "Level {1} {0} Aura When Equipped" }, { "id": 216, @@ -8511,7 +8511,7 @@ 31 ], "name": "item_aura", - "description": "Level Conviction 31 Aura When Equipped" + "description": "Level 31 Conviction Aura When Equipped" }, { "id": 127, @@ -9127,7 +9127,7 @@ 31 ], "name": "item_aura", - "description": "Level {0} {1} Aura When Equipped" + "description": "Level {1} {0} Aura When Equipped" }, { "id": 216, @@ -9226,7 +9226,7 @@ 31 ], "name": "item_aura", - "description": "Level Conviction 31 Aura When Equipped" + "description": "Level 31 Conviction Aura When Equipped" }, { "id": 127, @@ -9918,7 +9918,7 @@ 31 ], "name": "item_aura", - "description": "Level {0} {1} Aura When Equipped" + "description": "Level {1} {0} Aura When Equipped" }, { "id": 216, @@ -10022,7 +10022,7 @@ 31 ], "name": "item_aura", - "description": "Level Conviction 31 Aura When Equipped" + "description": "Level 31 Conviction Aura When Equipped" }, { "id": 127, @@ -10638,7 +10638,7 @@ 31 ], "name": "item_aura", - "description": "Level {0} {1} Aura When Equipped" + "description": "Level {1} {0} Aura When Equipped" }, { "id": 216, @@ -10737,7 +10737,7 @@ 31 ], "name": "item_aura", - "description": "Level Conviction 31 Aura When Equipped" + "description": "Level 31 Conviction Aura When Equipped" }, { "id": 127, @@ -11429,7 +11429,7 @@ 31 ], "name": "item_aura", - "description": "Level {0} {1} Aura When Equipped" + "description": "Level {1} {0} Aura When Equipped" }, { "id": 216, @@ -11533,7 +11533,7 @@ 31 ], "name": "item_aura", - "description": "Level Conviction 31 Aura When Equipped" + "description": "Level 31 Conviction Aura When Equipped" }, { "id": 127, @@ -12149,7 +12149,7 @@ 31 ], "name": "item_aura", - "description": "Level {0} {1} Aura When Equipped" + "description": "Level {1} {0} Aura When Equipped" }, { "id": 216, @@ -12248,7 +12248,7 @@ 31 ], "name": "item_aura", - "description": "Level Conviction 31 Aura When Equipped" + "description": "Level 31 Conviction Aura When Equipped" }, { "id": 127, @@ -12940,7 +12940,7 @@ 31 ], "name": "item_aura", - "description": "Level {0} {1} Aura When Equipped" + "description": "Level {1} {0} Aura When Equipped" }, { "id": 216, @@ -13044,7 +13044,7 @@ 31 ], "name": "item_aura", - "description": "Level Conviction 31 Aura When Equipped" + "description": "Level 31 Conviction Aura When Equipped" }, { "id": 127, @@ -13660,7 +13660,7 @@ 31 ], "name": "item_aura", - "description": "Level {0} {1} Aura When Equipped" + "description": "Level {1} {0} Aura When Equipped" }, { "id": 216, @@ -13759,7 +13759,7 @@ 31 ], "name": "item_aura", - "description": "Level Conviction 31 Aura When Equipped" + "description": "Level 31 Conviction Aura When Equipped" }, { "id": 127, @@ -14785,7 +14785,7 @@ 31 ], "name": "item_aura", - "description": "Level {0} {1} Aura When Equipped" + "description": "Level {1} {0} Aura When Equipped" }, { "id": 216, @@ -14889,7 +14889,7 @@ 31 ], "name": "item_aura", - "description": "Level Conviction 31 Aura When Equipped" + "description": "Level 31 Conviction Aura When Equipped" }, { "id": 127, @@ -15505,7 +15505,7 @@ 31 ], "name": "item_aura", - "description": "Level {0} {1} Aura When Equipped" + "description": "Level {1} {0} Aura When Equipped" }, { "id": 216, @@ -15604,7 +15604,7 @@ 31 ], "name": "item_aura", - "description": "Level Conviction 31 Aura When Equipped" + "description": "Level 31 Conviction Aura When Equipped" }, { "id": 127, @@ -16296,7 +16296,7 @@ 31 ], "name": "item_aura", - "description": "Level {0} {1} Aura When Equipped" + "description": "Level {1} {0} Aura When Equipped" }, { "id": 216, @@ -16400,7 +16400,7 @@ 31 ], "name": "item_aura", - "description": "Level Conviction 31 Aura When Equipped" + "description": "Level 31 Conviction Aura When Equipped" }, { "id": 127, @@ -17016,7 +17016,7 @@ 31 ], "name": "item_aura", - "description": "Level {0} {1} Aura When Equipped" + "description": "Level {1} {0} Aura When Equipped" }, { "id": 216, @@ -17115,7 +17115,7 @@ 31 ], "name": "item_aura", - "description": "Level Conviction 31 Aura When Equipped" + "description": "Level 31 Conviction Aura When Equipped" }, { "id": 127, @@ -17807,7 +17807,7 @@ 31 ], "name": "item_aura", - "description": "Level {0} {1} Aura When Equipped" + "description": "Level {1} {0} Aura When Equipped" }, { "id": 216, @@ -17911,7 +17911,7 @@ 31 ], "name": "item_aura", - "description": "Level Conviction 31 Aura When Equipped" + "description": "Level 31 Conviction Aura When Equipped" }, { "id": 127, @@ -18527,7 +18527,7 @@ 31 ], "name": "item_aura", - "description": "Level {0} {1} Aura When Equipped" + "description": "Level {1} {0} Aura When Equipped" }, { "id": 216, @@ -18626,7 +18626,7 @@ 31 ], "name": "item_aura", - "description": "Level Conviction 31 Aura When Equipped" + "description": "Level 31 Conviction Aura When Equipped" }, { "id": 127, @@ -19318,7 +19318,7 @@ 31 ], "name": "item_aura", - "description": "Level {0} {1} Aura When Equipped" + "description": "Level {1} {0} Aura When Equipped" }, { "id": 216, @@ -19422,7 +19422,7 @@ 31 ], "name": "item_aura", - "description": "Level Conviction 31 Aura When Equipped" + "description": "Level 31 Conviction Aura When Equipped" }, { "id": 127, @@ -20038,7 +20038,7 @@ 31 ], "name": "item_aura", - "description": "Level {0} {1} Aura When Equipped" + "description": "Level {1} {0} Aura When Equipped" }, { "id": 216, @@ -20137,7 +20137,7 @@ 31 ], "name": "item_aura", - "description": "Level Conviction 31 Aura When Equipped" + "description": "Level 31 Conviction Aura When Equipped" }, { "id": 127, @@ -20829,7 +20829,7 @@ 31 ], "name": "item_aura", - "description": "Level {0} {1} Aura When Equipped" + "description": "Level {1} {0} Aura When Equipped" }, { "id": 216, @@ -20933,7 +20933,7 @@ 31 ], "name": "item_aura", - "description": "Level Conviction 31 Aura When Equipped" + "description": "Level 31 Conviction Aura When Equipped" }, { "id": 127, @@ -21549,7 +21549,7 @@ 31 ], "name": "item_aura", - "description": "Level {0} {1} Aura When Equipped" + "description": "Level {1} {0} Aura When Equipped" }, { "id": 216, @@ -21648,7 +21648,7 @@ 31 ], "name": "item_aura", - "description": "Level Conviction 31 Aura When Equipped" + "description": "Level 31 Conviction Aura When Equipped" }, { "id": 127, diff --git a/source/examples/chars/97/DannyIsGreatIV.json b/source/examples/chars/97/DannyIsGreatIV.json index 64e51399..d9e8dd7b 100644 --- a/source/examples/chars/97/DannyIsGreatIV.json +++ b/source/examples/chars/97/DannyIsGreatIV.json @@ -3909,7 +3909,7 @@ 31 ], "name": "item_aura", - "description": "Level {0} {1} Aura When Equipped" + "description": "Level {1} {0} Aura When Equipped" }, { "id": 216, @@ -4013,7 +4013,7 @@ 31 ], "name": "item_aura", - "description": "Level Conviction 31 Aura When Equipped" + "description": "Level 31 Conviction Aura When Equipped" }, { "id": 127, @@ -4629,7 +4629,7 @@ 31 ], "name": "item_aura", - "description": "Level {0} {1} Aura When Equipped" + "description": "Level {1} {0} Aura When Equipped" }, { "id": 216, @@ -4728,7 +4728,7 @@ 31 ], "name": "item_aura", - "description": "Level Conviction 31 Aura When Equipped" + "description": "Level 31 Conviction Aura When Equipped" }, { "id": 127, @@ -5420,7 +5420,7 @@ 31 ], "name": "item_aura", - "description": "Level {0} {1} Aura When Equipped" + "description": "Level {1} {0} Aura When Equipped" }, { "id": 216, @@ -5524,7 +5524,7 @@ 31 ], "name": "item_aura", - "description": "Level Conviction 31 Aura When Equipped" + "description": "Level 31 Conviction Aura When Equipped" }, { "id": 127, @@ -6140,7 +6140,7 @@ 31 ], "name": "item_aura", - "description": "Level {0} {1} Aura When Equipped" + "description": "Level {1} {0} Aura When Equipped" }, { "id": 216, @@ -6239,7 +6239,7 @@ 31 ], "name": "item_aura", - "description": "Level Conviction 31 Aura When Equipped" + "description": "Level 31 Conviction Aura When Equipped" }, { "id": 127, @@ -6931,7 +6931,7 @@ 31 ], "name": "item_aura", - "description": "Level {0} {1} Aura When Equipped" + "description": "Level {1} {0} Aura When Equipped" }, { "id": 216, @@ -7035,7 +7035,7 @@ 31 ], "name": "item_aura", - "description": "Level Conviction 31 Aura When Equipped" + "description": "Level 31 Conviction Aura When Equipped" }, { "id": 127, @@ -7651,7 +7651,7 @@ 31 ], "name": "item_aura", - "description": "Level {0} {1} Aura When Equipped" + "description": "Level {1} {0} Aura When Equipped" }, { "id": 216, @@ -7750,7 +7750,7 @@ 31 ], "name": "item_aura", - "description": "Level Conviction 31 Aura When Equipped" + "description": "Level 31 Conviction Aura When Equipped" }, { "id": 127, @@ -8442,7 +8442,7 @@ 31 ], "name": "item_aura", - "description": "Level {0} {1} Aura When Equipped" + "description": "Level {1} {0} Aura When Equipped" }, { "id": 216, @@ -8546,7 +8546,7 @@ 31 ], "name": "item_aura", - "description": "Level Conviction 31 Aura When Equipped" + "description": "Level 31 Conviction Aura When Equipped" }, { "id": 127, @@ -9162,7 +9162,7 @@ 31 ], "name": "item_aura", - "description": "Level {0} {1} Aura When Equipped" + "description": "Level {1} {0} Aura When Equipped" }, { "id": 216, @@ -9261,7 +9261,7 @@ 31 ], "name": "item_aura", - "description": "Level Conviction 31 Aura When Equipped" + "description": "Level 31 Conviction Aura When Equipped" }, { "id": 127, @@ -9953,7 +9953,7 @@ 31 ], "name": "item_aura", - "description": "Level {0} {1} Aura When Equipped" + "description": "Level {1} {0} Aura When Equipped" }, { "id": 216, @@ -10057,7 +10057,7 @@ 31 ], "name": "item_aura", - "description": "Level Conviction 31 Aura When Equipped" + "description": "Level 31 Conviction Aura When Equipped" }, { "id": 127, @@ -10673,7 +10673,7 @@ 31 ], "name": "item_aura", - "description": "Level {0} {1} Aura When Equipped" + "description": "Level {1} {0} Aura When Equipped" }, { "id": 216, @@ -10772,7 +10772,7 @@ 31 ], "name": "item_aura", - "description": "Level Conviction 31 Aura When Equipped" + "description": "Level 31 Conviction Aura When Equipped" }, { "id": 127, @@ -11464,7 +11464,7 @@ 31 ], "name": "item_aura", - "description": "Level {0} {1} Aura When Equipped" + "description": "Level {1} {0} Aura When Equipped" }, { "id": 216, @@ -11568,7 +11568,7 @@ 31 ], "name": "item_aura", - "description": "Level Conviction 31 Aura When Equipped" + "description": "Level 31 Conviction Aura When Equipped" }, { "id": 127, @@ -12184,7 +12184,7 @@ 31 ], "name": "item_aura", - "description": "Level {0} {1} Aura When Equipped" + "description": "Level {1} {0} Aura When Equipped" }, { "id": 216, @@ -12283,7 +12283,7 @@ 31 ], "name": "item_aura", - "description": "Level Conviction 31 Aura When Equipped" + "description": "Level 31 Conviction Aura When Equipped" }, { "id": 127, @@ -12975,7 +12975,7 @@ 31 ], "name": "item_aura", - "description": "Level {0} {1} Aura When Equipped" + "description": "Level {1} {0} Aura When Equipped" }, { "id": 216, @@ -13079,7 +13079,7 @@ 31 ], "name": "item_aura", - "description": "Level Conviction 31 Aura When Equipped" + "description": "Level 31 Conviction Aura When Equipped" }, { "id": 127, @@ -13695,7 +13695,7 @@ 31 ], "name": "item_aura", - "description": "Level {0} {1} Aura When Equipped" + "description": "Level {1} {0} Aura When Equipped" }, { "id": 216, @@ -13794,7 +13794,7 @@ 31 ], "name": "item_aura", - "description": "Level Conviction 31 Aura When Equipped" + "description": "Level 31 Conviction Aura When Equipped" }, { "id": 127, @@ -14820,7 +14820,7 @@ 31 ], "name": "item_aura", - "description": "Level {0} {1} Aura When Equipped" + "description": "Level {1} {0} Aura When Equipped" }, { "id": 216, @@ -14924,7 +14924,7 @@ 31 ], "name": "item_aura", - "description": "Level Conviction 31 Aura When Equipped" + "description": "Level 31 Conviction Aura When Equipped" }, { "id": 127, @@ -15540,7 +15540,7 @@ 31 ], "name": "item_aura", - "description": "Level {0} {1} Aura When Equipped" + "description": "Level {1} {0} Aura When Equipped" }, { "id": 216, @@ -15639,7 +15639,7 @@ 31 ], "name": "item_aura", - "description": "Level Conviction 31 Aura When Equipped" + "description": "Level 31 Conviction Aura When Equipped" }, { "id": 127, @@ -16331,7 +16331,7 @@ 31 ], "name": "item_aura", - "description": "Level {0} {1} Aura When Equipped" + "description": "Level {1} {0} Aura When Equipped" }, { "id": 216, @@ -16435,7 +16435,7 @@ 31 ], "name": "item_aura", - "description": "Level Conviction 31 Aura When Equipped" + "description": "Level 31 Conviction Aura When Equipped" }, { "id": 127, @@ -17051,7 +17051,7 @@ 31 ], "name": "item_aura", - "description": "Level {0} {1} Aura When Equipped" + "description": "Level {1} {0} Aura When Equipped" }, { "id": 216, @@ -17150,7 +17150,7 @@ 31 ], "name": "item_aura", - "description": "Level Conviction 31 Aura When Equipped" + "description": "Level 31 Conviction Aura When Equipped" }, { "id": 127, @@ -17842,7 +17842,7 @@ 31 ], "name": "item_aura", - "description": "Level {0} {1} Aura When Equipped" + "description": "Level {1} {0} Aura When Equipped" }, { "id": 216, @@ -17946,7 +17946,7 @@ 31 ], "name": "item_aura", - "description": "Level Conviction 31 Aura When Equipped" + "description": "Level 31 Conviction Aura When Equipped" }, { "id": 127, @@ -18562,7 +18562,7 @@ 31 ], "name": "item_aura", - "description": "Level {0} {1} Aura When Equipped" + "description": "Level {1} {0} Aura When Equipped" }, { "id": 216, @@ -18661,7 +18661,7 @@ 31 ], "name": "item_aura", - "description": "Level Conviction 31 Aura When Equipped" + "description": "Level 31 Conviction Aura When Equipped" }, { "id": 127, @@ -19353,7 +19353,7 @@ 31 ], "name": "item_aura", - "description": "Level {0} {1} Aura When Equipped" + "description": "Level {1} {0} Aura When Equipped" }, { "id": 216, @@ -19457,7 +19457,7 @@ 31 ], "name": "item_aura", - "description": "Level Conviction 31 Aura When Equipped" + "description": "Level 31 Conviction Aura When Equipped" }, { "id": 127, @@ -20073,7 +20073,7 @@ 31 ], "name": "item_aura", - "description": "Level {0} {1} Aura When Equipped" + "description": "Level {1} {0} Aura When Equipped" }, { "id": 216, @@ -20172,7 +20172,7 @@ 31 ], "name": "item_aura", - "description": "Level Conviction 31 Aura When Equipped" + "description": "Level 31 Conviction Aura When Equipped" }, { "id": 127, @@ -20864,7 +20864,7 @@ 31 ], "name": "item_aura", - "description": "Level {0} {1} Aura When Equipped" + "description": "Level {1} {0} Aura When Equipped" }, { "id": 216, @@ -20968,7 +20968,7 @@ 31 ], "name": "item_aura", - "description": "Level Conviction 31 Aura When Equipped" + "description": "Level 31 Conviction Aura When Equipped" }, { "id": 127, @@ -21584,7 +21584,7 @@ 31 ], "name": "item_aura", - "description": "Level {0} {1} Aura When Equipped" + "description": "Level {1} {0} Aura When Equipped" }, { "id": 216, @@ -21683,7 +21683,7 @@ 31 ], "name": "item_aura", - "description": "Level Conviction 31 Aura When Equipped" + "description": "Level 31 Conviction Aura When Equipped" }, { "id": 127, diff --git a/source/examples/chars/97/DannyIsGreatV.json b/source/examples/chars/97/DannyIsGreatV.json index 56ab4c97..4f278a3f 100644 --- a/source/examples/chars/97/DannyIsGreatV.json +++ b/source/examples/chars/97/DannyIsGreatV.json @@ -3845,7 +3845,7 @@ 31 ], "name": "item_aura", - "description": "Level {0} {1} Aura When Equipped" + "description": "Level {1} {0} Aura When Equipped" }, { "id": 216, @@ -3949,7 +3949,7 @@ 31 ], "name": "item_aura", - "description": "Level Conviction 31 Aura When Equipped" + "description": "Level 31 Conviction Aura When Equipped" }, { "id": 127, @@ -4565,7 +4565,7 @@ 31 ], "name": "item_aura", - "description": "Level {0} {1} Aura When Equipped" + "description": "Level {1} {0} Aura When Equipped" }, { "id": 216, @@ -4664,7 +4664,7 @@ 31 ], "name": "item_aura", - "description": "Level Conviction 31 Aura When Equipped" + "description": "Level 31 Conviction Aura When Equipped" }, { "id": 127, @@ -5356,7 +5356,7 @@ 31 ], "name": "item_aura", - "description": "Level {0} {1} Aura When Equipped" + "description": "Level {1} {0} Aura When Equipped" }, { "id": 216, @@ -5460,7 +5460,7 @@ 31 ], "name": "item_aura", - "description": "Level Conviction 31 Aura When Equipped" + "description": "Level 31 Conviction Aura When Equipped" }, { "id": 127, @@ -6076,7 +6076,7 @@ 31 ], "name": "item_aura", - "description": "Level {0} {1} Aura When Equipped" + "description": "Level {1} {0} Aura When Equipped" }, { "id": 216, @@ -6175,7 +6175,7 @@ 31 ], "name": "item_aura", - "description": "Level Conviction 31 Aura When Equipped" + "description": "Level 31 Conviction Aura When Equipped" }, { "id": 127, @@ -6867,7 +6867,7 @@ 31 ], "name": "item_aura", - "description": "Level {0} {1} Aura When Equipped" + "description": "Level {1} {0} Aura When Equipped" }, { "id": 216, @@ -6971,7 +6971,7 @@ 31 ], "name": "item_aura", - "description": "Level Conviction 31 Aura When Equipped" + "description": "Level 31 Conviction Aura When Equipped" }, { "id": 127, @@ -7587,7 +7587,7 @@ 31 ], "name": "item_aura", - "description": "Level {0} {1} Aura When Equipped" + "description": "Level {1} {0} Aura When Equipped" }, { "id": 216, @@ -7686,7 +7686,7 @@ 31 ], "name": "item_aura", - "description": "Level Conviction 31 Aura When Equipped" + "description": "Level 31 Conviction Aura When Equipped" }, { "id": 127, @@ -8378,7 +8378,7 @@ 31 ], "name": "item_aura", - "description": "Level {0} {1} Aura When Equipped" + "description": "Level {1} {0} Aura When Equipped" }, { "id": 216, @@ -8482,7 +8482,7 @@ 31 ], "name": "item_aura", - "description": "Level Conviction 31 Aura When Equipped" + "description": "Level 31 Conviction Aura When Equipped" }, { "id": 127, @@ -9098,7 +9098,7 @@ 31 ], "name": "item_aura", - "description": "Level {0} {1} Aura When Equipped" + "description": "Level {1} {0} Aura When Equipped" }, { "id": 216, @@ -9197,7 +9197,7 @@ 31 ], "name": "item_aura", - "description": "Level Conviction 31 Aura When Equipped" + "description": "Level 31 Conviction Aura When Equipped" }, { "id": 127, @@ -9889,7 +9889,7 @@ 31 ], "name": "item_aura", - "description": "Level {0} {1} Aura When Equipped" + "description": "Level {1} {0} Aura When Equipped" }, { "id": 216, @@ -9993,7 +9993,7 @@ 31 ], "name": "item_aura", - "description": "Level Conviction 31 Aura When Equipped" + "description": "Level 31 Conviction Aura When Equipped" }, { "id": 127, @@ -10609,7 +10609,7 @@ 31 ], "name": "item_aura", - "description": "Level {0} {1} Aura When Equipped" + "description": "Level {1} {0} Aura When Equipped" }, { "id": 216, @@ -10708,7 +10708,7 @@ 31 ], "name": "item_aura", - "description": "Level Conviction 31 Aura When Equipped" + "description": "Level 31 Conviction Aura When Equipped" }, { "id": 127, @@ -11400,7 +11400,7 @@ 31 ], "name": "item_aura", - "description": "Level {0} {1} Aura When Equipped" + "description": "Level {1} {0} Aura When Equipped" }, { "id": 216, @@ -11504,7 +11504,7 @@ 31 ], "name": "item_aura", - "description": "Level Conviction 31 Aura When Equipped" + "description": "Level 31 Conviction Aura When Equipped" }, { "id": 127, @@ -12120,7 +12120,7 @@ 31 ], "name": "item_aura", - "description": "Level {0} {1} Aura When Equipped" + "description": "Level {1} {0} Aura When Equipped" }, { "id": 216, @@ -12219,7 +12219,7 @@ 31 ], "name": "item_aura", - "description": "Level Conviction 31 Aura When Equipped" + "description": "Level 31 Conviction Aura When Equipped" }, { "id": 127, @@ -12911,7 +12911,7 @@ 31 ], "name": "item_aura", - "description": "Level {0} {1} Aura When Equipped" + "description": "Level {1} {0} Aura When Equipped" }, { "id": 216, @@ -13015,7 +13015,7 @@ 31 ], "name": "item_aura", - "description": "Level Conviction 31 Aura When Equipped" + "description": "Level 31 Conviction Aura When Equipped" }, { "id": 127, @@ -13631,7 +13631,7 @@ 31 ], "name": "item_aura", - "description": "Level {0} {1} Aura When Equipped" + "description": "Level {1} {0} Aura When Equipped" }, { "id": 216, @@ -13730,7 +13730,7 @@ 31 ], "name": "item_aura", - "description": "Level Conviction 31 Aura When Equipped" + "description": "Level 31 Conviction Aura When Equipped" }, { "id": 127, @@ -14756,7 +14756,7 @@ 31 ], "name": "item_aura", - "description": "Level {0} {1} Aura When Equipped" + "description": "Level {1} {0} Aura When Equipped" }, { "id": 216, @@ -14860,7 +14860,7 @@ 31 ], "name": "item_aura", - "description": "Level Conviction 31 Aura When Equipped" + "description": "Level 31 Conviction Aura When Equipped" }, { "id": 127, @@ -15476,7 +15476,7 @@ 31 ], "name": "item_aura", - "description": "Level {0} {1} Aura When Equipped" + "description": "Level {1} {0} Aura When Equipped" }, { "id": 216, @@ -15575,7 +15575,7 @@ 31 ], "name": "item_aura", - "description": "Level Conviction 31 Aura When Equipped" + "description": "Level 31 Conviction Aura When Equipped" }, { "id": 127, @@ -16267,7 +16267,7 @@ 31 ], "name": "item_aura", - "description": "Level {0} {1} Aura When Equipped" + "description": "Level {1} {0} Aura When Equipped" }, { "id": 216, @@ -16371,7 +16371,7 @@ 31 ], "name": "item_aura", - "description": "Level Conviction 31 Aura When Equipped" + "description": "Level 31 Conviction Aura When Equipped" }, { "id": 127, @@ -16987,7 +16987,7 @@ 31 ], "name": "item_aura", - "description": "Level {0} {1} Aura When Equipped" + "description": "Level {1} {0} Aura When Equipped" }, { "id": 216, @@ -17086,7 +17086,7 @@ 31 ], "name": "item_aura", - "description": "Level Conviction 31 Aura When Equipped" + "description": "Level 31 Conviction Aura When Equipped" }, { "id": 127, @@ -17778,7 +17778,7 @@ 31 ], "name": "item_aura", - "description": "Level {0} {1} Aura When Equipped" + "description": "Level {1} {0} Aura When Equipped" }, { "id": 216, @@ -17882,7 +17882,7 @@ 31 ], "name": "item_aura", - "description": "Level Conviction 31 Aura When Equipped" + "description": "Level 31 Conviction Aura When Equipped" }, { "id": 127, @@ -18498,7 +18498,7 @@ 31 ], "name": "item_aura", - "description": "Level {0} {1} Aura When Equipped" + "description": "Level {1} {0} Aura When Equipped" }, { "id": 216, @@ -18597,7 +18597,7 @@ 31 ], "name": "item_aura", - "description": "Level Conviction 31 Aura When Equipped" + "description": "Level 31 Conviction Aura When Equipped" }, { "id": 127, @@ -19289,7 +19289,7 @@ 31 ], "name": "item_aura", - "description": "Level {0} {1} Aura When Equipped" + "description": "Level {1} {0} Aura When Equipped" }, { "id": 216, @@ -19393,7 +19393,7 @@ 31 ], "name": "item_aura", - "description": "Level Conviction 31 Aura When Equipped" + "description": "Level 31 Conviction Aura When Equipped" }, { "id": 127, @@ -20009,7 +20009,7 @@ 31 ], "name": "item_aura", - "description": "Level {0} {1} Aura When Equipped" + "description": "Level {1} {0} Aura When Equipped" }, { "id": 216, @@ -20108,7 +20108,7 @@ 31 ], "name": "item_aura", - "description": "Level Conviction 31 Aura When Equipped" + "description": "Level 31 Conviction Aura When Equipped" }, { "id": 127, @@ -20800,7 +20800,7 @@ 31 ], "name": "item_aura", - "description": "Level {0} {1} Aura When Equipped" + "description": "Level {1} {0} Aura When Equipped" }, { "id": 216, @@ -20904,7 +20904,7 @@ 31 ], "name": "item_aura", - "description": "Level Conviction 31 Aura When Equipped" + "description": "Level 31 Conviction Aura When Equipped" }, { "id": 127, @@ -21520,7 +21520,7 @@ 31 ], "name": "item_aura", - "description": "Level {0} {1} Aura When Equipped" + "description": "Level {1} {0} Aura When Equipped" }, { "id": 216, @@ -21619,7 +21619,7 @@ 31 ], "name": "item_aura", - "description": "Level Conviction 31 Aura When Equipped" + "description": "Level 31 Conviction Aura When Equipped" }, { "id": 127, diff --git a/source/examples/chars/97/Loradiel.json b/source/examples/chars/97/Loradiel.json index 7aed30d4..287f600e 100644 --- a/source/examples/chars/97/Loradiel.json +++ b/source/examples/chars/97/Loradiel.json @@ -7134,7 +7134,7 @@ 20 ], "name": "item_aura", - "description": "Level {0} {1} Aura When Equipped" + "description": "Level {1} {0} Aura When Equipped" }, { "id": 215, @@ -7181,7 +7181,7 @@ 20 ], "name": "item_aura", - "description": "Level Prayer 20 Aura When Equipped" + "description": "Level 20 Prayer Aura When Equipped" }, { "id": 127, @@ -7275,7 +7275,7 @@ 20 ], "name": "item_aura", - "description": "Level {0} {1} Aura When Equipped" + "description": "Level {1} {0} Aura When Equipped" }, { "id": 215, @@ -7318,7 +7318,7 @@ 20 ], "name": "item_aura", - "description": "Level Prayer 20 Aura When Equipped" + "description": "Level 20 Prayer Aura When Equipped" }, { "id": 127, @@ -7719,7 +7719,7 @@ 20 ], "name": "item_aura", - "description": "Level {0} {1} Aura When Equipped" + "description": "Level {1} {0} Aura When Equipped" }, { "id": 153, @@ -7797,7 +7797,7 @@ 20 ], "name": "item_aura", - "description": "Level Cleansing 20 Aura When Equipped" + "description": "Level 20 Cleansing Aura When Equipped" }, { "id": 99, @@ -8187,7 +8187,7 @@ 20 ], "name": "item_aura", - "description": "Level {0} {1} Aura When Equipped" + "description": "Level {1} {0} Aura When Equipped" }, { "id": 153, @@ -8256,7 +8256,7 @@ 20 ], "name": "item_aura", - "description": "Level Cleansing 20 Aura When Equipped" + "description": "Level 20 Cleansing Aura When Equipped" }, { "id": 99, @@ -10867,7 +10867,7 @@ 20 ], "name": "item_aura", - "description": "Level {0} {1} Aura When Equipped" + "description": "Level {1} {0} Aura When Equipped" }, { "id": 204, @@ -10922,7 +10922,7 @@ 20 ], "name": "item_aura", - "description": "Level Prayer 20 Aura When Equipped" + "description": "Level 20 Prayer Aura When Equipped" }, { "id": 99, @@ -11355,7 +11355,7 @@ 20 ], "name": "item_aura", - "description": "Level {0} {1} Aura When Equipped" + "description": "Level {1} {0} Aura When Equipped" }, { "id": 204, @@ -11401,7 +11401,7 @@ 20 ], "name": "item_aura", - "description": "Level Prayer 20 Aura When Equipped" + "description": "Level 20 Prayer Aura When Equipped" }, { "id": 99, @@ -22145,7 +22145,7 @@ 20 ], "name": "item_aura", - "description": "Level {0} {1} Aura When Equipped" + "description": "Level {1} {0} Aura When Equipped" }, { "id": 188, @@ -23379,7 +23379,7 @@ 20 ], "name": "item_aura", - "description": "Level Cleansing 20 Aura When Equipped" + "description": "Level 20 Cleansing Aura When Equipped" }, { "id": 188, @@ -23499,7 +23499,7 @@ 20 ], "name": "item_aura", - "description": "Level {0} {1} Aura When Equipped" + "description": "Level {1} {0} Aura When Equipped" }, { "id": 188, @@ -23713,7 +23713,7 @@ 20 ], "name": "item_aura", - "description": "Level Cleansing 20 Aura When Equipped" + "description": "Level 20 Cleansing Aura When Equipped" }, { "id": 188, @@ -24145,7 +24145,7 @@ 20 ], "name": "item_aura", - "description": "Level {0} {1} Aura When Equipped" + "description": "Level {1} {0} Aura When Equipped" }, { "id": 188, @@ -25315,7 +25315,7 @@ 20 ], "name": "item_aura", - "description": "Level Salvation 20 Aura When Equipped" + "description": "Level 20 Salvation Aura When Equipped" }, { "id": 188, @@ -25451,7 +25451,7 @@ 20 ], "name": "item_aura", - "description": "Level {0} {1} Aura When Equipped" + "description": "Level {1} {0} Aura When Equipped" }, { "id": 188, @@ -25649,7 +25649,7 @@ 20 ], "name": "item_aura", - "description": "Level Salvation 20 Aura When Equipped" + "description": "Level 20 Salvation Aura When Equipped" }, { "id": 188, @@ -26056,7 +26056,7 @@ 20 ], "name": "item_aura", - "description": "Level {0} {1} Aura When Equipped" + "description": "Level {1} {0} Aura When Equipped" }, { "id": 188, @@ -27202,7 +27202,7 @@ 20 ], "name": "item_aura", - "description": "Level Resist Fire 20 Aura When Equipped" + "description": "Level 20 Resist Fire Aura When Equipped" }, { "id": 188, @@ -27318,7 +27318,7 @@ 20 ], "name": "item_aura", - "description": "Level {0} {1} Aura When Equipped" + "description": "Level {1} {0} Aura When Equipped" }, { "id": 188, @@ -27532,7 +27532,7 @@ 20 ], "name": "item_aura", - "description": "Level Resist Fire 20 Aura When Equipped" + "description": "Level 20 Resist Fire Aura When Equipped" }, { "id": 188, @@ -27910,7 +27910,7 @@ 20 ], "name": "item_aura", - "description": "Level {0} {1} Aura When Equipped" + "description": "Level {1} {0} Aura When Equipped" }, { "id": 188, @@ -29056,7 +29056,7 @@ 20 ], "name": "item_aura", - "description": "Level Resist Lightning 20 Aura When Equipped" + "description": "Level 20 Resist Lightning Aura When Equipped" }, { "id": 188, @@ -29172,7 +29172,7 @@ 20 ], "name": "item_aura", - "description": "Level {0} {1} Aura When Equipped" + "description": "Level {1} {0} Aura When Equipped" }, { "id": 188, @@ -29386,7 +29386,7 @@ 20 ], "name": "item_aura", - "description": "Level Resist Lightning 20 Aura When Equipped" + "description": "Level 20 Resist Lightning Aura When Equipped" }, { "id": 188, @@ -34061,7 +34061,7 @@ 20 ], "name": "item_aura", - "description": "Level {0} {1} Aura When Equipped" + "description": "Level {1} {0} Aura When Equipped" }, { "id": 188, @@ -35294,7 +35294,7 @@ 20 ], "name": "item_aura", - "description": "Level Concentration 20 Aura When Equipped" + "description": "Level 20 Concentration Aura When Equipped" }, { "id": 188, @@ -35414,7 +35414,7 @@ 20 ], "name": "item_aura", - "description": "Level {0} {1} Aura When Equipped" + "description": "Level {1} {0} Aura When Equipped" }, { "id": 188, @@ -35628,7 +35628,7 @@ 20 ], "name": "item_aura", - "description": "Level Concentration 20 Aura When Equipped" + "description": "Level 20 Concentration Aura When Equipped" }, { "id": 188, @@ -36026,7 +36026,7 @@ 20 ], "name": "item_aura", - "description": "Level {0} {1} Aura When Equipped" + "description": "Level {1} {0} Aura When Equipped" }, { "id": 188, @@ -37172,7 +37172,7 @@ 20 ], "name": "item_aura", - "description": "Level Fanaticism 20 Aura When Equipped" + "description": "Level 20 Fanaticism Aura When Equipped" }, { "id": 188, @@ -37290,7 +37290,7 @@ 20 ], "name": "item_aura", - "description": "Level {0} {1} Aura When Equipped" + "description": "Level {1} {0} Aura When Equipped" }, { "id": 188, @@ -37503,7 +37503,7 @@ 20 ], "name": "item_aura", - "description": "Level Fanaticism 20 Aura When Equipped" + "description": "Level 20 Fanaticism Aura When Equipped" }, { "id": 188, @@ -37882,7 +37882,7 @@ 20 ], "name": "item_aura", - "description": "Level {0} {1} Aura When Equipped" + "description": "Level {1} {0} Aura When Equipped" }, { "id": 188, @@ -39028,7 +39028,7 @@ 20 ], "name": "item_aura", - "description": "Level Resist Cold 20 Aura When Equipped" + "description": "Level 20 Resist Cold Aura When Equipped" }, { "id": 188, @@ -39146,7 +39146,7 @@ 20 ], "name": "item_aura", - "description": "Level {0} {1} Aura When Equipped" + "description": "Level {1} {0} Aura When Equipped" }, { "id": 188, @@ -39359,7 +39359,7 @@ 20 ], "name": "item_aura", - "description": "Level Resist Cold 20 Aura When Equipped" + "description": "Level 20 Resist Cold Aura When Equipped" }, { "id": 188, @@ -39762,7 +39762,7 @@ 20 ], "name": "item_aura", - "description": "Level {0} {1} Aura When Equipped" + "description": "Level {1} {0} Aura When Equipped" }, { "id": 188, @@ -40995,7 +40995,7 @@ 20 ], "name": "item_aura", - "description": "Level Redemption 20 Aura When Equipped" + "description": "Level 20 Redemption Aura When Equipped" }, { "id": 188, @@ -41115,7 +41115,7 @@ 20 ], "name": "item_aura", - "description": "Level {0} {1} Aura When Equipped" + "description": "Level {1} {0} Aura When Equipped" }, { "id": 188, @@ -41329,7 +41329,7 @@ 20 ], "name": "item_aura", - "description": "Level Redemption 20 Aura When Equipped" + "description": "Level 20 Redemption Aura When Equipped" }, { "id": 188, diff --git a/source/resource.h b/source/resource.h index 1f14b302..591834a9 100644 --- a/source/resource.h +++ b/source/resource.h @@ -28,6 +28,7 @@ #define IDB_INVQLT 157 #define IDD_SHARED_STASH_DIALOG 157 #define IDB_INVLEA 158 +#define IDD_RUNEWORD_DIALOG 158 #define IDB_INVHLA 159 #define IDB_INVSTU 160 #define IDB_INVRNG 161 @@ -875,6 +876,7 @@ #define IDC_BUTTON_TREE_3_ROW_6_COL_3 1147 #define IDC_PAGE_COMBO 1150 #define IDC_SHARED_STASH_BUTTON 1151 +#define IDC_RUNEWORD_LIST 1152 #define ID_VIEW_REFRESH 32772 #define ID_VIEW_LEVEL_REQ 32773 #define ID_OPTIONS_BACKUP_CHAR 32774 @@ -932,9 +934,9 @@ // #ifdef APSTUDIO_INVOKED #ifndef APSTUDIO_READONLY_SYMBOLS -#define _APS_NEXT_RESOURCE_VALUE 727 +#define _APS_NEXT_RESOURCE_VALUE 725 #define _APS_NEXT_COMMAND_VALUE 32824 -#define _APS_NEXT_CONTROL_VALUE 1152 +#define _APS_NEXT_CONTROL_VALUE 1153 #define _APS_NEXT_SYMED_VALUE 103 #endif #endif