├── tools
└── esCharView
│ └── CharacterEditor
│ ├── Resources
│ ├── RoT_1.A3.1
│ │ ├── Sets.txt
│ │ ├── AllItems.txt
│ │ └── ItemGroups.txt
│ ├── AllItems.txt
│ ├── ItemGroups.txt
│ ├── 1.13c
│ │ ├── ItemGroups.txt
│ │ ├── Sets.txt
│ │ ├── AllItems.txt
│ │ └── ItemStatCost.txt
│ ├── es300_R6D
│ │ ├── AllItems.txt
│ │ ├── ItemGroups.txt
│ │ └── Sets.txt
│ └── Sets.txt
│ ├── BitStream.cs
│ ├── Properties
│ └── AssemblyInfo.cs
│ ├── Skill.cs
│ ├── Utils.cs
│ ├── CharacterEditor.csproj
│ ├── Resources.cs
│ ├── Character.cs
│ ├── ItemStatCost.cs
│ ├── ItemDefs.cs
│ ├── BitStream.resx
│ ├── Stat.cs
│ ├── SaveReader.cs
│ ├── Inventory.cs
│ └── Item.cs
├── .gitignore
└── README.md
/tools/esCharView/CharacterEditor/Resources/RoT_1.A3.1/Sets.txt:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | Debug
2 | Release
3 | Bin
4 | Obj
5 | Output
6 | *.user
7 | *.sdf
8 | *.suo
9 | *.ipch
10 | *.opensdf
11 |
--------------------------------------------------------------------------------
/tools/esCharView/CharacterEditor/BitStream.cs:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/HarpyWar/d2s-character-editor/HEAD/tools/esCharView/CharacterEditor/BitStream.cs
--------------------------------------------------------------------------------
/tools/esCharView/CharacterEditor/Resources/AllItems.txt:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/HarpyWar/d2s-character-editor/HEAD/tools/esCharView/CharacterEditor/Resources/AllItems.txt
--------------------------------------------------------------------------------
/tools/esCharView/CharacterEditor/Resources/ItemGroups.txt:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/HarpyWar/d2s-character-editor/HEAD/tools/esCharView/CharacterEditor/Resources/ItemGroups.txt
--------------------------------------------------------------------------------
/tools/esCharView/CharacterEditor/Resources/1.13c/ItemGroups.txt:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/HarpyWar/d2s-character-editor/HEAD/tools/esCharView/CharacterEditor/Resources/1.13c/ItemGroups.txt
--------------------------------------------------------------------------------
/tools/esCharView/CharacterEditor/Resources/RoT_1.A3.1/AllItems.txt:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/HarpyWar/d2s-character-editor/HEAD/tools/esCharView/CharacterEditor/Resources/RoT_1.A3.1/AllItems.txt
--------------------------------------------------------------------------------
/tools/esCharView/CharacterEditor/Resources/es300_R6D/AllItems.txt:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/HarpyWar/d2s-character-editor/HEAD/tools/esCharView/CharacterEditor/Resources/es300_R6D/AllItems.txt
--------------------------------------------------------------------------------
/tools/esCharView/CharacterEditor/Resources/RoT_1.A3.1/ItemGroups.txt:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/HarpyWar/d2s-character-editor/HEAD/tools/esCharView/CharacterEditor/Resources/RoT_1.A3.1/ItemGroups.txt
--------------------------------------------------------------------------------
/tools/esCharView/CharacterEditor/Resources/es300_R6D/ItemGroups.txt:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/HarpyWar/d2s-character-editor/HEAD/tools/esCharView/CharacterEditor/Resources/es300_R6D/ItemGroups.txt
--------------------------------------------------------------------------------
/tools/esCharView/CharacterEditor/Properties/AssemblyInfo.cs:
--------------------------------------------------------------------------------
1 | using System.Reflection;
2 | using System.Runtime.CompilerServices;
3 | using System.Runtime.InteropServices;
4 |
5 | // General Information about an assembly is controlled through the following
6 | // set of attributes. Change these attribute values to modify the information
7 | // associated with an assembly.
8 | [assembly: AssemblyTitle("CharacterEditor")]
9 | [assembly: AssemblyDescription("")]
10 | [assembly: AssemblyConfiguration("")]
11 | [assembly: AssemblyCompany("Microsoft")]
12 | [assembly: AssemblyProduct("CharacterEditor")]
13 | [assembly: AssemblyCopyright("Copyright © Microsoft 2010")]
14 | [assembly: AssemblyTrademark("")]
15 | [assembly: AssemblyCulture("")]
16 |
17 | // Setting ComVisible to false makes the types in this assembly not visible
18 | // to COM components. If you need to access a type in this assembly from
19 | // COM, set the ComVisible attribute to true on that type.
20 | [assembly: ComVisible(false)]
21 |
22 | // The following GUID is for the ID of the typelib if this project is exposed to COM
23 | [assembly: Guid("4bd9a9cf-c9f9-4c01-bfb6-d4091e5197ac")]
24 |
25 | // Version information for an assembly consists of the following four values:
26 | //
27 | // Major Version
28 | // Minor Version
29 | // Build Number
30 | // Revision
31 | //
32 | // You can specify all the values or you can default the Build and Revision Numbers
33 | // by using the '*' as shown below:
34 | // [assembly: AssemblyVersion("1.0.*")]
35 | [assembly: AssemblyVersion("1.0.0.0")]
36 | [assembly: AssemblyFileVersion("1.0.0.0")]
37 |
--------------------------------------------------------------------------------
/tools/esCharView/CharacterEditor/Skill.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Linq;
4 | using System.Text;
5 | using System.Collections;
6 |
7 | namespace CharacterEditor
8 | {
9 | ///
10 | /// Skill class for accessing raw skill data
11 | ///
12 | public class Skill : IEnumerable
13 | {
14 | ///
15 | /// Each byte in skillBytes represents level of a skill
16 | ///
17 | private byte[] skillBytes;
18 |
19 | ///
20 | /// Gets or sets the skill at specified index
21 | ///
22 | /// Index of skill to access
23 | /// Value of skill at specified index
24 | public byte this[int index]
25 | {
26 | get
27 | {
28 | return skillBytes[index+2];
29 | }
30 | set
31 | {
32 | skillBytes[index+2] = value;
33 | }
34 | }
35 |
36 | ///
37 | /// Number of skills
38 | ///
39 | public int Length
40 | {
41 | get { return skillBytes.Length - 2; }
42 | }
43 |
44 | ///
45 | /// Creates a new skill class for accessing raw skill data
46 | ///
47 | /// Raw skill data from save file
48 | /// Skill data exists between the end of stat data and beginning of item data
49 | public Skill(byte[] skillBytes)
50 | {
51 | if (skillBytes[0] != 'i' || skillBytes[1] != 'f')
52 | {
53 | throw new Exception("SkillByte data missing if header");
54 | }
55 |
56 | this.skillBytes = skillBytes;
57 | }
58 |
59 | ///
60 | /// Converts all skill data into raw data for save file
61 | ///
62 | /// Raw skill data ready for insertion into save file
63 | public byte[] GetSkillBytes()
64 | {
65 | return skillBytes;
66 | }
67 |
68 | #region IEnumerable Members
69 |
70 | public IEnumerator GetEnumerator()
71 | {
72 | for (int i = 0; i < skillBytes.Length; i++)
73 | {
74 | yield return skillBytes[i];
75 | }
76 | }
77 |
78 | #endregion
79 | }
80 | }
81 |
--------------------------------------------------------------------------------
/tools/esCharView/CharacterEditor/Resources/1.13c/Sets.txt:
--------------------------------------------------------------------------------
1 | lrg Civerb's Ward
2 | 2ax Berserker's Hatchet
3 | 6cs Naj's Puzzler
4 | 7gd Bul-Kathos' Sacred Charge
5 | 7ls Sazabi's Cobalt Redeemer
6 | 7m7 Immortal King's Stone Crusher
7 | 7ma Dangoon's Teaching
8 | 7qr Natalya's Mark
9 | 7wd Bul-Kathos' Tribal Guardian
10 | 7ws Griswolds's Redemption
11 | 9mt Aldur's Gauntlet
12 | 9vo Hwanin's Justice
13 | aar Milabrega's Robe
14 | amc M'avina's Caster
15 | amu Set Amulet
16 | ba5 Immortal King's Will
17 | bhm Tancred's Skull
18 | brs Isenhart's Case
19 | bsd Isenhart's Lightbrand
20 | bst Cathan's Rule
21 | buc Hsarus' Iron Fist
22 | bwn McAuley's Superstition
23 | cap Set cap
24 | chn Cathan's Mesh
25 | ci0 Naj's Circlet
26 | ci3 M'avina's True Sight
27 | crn Iratha's Coil
28 | crn Milabrega's Diadem
29 | dr8 Aldur's Stony Gaze
30 | fhl Isenhart's Horns
31 | ful Tancred's Spine
32 | ghm Sigon's Visor
33 | gsc Civerb's Cudgel
34 | gth Sigon's Shelter
35 | gts Isenhart's Parry
36 | gwn Infernal Torch
37 | hbl Sigon's Wrap
38 | hbt Sigon's Sabot
39 | hgl Sigon's Gage
40 | hlm Berserker's Headgear
41 | kit Milabrega's Orb
42 | lbb Vidala's Barb
43 | lbl Death's Guard
44 | lbt Tancred's Hobnails
45 | lea Vidala's Ambush
46 | lgl Death's Hand
47 | lsd Cleglaw's Tooth
48 | ltp Arcanna's Flesh
49 | mbl Set buckler
50 | mbt Hsarus' Iron Heel
51 | mgl Cleglaw's Pincers
52 | mpi Tancred's Crowbill
53 | msk Cathan's Visage
54 | ne9 Trang-Oul's Wing
55 | oba Tal Rasha's Lidless Eye
56 | paf Griswold's Honor
57 | qui Arctic Furs
58 | rin Set ring
59 | rng Angelic Mantle
60 | sbr Angelic Sickle
61 | skp Arcanna's Head
62 | sml Cleglaw's Claw
63 | spl Berserker's Hauberk
64 | stu Cow King's Hide
65 | swb Arctic Horn
66 | tbl Set belt
67 | tbt Vidala's Fetlock
68 | tgl Set gloves
69 | tow Sigon's Guard
70 | uar Immortal King's Soul Cage
71 | ucl Natalya's Shadow
72 | uh9 Trang-Oul's Guise
73 | uhm Ondal's Almighty
74 | uld M'avina's Embrace
75 | ulg Laying of Hands
76 | ult Naj's Light Plate
77 | umc Credendum
78 | upl Sazabi's Ghost Liberator
79 | urn Griswold's Valor
80 | utc Trang-Oul's Girth
81 | uth Tal Rasha's Howling Wind
82 | uts Heaven's Taebaek
83 | uui Spiritual Custodian
84 | uul Aldur's Deception
85 | vbl Arctic Binding
86 | vbt Set boots
87 | vgl McAuley's Taboo
88 | wsd Death's Touch
89 | wsp Milabrega's Rod
90 | wst Arcanna's Deathwand
91 | xap Cow King's Horns
92 | xar Griswold's Heart
93 | xcl Hwanin's Refuge
94 | xh9 Natalya's Totem
95 | xhb Immortal King's Pillar
96 | xhg Immortal King's Forge
97 | xhl Sazabi's Mental Sheath
98 | xhm Guillaume's Face
99 | xlb Rite of Passage
100 | xmb Natalya's Soul
101 | xmg Trang-Oul's Claws
102 | xml Wihtstan's Guard
103 | xrn Hwanin's Splendor
104 | xrs Haemosu's Adament
105 | xsk Tal Rasha's Horadric Crest
106 | xtb Aldur's Advance
107 | xtg M'avina's Icy Clutch
108 | xul Trang-Oul's Scales
109 | xvg Magnus' Skin
110 | zhb Immortal King's Detail
111 | zmb Tal Rasha's Fire-Spun Cloth
112 | ztb Wilhelm's Pride
113 | zvb M'avina's Tenet
114 |
--------------------------------------------------------------------------------
/tools/esCharView/CharacterEditor/Utils.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Linq;
4 | using System.Text;
5 | using System.IO;
6 |
7 | #if SILVERLIGHT
8 | using System.Windows.Resources;
9 | using System.Windows;
10 | #endif
11 |
12 | // Utils for the silverlight app
13 | namespace CharacterEditor
14 | {
15 | public class StringUtils
16 | {
17 | ///
18 | /// Convert a string value into specified type. If string is null or empty,
19 | /// default value of type is returned (null for non-value types)
20 | ///
21 | /// String to parse for value
22 | /// Type of value
23 | /// Value of specified string for a given type
24 | public static object ConvertFromString(string value, Type t)
25 | {
26 | if (value.Length == 0)
27 | {
28 | if (t.IsValueType)
29 | {
30 | return Activator.CreateInstance(t);
31 | }
32 | else
33 | {
34 | if (t == typeof(string))
35 | {
36 | return "";
37 | }
38 |
39 | return null;
40 | }
41 | }
42 |
43 | if (t == typeof(bool) && value.Length == 1)
44 | {
45 | return value == "1";
46 | }
47 |
48 | return Convert.ChangeType(value, t, null);
49 | }
50 | }
51 |
52 | public class ResourceUtils
53 | {
54 | public static Stream OpenResource(string assemblyName, string resourcePath)
55 | {
56 | #if SILVERLIGHT
57 | Uri resourceUri = new Uri(string.Format("{0};component/{1}", assemblyName, resourcePath), UriKind.Relative);
58 | StreamResourceInfo sri = Application.GetResourceStream(resourceUri);
59 |
60 | if (sri == null)
61 | {
62 | throw new FileNotFoundException("Failed to read file: " + resourceUri);
63 | }
64 |
65 | return sri.Stream;
66 | #else
67 | return File.Open(resourcePath, FileMode.Open);
68 | #endif
69 | }
70 |
71 | public static StreamReader OpenResourceText(string assemblyName, string resourcePath)
72 | {
73 | return new StreamReader(OpenResource(assemblyName, resourcePath));
74 | }
75 |
76 | public static BinaryReader OpenResourceBinary(string assemblyName, string resourcePath)
77 | {
78 | return new BinaryReader(OpenResource(assemblyName, resourcePath));
79 | }
80 |
81 | public static List ReadAllLines(string assemblyName, string resourcePath)
82 | {
83 | List lines = new List();
84 |
85 | using (StreamReader sr = OpenResourceText(assemblyName, resourcePath))
86 | {
87 | while (!sr.EndOfStream)
88 | {
89 | lines.Add(sr.ReadLine());
90 | }
91 | }
92 |
93 | return lines;
94 | }
95 |
96 | public static string ReadToEnd(string assemblyName, string resourcePath)
97 | {
98 | using (StreamReader sr = OpenResourceText(assemblyName, resourcePath))
99 | {
100 | return sr.ReadToEnd();
101 | }
102 | }
103 |
104 | public static byte[] ReadAllBytes(string assemblyName, string resourcePath)
105 | {
106 | using (BinaryReader br = OpenResourceBinary(assemblyName, resourcePath))
107 | {
108 | return br.ReadBytes((int)br.BaseStream.Length);
109 | }
110 | }
111 | }
112 | }
--------------------------------------------------------------------------------
/tools/esCharView/CharacterEditor/CharacterEditor.csproj:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | Debug
5 | AnyCPU
6 | 8.0.30703
7 | 2.0
8 | {69326F80-7E22-41AD-BF83-02829A2BA924}
9 | Library
10 | Properties
11 | CharacterEditor
12 | CharacterEditor
13 | v3.5
14 | 512
15 |
16 |
17 |
18 | true
19 | full
20 | false
21 | bin\Debug\
22 | TRACE;DEBUG;DESKTOP
23 | prompt
24 | 4
25 | true
26 |
27 |
28 | pdbonly
29 | true
30 | bin\Release\
31 | TRACE
32 | prompt
33 | 4
34 | true
35 | AnyCPU
36 |
37 |
38 |
39 |
40 |
41 |
42 |
43 |
44 |
45 |
46 |
47 |
48 |
49 |
50 |
51 |
52 |
53 |
54 |
55 |
56 |
57 |
58 |
59 |
60 |
61 | PreserveNewest
62 |
63 |
64 | PreserveNewest
65 |
66 |
67 | PreserveNewest
68 |
69 |
70 | PreserveNewest
71 |
72 |
73 | PreserveNewest
74 |
75 |
76 | PreserveNewest
77 |
78 |
79 | PreserveNewest
80 |
81 |
82 | PreserveNewest
83 |
84 |
85 |
86 |
87 | BitStream.cs
88 | Designer
89 |
90 |
91 |
92 |
93 |
100 |
--------------------------------------------------------------------------------
/tools/esCharView/CharacterEditor/Resources.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Linq;
4 | using System.Text;
5 | using System.IO;
6 | using System.Resources;
7 | using System.Threading;
8 | using System.Collections;
9 | using System.Text.RegularExpressions;
10 | using System.Reflection;
11 | using System.Diagnostics;
12 |
13 | namespace CharacterEditor
14 | {
15 | public class Resources
16 | {
17 | private static readonly Resources instance = new Resources();
18 | public static Resources Instance
19 | {
20 | get { return instance; }
21 | }
22 |
23 | private Resources()
24 | {
25 |
26 | }
27 |
28 | private string resourceSet;
29 | public string ResourceSet
30 | {
31 | get
32 | {
33 | return resourceSet;
34 | }
35 | set
36 | {
37 | if (IsValidResourceSet(value))
38 | {
39 | resourceSet = value;
40 | }
41 | }
42 | }
43 |
44 | ///
45 | /// Obtains a list of all available resource sets. Resources must be marked as Resource when building project.
46 | ///
47 | /// Resources/es300_R6D/AllItems.txt -> es300_R6D
48 | ///
49 | /// http://blogs.microsoft.co.il/blogs/alex_golesh/archive/2009/11/13/silverlight-tip-enumerating-embedded-resources.aspx
50 | private static List GetResourceSetsSilverlight()
51 | {
52 | List resourceNames = new List();
53 | Assembly currentAssembly = Assembly.GetExecutingAssembly();
54 | string[] resources = currentAssembly.GetManifestResourceNames();
55 |
56 | foreach (var resource in resources)
57 | {
58 | ResourceManager rm = new ResourceManager(resource.Replace(".resources", ""), currentAssembly);
59 | rm.GetStream("app.xaml"); // can't seem to GetResourceSet without getting a stream -> see above link where code comes from
60 | ResourceSet rs = rm.GetResourceSet(Thread.CurrentThread.CurrentCulture, false, true);
61 |
62 | foreach (DictionaryEntry item in rs)
63 | {
64 | string resourceName = (string)item.Key;
65 |
66 | // "Resources/es300_R6D/AllItems.txt"
67 | Regex regex = new Regex(@"^(?[^/]+)/(?[^/]+)/(?.*)$");
68 |
69 | if (regex.IsMatch(resourceName))
70 | {
71 | Match match = regex.Match(resourceName);
72 |
73 | if (match.Groups["file"].Value.ToLower() == "allitems.txt")
74 | {
75 | resourceNames.Add(match.Groups["set"].Value);
76 | }
77 | }
78 | }
79 |
80 | if (resourceNames.Count > 0)
81 | {
82 | return resourceNames;
83 | }
84 | }
85 |
86 | return resourceNames;
87 | }
88 |
89 | #if !SILVERLIGHT
90 | private static List GetResourceSetsDesktop()
91 | {
92 | List resourceNames = new List();
93 | string[] directories = Directory.GetDirectories("Resources/");
94 |
95 | foreach (var dir in directories)
96 | {
97 | if (File.Exists(dir + "/" + "allitems.txt"))
98 | {
99 | resourceNames.Add(Path.GetFileName(dir));
100 | }
101 | }
102 |
103 | return resourceNames;
104 | }
105 | #endif
106 |
107 | public static string CurrentDirectory
108 | {
109 | get
110 | {
111 | return Directory.GetCurrentDirectory();
112 | }
113 | set
114 | {
115 | Directory.SetCurrentDirectory(value);
116 | }
117 | }
118 |
119 | public static List GetResourceSets()
120 | {
121 | #if SILVERLIGHT
122 | return GetResourceSetsSilverlight();
123 | #else
124 | return GetResourceSetsDesktop();
125 | #endif
126 | }
127 |
128 |
129 | internal static bool IsValidResourceSet(string value)
130 | {
131 | #if SILVERLIGHT
132 | // Pretty lengthy process, but is rarely called
133 | return GetResourceSetsSilverlight().Contains(value.ToLower());
134 | #else
135 | return Directory.Exists("Resources/" + value);
136 | #endif
137 | }
138 |
139 | public Stream OpenResource(string resourceName)
140 | {
141 | string resourcePath = "Resources/" + resourceSet + "/" + resourceName;
142 |
143 | return ResourceUtils.OpenResource("CharacterEditor.Silverlight", resourcePath);
144 | }
145 |
146 | public StreamReader OpenResourceText(string resourceName)
147 | {
148 | string resourcePath = "Resources/" + resourceSet + "/" + resourceName;
149 |
150 | return ResourceUtils.OpenResourceText("CharacterEditor.Silverlight", resourcePath);
151 | }
152 |
153 | public List ReadAllLines(string resourceName)
154 | {
155 | string resourcePath = "Resources/" + resourceSet + "/" + resourceName;
156 |
157 | return ResourceUtils.ReadAllLines("CharacterEditor.Silverlight", resourcePath);
158 | }
159 | }
160 | }
161 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | I pay attention to a project `tools/esCharView/CharacterEditor` in the repository forked from [nooperation/d2es-stuff](https://github.com/nooperation/d2es-stuff).
2 |
3 | **CharacterEditor** is .NET library for editing Diablo 2 character files (`.d2s`).
4 |
5 | Several changes from me:
6 | * fix a bug in inventory
7 | * add feature to get bytes of `d2s` to save data to a file
8 | * feature to add new items to a character
9 | * add resources for 1.13c to make it possible edit original d2s files.
10 |
11 | This library is used in online service that can edit characters through REST API, there is PHP interface to consume it https://github.com/pvpgn/d2smanager-api
12 |
13 |
14 |
15 |
16 | ## How to use CharacterEditor.dll
17 |
18 | Put `Resources` directory in the root with your application, then you can pass different "mods" (a directory name) to `SaveReader` constructor. For 1.13c you should use `new SaveReader("1.13c")`.
19 |
20 | It is possible to set a directory with Resources in code:
21 | ```c#
22 | CharacterEditor.Resources.CurrentDirectory = @"C:\MyProject\App_Data\";
23 | ```
24 |
25 | Read character into object
26 | ```c#
27 | var reader = new SaveReader("1.13c")
28 |
29 | var charBytes = File.ReadAllBytes("harpywar.d2s");
30 | var d2s = reader.Read(charBytes);
31 | ```
32 |
33 |
34 | Split all character items into different files
35 | ```c#
36 | var items = new List- ();
37 | items.AddRange(d2s.Inventory.PlayerItems);
38 | items.AddRange(d2s.Inventory.CorpseItems);
39 | items.AddRange(d2s.Inventory.GolemItems);
40 | items.AddRange(d2s.Inventory.MercItems);
41 |
42 | for (var i = 0; i < items.Length; i++)
43 | {
44 | File.WriteAllBytes(i + ".d2i", items[i].GetItemBytes());
45 | }
46 | ```
47 |
48 | Add new item from `.d2i` file to a character's inventory
49 | ```c#
50 | var itemBytes = File.ReadAllBytes("item.d2i");
51 | var item = new Item(itemBytes, true)
52 |
53 | // add to character inventory
54 | d2s.Inventory.PlayerItems.Add( FixItem(item) );
55 |
56 | // set default item position in inventory in left-top corner
57 | public static Item FixItem(Item item)
58 | {
59 | var newItem = new Item(item.GetItemBytes(), true);
60 |
61 | newItem.Id = 0;
62 | newItem.Location = (uint)Item.ItemLocation.Stored;
63 | newItem.PositionOnBody = (uint)Item.EquipmentLocation.None;
64 | newItem.PositionX = 0;
65 | newItem.PositionY = 0;
66 | newItem.StorageId = (uint) Item.StorageType.Inventory;
67 |
68 | return newItem;
69 | }
70 | ```
71 |
72 | Remove item from a character
73 | ```c#
74 | // item you want to remove
75 | Item findItem;
76 |
77 | // find item on body
78 | if ( findInItems(d2s.Inventory.PlayerItems, findItem) )
79 | {
80 | d2s.Inventory.PlayerItems.Remove(item);
81 | }
82 | // find in merc
83 | if ( findInItems(d2s.Inventory.MercItems, findItem) )
84 | {
85 | d2s.Inventory.MercItems.Remove(item);
86 | }
87 | // find in golem
88 | if ( findInItems(d2s.Inventory.GolemItems, findItem) )
89 | {
90 | d2s.Inventory.GolemItems.Remove(item);
91 | }
92 | // find in corpse
93 | if ( findInItems(d2s.Inventory.CorpseItems, findItem) )
94 | {
95 | d2s.Inventory.CorpseItems.Remove(item);
96 | }
97 |
98 | // find an item in items list
99 | private findInItems(List
- items, Item findItem)
100 | {
101 | foreach (var item in items)
102 | {
103 | if (ByteArrayCompare(item.GetItemBytes(), findItem.GetItemBytes()))
104 | {
105 | return true;
106 | }
107 | }
108 | return false;
109 | }
110 | // just compare two byte arrays
111 | static bool ByteArrayCompare(byte[] a1, byte[] a2)
112 | {
113 | return StructuralComparisons.StructuralEqualityComparer.Equals(a1, a2);
114 | }
115 | ```
116 |
117 | Save modified character
118 | ```c#
119 | File.WriteAllBytes("newchar.d2s", d2s.GetBytes());
120 | ```
121 |
122 |
123 |
124 | Use IClonable interface to work with many characters without preloading resources each time:
125 | ```c#
126 |
127 | foreach (var file in Directory.GetFiles(@"C:\pvpgn\var\charsave"))
128 | {
129 | ReadCharacter(file);
130 | }
131 |
132 | private static void ReadCharacter(string fileName)
133 | {
134 | var charBytes = File.ReadAllBytes(fileName);
135 | var d2s = CharManager.Read(charBytes);
136 |
137 | // other manipulates with "d2s" object
138 | ...
139 | }
140 |
141 | public static class CharManager
142 | {
143 | private static SaveReader _reader;
144 | public static SaveReader Reader
145 | {
146 | get
147 | {
148 | // lazy loading resources
149 | if (_reader == null)
150 | {
151 | // set working directory
152 | CharacterEditor.Resources.CurrentDirectory = Directory.GetCurrentDirectory();
153 | // load "ItemDefs" from Resources
154 | _reader = new SaveReader("1.13c");
155 | }
156 | return (SaveReader)_reader.Clone(); // create new instance
157 | }
158 | }
159 |
160 | public static SaveReader Read(byte[] charBytes)
161 | {
162 | return Reader.Read(charBytes);
163 | }
164 | }
165 | ```
166 |
167 |
--------------------------------------------------------------------------------
/tools/esCharView/CharacterEditor/Character.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Text;
4 | using System.IO;
5 | using System.Collections;
6 | using System.ComponentModel;
7 |
8 | namespace CharacterEditor
9 | {
10 | public class Character : INotifyPropertyChanged
11 | {
12 | private byte[] characterBytes;
13 | private byte characterFlags;
14 |
15 | ///
16 | /// Character classes
17 | ///
18 | public enum CharacterClass
19 | {
20 | Amazon,
21 | Sorceress,
22 | Necromancer,
23 | Paladin,
24 | Barbarian,
25 | Druid,
26 | Assassin,
27 | }
28 |
29 | ///
30 | /// Character's name
31 | ///
32 | public String Name
33 | {
34 | get
35 | {
36 | string name = UnicodeEncoding.UTF8.GetString(characterBytes, 0x14, 16);
37 | return name.Substring(0, name.IndexOf('\0'));
38 | }
39 | set
40 | {
41 | byte[] paddedName = new byte[16];
42 | byte[] newName = UnicodeEncoding.UTF8.GetBytes(value);
43 |
44 | //15 instead of 16 to keep trailing null character
45 | Array.Copy(newName, paddedName, newName.Length < 15 ? newName.Length : 15);
46 | Array.Copy(paddedName, 0, characterBytes, 0x14, paddedName.Length);
47 | OnPropertyChange("Name");
48 | }
49 | }
50 |
51 | ///
52 | /// Character is in hardcore mode
53 | ///
54 | public bool Hardcore
55 | {
56 | get
57 | {
58 | return (characterFlags & 0x04) > 0;
59 | }
60 | set
61 | {
62 | if (value)
63 | {
64 | characterFlags |= 0x04;
65 | }
66 | else
67 | {
68 | characterFlags &= 0xfb;
69 | }
70 | OnPropertyChange("Hardcore");
71 | }
72 | }
73 |
74 | ///
75 | /// Character has died before
76 | ///
77 | public bool Died
78 | {
79 | get
80 | {
81 | return (characterFlags & 0x08) > 0;
82 | }
83 | set
84 | {
85 | if (value)
86 | {
87 | characterFlags |= 0x08;
88 | }
89 | else
90 | {
91 | characterFlags &= 0xf7;
92 | }
93 | OnPropertyChange("Died");
94 | }
95 | }
96 |
97 | ///
98 | /// Character is expansion character
99 | ///
100 | public bool Expansion
101 | {
102 | get
103 | {
104 | return (characterFlags & 0x20) > 0;
105 | }
106 | set
107 | {
108 | if (value)
109 | {
110 | characterFlags |= 0x20;
111 | }
112 | else
113 | {
114 | characterFlags &= 0xDF;
115 | }
116 | OnPropertyChange("Expansion");
117 | }
118 | }
119 |
120 | ///
121 | /// Collection of unknown flags
122 | ///
123 | public byte UnknownFlags
124 | {
125 | get
126 | {
127 | return (byte)(characterFlags & (byte)0xd3);
128 | }
129 | set
130 | {
131 | characterFlags &= 0x2C;
132 | characterFlags |= value;
133 | OnPropertyChange("UnknownFlags");
134 | }
135 | }
136 |
137 | ///
138 | /// Character's title / progression
139 | ///
140 | public byte Progression
141 | {
142 | get { return characterBytes[37]; }
143 | set
144 | {
145 | characterBytes[37] = value;
146 | OnPropertyChange("Progression");
147 | }
148 | }
149 |
150 | ///
151 | /// Character's class
152 | ///
153 | public CharacterClass Class
154 | {
155 | get { return (CharacterClass)characterBytes[40]; }
156 | set
157 | {
158 | characterBytes[40] = (byte)value;
159 | OnPropertyChange("Class");
160 | }
161 | }
162 |
163 | ///
164 | /// Level displayed on character list ?
165 | ///
166 | public byte LevelDisplay
167 | {
168 | get { return characterBytes[43]; }
169 | set
170 | {
171 | characterBytes[43] = value;
172 | OnPropertyChange("LevelDisplay");
173 | }
174 | }
175 |
176 | ///
177 | /// Chracter has a mercenary
178 | ///
179 | public bool HasMercenary
180 | {
181 | get
182 | {
183 | return BitConverter.ToUInt32(characterBytes, 179) != 0;
184 | }
185 | }
186 |
187 | ///
188 | /// ID Of mercenary's name
189 | ///
190 | public ushort MercenaryNameId
191 | {
192 | get
193 | {
194 | return BitConverter.ToUInt16(characterBytes, 183);
195 | }
196 | }
197 |
198 | ///
199 | /// Mercenary type
200 | ///
201 | public ushort MercenaryType
202 | {
203 | get
204 | {
205 | return BitConverter.ToUInt16(characterBytes, 185);
206 | }
207 | }
208 |
209 | ///
210 | /// Mercenary's experience points
211 | ///
212 | public uint MercenaryExp
213 | {
214 | get
215 | {
216 | return BitConverter.ToUInt32(characterBytes, 185);
217 | }
218 | }
219 |
220 | ///
221 | /// Creates a new character reader with specified header
222 | ///
223 | /// Raw character bytes from save file
224 | public Character(byte[] characterBytes)
225 | {
226 | if (characterBytes[0] != 0x55 || characterBytes[1] != 0xAA || characterBytes[2] != 0x55 || characterBytes[3] != 0xAA)
227 | {
228 | throw new Exception("CharacterByte data missing 0x55AA55AA header");
229 | }
230 |
231 | this.characterBytes = characterBytes;
232 | characterFlags = characterBytes[0x24];
233 | }
234 |
235 | ///
236 | /// Returns modified character bytes for use in save file
237 | ///
238 | /// Raw character bytes
239 | public byte[] GetCharacterBytes()
240 | {
241 | characterBytes[0x24] = characterFlags;
242 |
243 | return characterBytes;
244 | }
245 |
246 | #region INotifyPropertyChanged Members
247 |
248 | public event PropertyChangedEventHandler PropertyChanged;
249 |
250 | private void OnPropertyChange(string propertyName)
251 | {
252 | if (PropertyChanged != null)
253 | {
254 | PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
255 | }
256 | }
257 |
258 | #endregion
259 | }
260 | }
261 |
--------------------------------------------------------------------------------
/tools/esCharView/CharacterEditor/Resources/Sets.txt:
--------------------------------------------------------------------------------
1 | qui Autolycus' Robes
2 | 0b0 Barbarian's Point-H
3 | 0bs Iron Wolf's Broad Sword-H
4 | 0gd Sarevok's Master
5 | 0nn Borik's Nightblade
6 | 0sb Griffith's Parry
7 | 0st Mercenary's Pike-H
8 | 0sy Reaver of the Angel of A
9 | 1cs Crook of the Darkest Valley
10 | 1ls Branch of the Ents
11 | 1sb Rogue's Bow-H
12 | 7wb Sascha's Deadly Point
13 | 8lw Lixo's Harp
14 | 8sb Rogue's Bow-NM
15 | 8ws The Staff of the Magi
16 | 9b9 Barbarian's Point-NM
17 | 9be Lancelot's Prediction
18 | 9bs Iron Wolf's Broad Sword-NM
19 | 9cr Keeper of the Fire
20 | 9cs Alora's Silent Assault
21 | 9fc Krakerag's Point
22 | 9fl Darkshade's Evisceration
23 | 9gm Fyrre's Deception
24 | 9gs Krakerag's Slay
25 | 9gw Lim-Dul's Hex
26 | 9mt Darkshade's Skewer
27 | 9p9 Aanna's Touch
28 | 9pb Noir's Focus
29 | 9qr Sascha's Jagged Strike
30 | 9rd Nupraptor's Eradicator
31 | 9st Mercenary's Pike-NM
32 | 9yw The Lich's Curse
33 | aar Kain's Fear
34 | ahb Darien's Band
35 | alb Lim-Dul's Vault
36 | am3 Gabrielle's Pointed Staff
37 | ama Alaziel's Point
38 | amd Milea's Maim
39 | amu Amulet
40 | ba3 Barbarian's Visage-N
41 | ba8 Barbarian's Visage-NM
42 | ba9 Darkshade's Haze
43 | bad Barbarian's Visage-H
44 | bae Sarevok's Malicious Stare
45 | baf Crown of the Northern Tribes
46 | bhm Wrathamon's Skull
47 | bmb Tasselhoff's Pouches
48 | brg Worldstone Shard
49 | brs Tyrael's Halo
50 | bsd Iron Wolf's Broad Sword-N
51 | bsw Barbarian's Point-N
52 | btl Power
53 | btx Messerschmidt's Reaver
54 | buc Hsarus' Iron Fist-Dru
55 | cap Infernal Cranium-Nec
56 | cap Berserker's Headgear-Bar
57 | chn Iron Wolf's Robes-N
58 | ci0 Tara's Vision
59 | ci1 Divada's Tiara
60 | ci2 Raistlin's Glance
61 | ci3 Milea's Crown
62 | ci4 Lixo's Flight
63 | cix Vega's Beauty
64 | clb Hsaru's Iron Arm
65 | clk Death's Guard-Ass
66 | clw Grace
67 | crn Anduin's Vision
68 | crs Tyrael's Virtue
69 | dam Jaheira's Force
70 | dbt Wanderer's Waltz
71 | dr2 Blackwing's Will
72 | dr4 Danarak's Spirit
73 | dr8 Horns of Power
74 | drb Terra's Clairvoyance
75 | eht Gabrielle's Revelation
76 | elv Malek's Pride
77 | fhl Helm of Spirits
78 | ful Armor of Gloom
79 | ghm Iron Wolf's Coif-N
80 | gis Blackwing's Force
81 | gsd Blood Baron
82 | gts Kain's Sentinel
83 | hax Berserker's Hatchet-Bar
84 | hbl Achilles' Girdle
85 | hbt Achilles' Heel
86 | hbw Arctic Horn-Ama
87 | hgl Achilles' Force
88 | hla Berserker's Hauberk-Bar
89 | hlm Mercenary's Shiek-N
90 | irg Kain's Wings
91 | kit Iron Wolf's Guard-N
92 | ktr Death's Touch-Ass
93 | lbl Arcanna's Flesh-Sor
94 | lbt Boots of Sneaking/Hsarus' Iron Heel-Dru
95 | lea Rogue's Suit-N
96 | lgl Death's Hand-Ass
97 | lrg Tara's Mirror
98 | ltp Naj's Light Plate
99 | mau Danarak's Mallet
100 | mbl Infernal Sign-Nec
101 | mbt Blackwing's Icewoven Strap
102 | mgl Messerschmidt's Burning Palm
103 | mnb Divada's Focus
104 | msb Malek's Grip
105 | msk Rathol's Gaze
106 | nea Nupraptor's Servant
107 | neb Lim-Dul's High Guardian
108 | njt Motoko's Power
109 | nsy Rathol's Touch
110 | ob3 Tara's Eye
111 | obc Arion's Eye
112 | pa4 Anduin's Protector
113 | paa Lancelot's Heraldic Lion
114 | pam Griffith's Charm
115 | pbe Malek's Strike
116 | rin Ring
117 | rng Rathol's Fear
118 | rob Tara's Gown
119 | sam Jade Star
120 | sbw Rogue's Bow-N
121 | scl Gabrielle's Defense
122 | scp Milabrega's Rod-Pal
123 | shl Motoko's Kimono
124 | skp Rogue's Cap-N
125 | sml Milabrega's Orb-Pal
126 | spk Tyrael's Faith
127 | spl Barbarian's Shelter-N
128 | spt Mercenary's Pike-N
129 | srn Jade Crest
130 | sst Arcanna's Deathwand-Sor
131 | stu Mercenary's Wraps-N
132 | syn Wrathamon's Scythe of Doom
133 | tbl Vega's Sash
134 | tbt Messerschmidt's Brace
135 | tgl Blackwing's Clench
136 | tow Stormshield
137 | vbl Autolycus' Thieving Tools/Arctic Binding
138 | vbt Milabrega's Ironsoles-Pal
139 | vgl Arctic Mitts-Ama
140 | whm Anduin's Vanquisher
141 | wnd Infernal Torch-Nec
142 | wst Naj's Puzzler
143 | xap Alora's Veil
144 | xar Darkshade's Spined Sheath
145 | xbt Noir's Stride
146 | xcl Robes of Earth and Water
147 | xea Rogue's Suit-NM
148 | xh9 Nupraptor's Skull
149 | xhb Persephone's Heel
150 | xhg Ihsan's Clutch
151 | xhh Sascha's Bosom
152 | xhl Tharn's Ward
153 | xhm Iron Wolf's Coif-NM
154 | xhn Iron Wolf's Robes-NM
155 | xig Noir's Tenacity
156 | xit Iron Wolf's Guard-NM
157 | xkp Rogue's Cap-NM
158 | xla Lixo's Coat
159 | xlb Naj's Fireward
160 | xld Krakerag's Chestplate
161 | xlg The Hands of Wier
162 | xlk Alora's Silhouette
163 | xlm Mercenary's Shiek-NM
164 | xlt Aanna's Dress
165 | xlv Alaziel's Protector
166 | xmb Alora's Vestige
167 | xmg The Lich's Clutch
168 | xms Ihsan's Coil
169 | xng Wrathamon's Cloak of Night
170 | xpk Malek's Defense
171 | xpl Barbarian's Shelter-NM
172 | xrb Divada's Shawl
173 | xrn Malek's Sight
174 | xrs The Lich's Cage
175 | xsk The Lich's Pate
176 | xtb Aanna's March
177 | xtg Aanna's Skill
178 | xth Griffith's Protection
179 | xtp Robes of the Arch-Magi
180 | xtu Mercenary's Wraps-NM
181 | xuc Divada's Screen
182 | xui Danarak's Wrap
183 | xul Lancelot's Security
184 | xvb Sandals of the Wind
185 | xvg Bard's Graceful Hand
186 | yap Ihsan's Gaze
187 | yar Cow King's Steel Hide
188 | ybt Cow King's Steel Hoofs
189 | ycl Darien's Faith
190 | ydw Cow King's Steel Horns
191 | yea Rogue's Suit-H
192 | yh9 Mask of the Angel of Death
193 | yhg Jaheira's Caress
194 | yhh Borik's Dark Binding
195 | yhl Darien's Wit
196 | yhm Iron Wolf's Coif-H
197 | yhn Iron Wolf's Robes-H
198 | yht Noir's Anticipation
199 | yig Claws of the Dragon
200 | yit Iron Wolf's Guard-H
201 | ykp Rogue's Cap-H
202 | yla Jade Wrap
203 | ylb Sascha's Black Slipper
204 | yld Sarevok's Savage Heart
205 | ylg Arion's Hand
206 | ylk Ihsan's Spine
207 | ylm Mercenary's Shiek-H
208 | ylt Jaheira's Volition
209 | ylv Tasselhoff's Jerkin
210 | ymb Lim-Dul's Oath
211 | ymg Alaziel's Grip
212 | yml Alaziel's Buckler
213 | yng Milea's Mail
214 | ypl Barbarian's Shelter-H
215 | yrb Arion's Heart
216 | yrs Shepherd's Invocation
217 | ysk Griffith's Stare
218 | ytb Tasselhoff's Breaches
219 | ytg Shepherd's Blessing
220 | yth Flesh of the Angel of Chaos
221 | ytp Hide of the Tarrasque
222 | ytu Mercenary's Wraps-H
223 | yui Gaia's Carapace
224 | yul Harrogath's Heirloom
225 | yvb Jade Slipper
226 | yvg Borik's Black Hand
227 | zhb Darkshade's Binding
228 | zlb Root's Banded Restraint
229 | zmb Band of Famine
230 | ztb Jaheira's Girdle
231 | zvb The Lich's Sole
232 |
--------------------------------------------------------------------------------
/tools/esCharView/CharacterEditor/Resources/es300_R6D/Sets.txt:
--------------------------------------------------------------------------------
1 | qui Autolycus' Robes
2 | 0b0 Barbarian's Point-H
3 | 0bs Iron Wolf's Broad Sword-H
4 | 0gd Sarevok's Master
5 | 0nn Borik's Nightblade
6 | 0sb Griffith's Parry
7 | 0st Mercenary's Pike-H
8 | 0sy Reaver of the Angel of A
9 | 1cs Crook of the Darkest Valley
10 | 1ls Branch of the Ents
11 | 1sb Rogue's Bow-H
12 | 7wb Sascha's Deadly Point
13 | 8lw Lixo's Harp
14 | 8sb Rogue's Bow-NM
15 | 8ws The Staff of the Magi
16 | 9b9 Barbarian's Point-NM
17 | 9be Lancelot's Prediction
18 | 9bs Iron Wolf's Broad Sword-NM
19 | 9cr Keeper of the Fire
20 | 9cs Alora's Silent Assault
21 | 9fc Krakerag's Point
22 | 9fl Darkshade's Evisceration
23 | 9gm Fyrre's Deception
24 | 9gs Krakerag's Slay
25 | 9gw Lim-Dul's Hex
26 | 9mt Darkshade's Skewer
27 | 9p9 Aanna's Touch
28 | 9pb Noir's Focus
29 | 9qr Sascha's Jagged Strike
30 | 9rd Nupraptor's Eradicator
31 | 9st Mercenary's Pike-NM
32 | 9yw The Lich's Curse
33 | aar Kain's Fear
34 | ahb Darien's Band
35 | alb Lim-Dul's Vault
36 | am3 Gabrielle's Pointed Staff
37 | ama Alaziel's Point
38 | amd Milea's Maim
39 | amu Amulet
40 | ba3 Barbarian's Visage-N
41 | ba8 Barbarian's Visage-NM
42 | ba9 Darkshade's Haze
43 | bad Barbarian's Visage-H
44 | bae Sarevok's Malicious Stare
45 | baf Crown of the Northern Tribes
46 | bhm Wrathamon's Skull
47 | bmb Tasselhoff's Pouches
48 | brg Worldstone Shard
49 | brs Tyrael's Halo
50 | bsd Iron Wolf's Broad Sword-N
51 | bsw Barbarian's Point-N
52 | btl Power
53 | btx Messerschmidt's Reaver
54 | buc Hsarus' Iron Fist-Dru
55 | cap Infernal Cranium-Nec
56 | cap Berserker's Headgear-Bar
57 | chn Iron Wolf's Robes-N
58 | ci0 Tara's Vision
59 | ci1 Divada's Tiara
60 | ci2 Raistlin's Glance
61 | ci3 Milea's Crown
62 | ci4 Lixo's Flight
63 | cix Vega's Beauty
64 | clb Hsaru's Iron Arm
65 | clk Death's Guard-Ass
66 | clw Grace
67 | crn Anduin's Vision
68 | crs Tyrael's Virtue
69 | dam Jaheira's Force
70 | dbt Wanderer's Waltz
71 | dr2 Blackwing's Will
72 | dr4 Danarak's Spirit
73 | dr8 Horns of Power
74 | drb Terra's Clairvoyance
75 | eht Gabrielle's Revelation
76 | elv Malek's Pride
77 | fhl Helm of Spirits
78 | ful Armor of Gloom
79 | ghm Iron Wolf's Coif-N
80 | gis Blackwing's Force
81 | gsd Blood Baron
82 | gts Kain's Sentinel
83 | hax Berserker's Hatchet-Bar
84 | hbl Achilles' Girdle
85 | hbt Achilles' Heel
86 | hbw Arctic Horn-Ama
87 | hgl Achilles' Force
88 | hla Berserker's Hauberk-Bar
89 | hlm Mercenary's Shiek-N
90 | irg Kain's Wings
91 | kit Iron Wolf's Guard-N
92 | ktr Death's Touch-Ass
93 | lbl Arcanna's Flesh-Sor
94 | lbt Boots of Sneaking/Hsarus' Iron Heel-Dru
95 | lea Rogue's Suit-N
96 | lgl Death's Hand-Ass
97 | lrg Tara's Mirror
98 | ltp Naj's Light Plate
99 | mau Danarak's Mallet
100 | mbl Infernal Sign-Nec
101 | mbt Blackwing's Icewoven Strap
102 | mgl Messerschmidt's Burning Palm
103 | mnb Divada's Focus
104 | msb Malek's Grip
105 | msk Rathol's Gaze
106 | nea Nupraptor's Servant
107 | neb Lim-Dul's High Guardian
108 | njt Motoko's Power
109 | nsy Rathol's Touch
110 | ob3 Tara's Eye
111 | obc Arion's Eye
112 | pa4 Anduin's Protector
113 | paa Lancelot's Heraldic Lion
114 | pam Griffith's Charm
115 | pbe Malek's Strike
116 | rin Ring
117 | rng Rathol's Fear
118 | rob Tara's Gown
119 | sam Jade Star
120 | sbw Rogue's Bow-N
121 | scl Gabrielle's Defense
122 | scp Milabrega's Rod-Pal
123 | shl Motoko's Kimono
124 | skp Rogue's Cap-N
125 | sml Milabrega's Orb-Pal
126 | spk Tyrael's Faith
127 | spl Barbarian's Shelter-N
128 | spt Mercenary's Pike-N
129 | srn Jade Crest
130 | sst Arcanna's Deathwand-Sor
131 | stu Mercenary's Wraps-N
132 | syn Wrathamon's Scythe of Doom
133 | tbl Vega's Sash
134 | tbt Messerschmidt's Brace
135 | tgl Blackwing's Clench
136 | tow Stormshield
137 | vbl Autolycus' Thieving Tools/Arctic Binding
138 | vbt Milabrega's Ironsoles-Pal
139 | vgl Arctic Mitts-Ama
140 | whm Anduin's Vanquisher
141 | wnd Infernal Torch-Nec
142 | wst Naj's Puzzler
143 | xap Alora's Veil
144 | xar Darkshade's Spined Sheath
145 | xbt Noir's Stride
146 | xcl Robes of Earth and Water
147 | xea Rogue's Suit-NM
148 | xh9 Nupraptor's Skull
149 | xhb Persephone's Heel
150 | xhg Ihsan's Clutch
151 | xhh Sascha's Bosom
152 | xhl Tharn's Ward
153 | xhm Iron Wolf's Coif-NM
154 | xhn Iron Wolf's Robes-NM
155 | xig Noir's Tenacity
156 | xit Iron Wolf's Guard-NM
157 | xkp Rogue's Cap-NM
158 | xla Lixo's Coat
159 | xlb Naj's Fireward
160 | xld Krakerag's Chestplate
161 | xlg The Hands of Wier
162 | xlk Alora's Silhouette
163 | xlm Mercenary's Shiek-NM
164 | xlt Aanna's Dress
165 | xlv Alaziel's Protector
166 | xmb Alora's Vestige
167 | xmg The Lich's Clutch
168 | xms Ihsan's Coil
169 | xng Wrathamon's Cloak of Night
170 | xpk Malek's Defense
171 | xpl Barbarian's Shelter-NM
172 | xrb Divada's Shawl
173 | xrn Malek's Sight
174 | xrs The Lich's Cage
175 | xsk The Lich's Pate
176 | xtb Aanna's March
177 | xtg Aanna's Skill
178 | xth Griffith's Protection
179 | xtp Robes of the Arch-Magi
180 | xtu Mercenary's Wraps-NM
181 | xuc Divada's Screen
182 | xui Danarak's Wrap
183 | xul Lancelot's Security
184 | xvb Sandals of the Wind
185 | xvg Bard's Graceful Hand
186 | yap Ihsan's Gaze
187 | yar Cow King's Steel Hide
188 | ybt Cow King's Steel Hoofs
189 | ycl Darien's Faith
190 | ydw Cow King's Steel Horns
191 | yea Rogue's Suit-H
192 | yh9 Mask of the Angel of Death
193 | yhg Jaheira's Caress
194 | yhh Borik's Dark Binding
195 | yhl Darien's Wit
196 | yhm Iron Wolf's Coif-H
197 | yhn Iron Wolf's Robes-H
198 | yht Noir's Anticipation
199 | yig Claws of the Dragon
200 | yit Iron Wolf's Guard-H
201 | ykp Rogue's Cap-H
202 | yla Jade Wrap
203 | ylb Sascha's Black Slipper
204 | yld Sarevok's Savage Heart
205 | ylg Arion's Hand
206 | ylk Ihsan's Spine
207 | ylm Mercenary's Shiek-H
208 | ylt Jaheira's Volition
209 | ylv Tasselhoff's Jerkin
210 | ymb Lim-Dul's Oath
211 | ymg Alaziel's Grip
212 | yml Alaziel's Buckler
213 | yng Milea's Mail
214 | ypl Barbarian's Shelter-H
215 | yrb Arion's Heart
216 | yrs Shepherd's Invocation
217 | ysk Griffith's Stare
218 | ytb Tasselhoff's Breaches
219 | ytg Shepherd's Blessing
220 | yth Flesh of the Angel of Chaos
221 | ytp Hide of the Tarrasque
222 | ytu Mercenary's Wraps-H
223 | yui Gaia's Carapace
224 | yul Harrogath's Heirloom
225 | yvb Jade Slipper
226 | yvg Borik's Black Hand
227 | zhb Darkshade's Binding
228 | zlb Root's Banded Restraint
229 | zmb Band of Famine
230 | ztb Jaheira's Girdle
231 | zvb The Lich's Sole
232 |
--------------------------------------------------------------------------------
/tools/esCharView/CharacterEditor/ItemStatCost.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Linq;
4 | using System.Text;
5 | using System.IO;
6 | using System.Reflection;
7 |
8 | namespace CharacterEditor
9 | {
10 | public class ItemStatCost
11 | {
12 | public string Stat { get; set; }
13 | public int ID { get; set; }
14 | public bool SendOther { get; set; }
15 | public bool Signed { get; set; }
16 | public int SendBits { get; set; }
17 | public int SendParamBits { get; set; }
18 | public bool UpdateAnimRate { get; set; }
19 | public bool Saved { get; set; }
20 | public bool CSvSigned { get; set; }
21 | public int CSvBits { get; set; }
22 | public int CSvParam { get; set; }
23 | public bool FCallback { get; set; }
24 | public bool FMin { get; set; }
25 | public int MinAccr { get; set; }
26 | public int Encode { get; set; }
27 | public int Add { get; set; }
28 | public int Multiply { get; set; }
29 | public int Divide { get; set; }
30 | public int ValShift { get; set; }
31 | public int OldSaveBits { get; set; }
32 | public int OldSaveAdd { get; set; }
33 | public int SaveBits { get; set; }
34 | public int SaveAdd { get; set; }
35 | public int SaveParamBits { get; set; }
36 | public int Keepzero { get; set; }
37 | public int Op { get; set; }
38 | public int OpParam { get; set; }
39 | public string OpBase { get; set; }
40 | public string OpStat1 { get; set; }
41 | public string OpStat2 { get; set; }
42 | public string OpStat3 { get; set; }
43 | public bool Direct { get; set; }
44 | public string Maxstat { get; set; }
45 | public bool Itemspecific { get; set; }
46 | public bool Damagerelated { get; set; }
47 | public string Itemevent1 { get; set; }
48 | public int Itemeventfunc1 { get; set; }
49 | public string Itemevent2 { get; set; }
50 | public int Itemeventfunc2 { get; set; }
51 | public int Descpriority { get; set; }
52 | public int Descfunc { get; set; }
53 | public int Descval { get; set; }
54 | public string Descstrpos { get; set; }
55 | public string Descstrneg { get; set; }
56 | public string Descstr2 { get; set; }
57 | public int Dgrp { get; set; }
58 | public int Dgrpfunc { get; set; }
59 | public int Dgrpval { get; set; }
60 | public string Dgrpstrpos { get; set; }
61 | public string Dgrpstrneg { get; set; }
62 | public string Dgrpstr2 { get; set; }
63 | public int Stuff { get; set; }
64 | public bool Eol { get; set; }
65 |
66 | public ItemStatCost()
67 | {
68 |
69 | }
70 |
71 | public ItemStatCost(string[] data)
72 | {
73 | int i = 0;
74 |
75 | // TODO: Horrible cut+paste+replace mess
76 | Stat = (string)data[i++];
77 | ID = (int)StringUtils.ConvertFromString(data[i++], typeof(int));
78 | SendOther = (bool)StringUtils.ConvertFromString(data[i++], typeof(bool));
79 | Signed = (bool)StringUtils.ConvertFromString(data[i++], typeof(bool));
80 | SendBits = (int)StringUtils.ConvertFromString(data[i++], typeof(int));
81 | SendParamBits = (int)StringUtils.ConvertFromString(data[i++], typeof(int));
82 | UpdateAnimRate = (bool)StringUtils.ConvertFromString(data[i++], typeof(bool));
83 | Saved = (bool)StringUtils.ConvertFromString(data[i++], typeof(bool));
84 | CSvSigned = (bool)StringUtils.ConvertFromString(data[i++], typeof(bool));
85 | CSvBits = (int)StringUtils.ConvertFromString(data[i++], typeof(int));
86 | CSvParam = (int)StringUtils.ConvertFromString(data[i++], typeof(int));
87 | FCallback = (bool)StringUtils.ConvertFromString(data[i++], typeof(bool));
88 | FMin = (bool)StringUtils.ConvertFromString(data[i++], typeof(bool));
89 | MinAccr = (int)StringUtils.ConvertFromString(data[i++], typeof(int));
90 | Encode = (int)StringUtils.ConvertFromString(data[i++], typeof(int));
91 | Add = (int)StringUtils.ConvertFromString(data[i++], typeof(int));
92 | Multiply = (int)StringUtils.ConvertFromString(data[i++], typeof(int));
93 | Divide = (int)StringUtils.ConvertFromString(data[i++], typeof(int));
94 | ValShift = (int)StringUtils.ConvertFromString(data[i++], typeof(int));
95 | OldSaveBits = (int)StringUtils.ConvertFromString(data[i++], typeof(int));
96 | OldSaveAdd = (int)StringUtils.ConvertFromString(data[i++], typeof(int));
97 | SaveBits = (int)StringUtils.ConvertFromString(data[i++], typeof(int));
98 | SaveAdd = (int)StringUtils.ConvertFromString(data[i++], typeof(int));
99 | SaveParamBits = (int)StringUtils.ConvertFromString(data[i++], typeof(int));
100 | Keepzero = (int)StringUtils.ConvertFromString(data[i++], typeof(int));
101 | Op = (int)StringUtils.ConvertFromString(data[i++], typeof(int));
102 | OpParam = (int)StringUtils.ConvertFromString(data[i++], typeof(int));
103 | OpBase = (string)data[i++];
104 | OpStat1 = (string)data[i++];
105 | OpStat2 = (string)data[i++];
106 | OpStat3 = (string)data[i++];
107 | Direct = (bool)StringUtils.ConvertFromString(data[i++], typeof(bool));
108 | Maxstat = (string)data[i++];
109 | Itemspecific = (bool)StringUtils.ConvertFromString(data[i++], typeof(bool));
110 | Damagerelated = (bool)StringUtils.ConvertFromString(data[i++], typeof(bool));
111 | Itemevent1 = (string)data[i++];
112 | Itemeventfunc1 = (int)StringUtils.ConvertFromString(data[i++], typeof(int));
113 | Itemevent2 = (string)data[i++];
114 | Itemeventfunc2 = (int)StringUtils.ConvertFromString(data[i++], typeof(int));
115 | Descpriority = (int)StringUtils.ConvertFromString(data[i++], typeof(int));
116 | Descfunc = (int)StringUtils.ConvertFromString(data[i++], typeof(int));
117 | Descval = (int)StringUtils.ConvertFromString(data[i++], typeof(int));
118 | Descstrpos = (string)data[i++];
119 | Descstrneg = (string)data[i++];
120 | Descstr2 = (string)data[i++];
121 | Dgrp = (int)StringUtils.ConvertFromString(data[i++], typeof(int));
122 | Dgrpfunc = (int)StringUtils.ConvertFromString(data[i++], typeof(int));
123 | Dgrpval = (int)StringUtils.ConvertFromString(data[i++], typeof(int));
124 | Dgrpstrpos = (string)data[i++];
125 | Dgrpstrneg = (string)data[i++];
126 | Dgrpstr2 = (string)data[i++];
127 | Stuff = (int)StringUtils.ConvertFromString(data[i++], typeof(int));
128 | Eol = (bool)StringUtils.ConvertFromString(data[i++], typeof(bool));
129 | }
130 |
131 | public static List Read(StreamReader stream)
132 | {
133 | List statCosts = new List();
134 | PropertyInfo[] properties = typeof(ItemStatCost).GetProperties();
135 |
136 | using (stream)
137 | {
138 | stream.ReadLine();
139 |
140 | while (!stream.EndOfStream)
141 | {
142 | string currentLine = stream.ReadLine();
143 | string[] splitLine = currentLine.Split('\t');
144 |
145 |
146 | statCosts.Add(new ItemStatCost(splitLine));
147 | }
148 | }
149 |
150 | return statCosts;
151 | }
152 |
153 | public override string ToString()
154 | {
155 | return string.Format("{0} - {1}", ID, Stat);
156 | }
157 | }
158 | }
159 |
--------------------------------------------------------------------------------
/tools/esCharView/CharacterEditor/ItemDefs.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Text;
4 | using System.IO;
5 | using System.Collections;
6 | using System.Linq;
7 |
8 | namespace CharacterEditor
9 | {
10 | public class ItemDefs
11 | {
12 | private static Dictionary itemDescriptions = new Dictionary();
13 | private static Dictionary setDescriptions = new Dictionary();
14 | private static Dictionary> itemCodeSets = new Dictionary>();
15 | private static Dictionary itemStatCostsByName = new Dictionary();
16 | private static Dictionary itemStatCostsById = new Dictionary();
17 |
18 | ///
19 | /// List of ItemStatCost records based on Name
20 | ///
21 | public static Dictionary ItemStatCostsByName
22 | {
23 | get { return itemStatCostsByName; }
24 | }
25 |
26 | ///
27 | /// List of ItemStatCost records based on ID
28 | ///
29 | public static Dictionary ItemStatCostsById
30 | {
31 | get { return itemStatCostsById; }
32 | }
33 |
34 | // TODO: Temp fix! Get rid of static class and move to singleton based on current resource
35 | // set (es300_r6d, rot_1.a3.1, etc)
36 | internal static void LoadItemDefs()
37 | {
38 | // Temp!
39 | itemDescriptions = new Dictionary();
40 | setDescriptions = new Dictionary();
41 | itemCodeSets = new Dictionary>();
42 | itemStatCostsByName = new Dictionary();
43 | itemStatCostsById = new Dictionary();
44 |
45 | List fileContents = Resources.Instance.ReadAllLines("AllItems.txt");
46 |
47 | foreach (String str in fileContents)
48 | {
49 | string cleanStr = str;
50 |
51 | while (true)
52 | {
53 | // SpecialChar is the color character (followed by 2 other characters), this
54 | // is just stripping it since it looks bad
55 | int specialCharLocation = cleanStr.IndexOf('\xfffd');
56 |
57 | if (specialCharLocation == -1)
58 | break;
59 |
60 | cleanStr = cleanStr.Remove(specialCharLocation, 3);
61 | }
62 |
63 | itemDescriptions.Add(cleanStr.Substring(0, 3), cleanStr.Substring(4));
64 | }
65 |
66 | // Just so it's guaranteed that these sections exist
67 | itemCodeSets.Add("weapons", new HashSet());
68 | itemCodeSets.Add("armor", new HashSet());
69 | itemCodeSets.Add("stackable", new HashSet());
70 | itemCodeSets.Add("monsterparts", new HashSet());
71 | itemCodeSets.Add("scrolltome", new HashSet());
72 | itemCodeSets.Add("charms", new HashSet());
73 |
74 | ReadItemCodeSet(itemCodeSets, "ItemGroups.txt");
75 |
76 | foreach (string str in Resources.Instance.ReadAllLines("Sets.txt"))
77 | {
78 | string itemCode = str.Substring(0, 3);
79 |
80 | if (!setDescriptions.ContainsKey(itemCode))
81 | setDescriptions.Add(itemCode, str.Substring(4));
82 | }
83 |
84 | ReadItemStatCost();
85 | }
86 |
87 | static ItemDefs()
88 | {
89 | //LoadItemDefs(); // TODO: No more static class
90 | }
91 |
92 | ///
93 | /// Read ItemStatCost data
94 | ///
95 | private static void ReadItemStatCost()
96 | {
97 | List statCosts = ItemStatCost.Read(Resources.Instance.OpenResourceText("ItemStatCost.txt"));
98 |
99 | itemStatCostsByName = statCosts.ToDictionary(v => v.Stat, v => v);
100 | itemStatCostsById = statCosts.ToDictionary(v => v.ID, v => v);
101 | }
102 |
103 | ///
104 | /// Returns the name of the specified property ID
105 | ///
106 | /// ID of property
107 | /// Name of property with specified ID
108 | public static string GetPropertyName(int id)
109 | {
110 | if (!itemStatCostsById.ContainsKey(id))
111 | {
112 | if (id == 0x1ff)
113 | {
114 | return "EOF";
115 | }
116 |
117 | return "UNKNOWN";
118 | }
119 |
120 | return itemStatCostsById[id].Stat;
121 | }
122 |
123 | ///
124 | /// Returns the description of the specified item code
125 | ///
126 | /// Item code
127 | /// Item description
128 | public static string GetItemDescription(string itemCode)
129 | {
130 | if (itemDescriptions.ContainsKey(itemCode))
131 | {
132 | return itemDescriptions[itemCode];
133 | }
134 |
135 | return "UNKNOWN";
136 | }
137 |
138 | ///
139 | /// Returns the name of the set item with specified item code
140 | ///
141 | /// Item code
142 | /// Name of set item
143 | public static string GetUniqueSetName(string itemCode)
144 | {
145 | if (!setDescriptions.ContainsKey(itemCode))
146 | {
147 | return "UNKNOWN SET";
148 | }
149 |
150 | return setDescriptions[itemCode];
151 | }
152 |
153 | ///
154 | /// Item is armor
155 | ///
156 | /// Item code
157 | /// True if item is armor
158 | public static bool IsArmor(string itemCode)
159 | {
160 | return itemCodeSets["armor"].Contains(itemCode);
161 | }
162 |
163 | ///
164 | /// Item is a weapon
165 | ///
166 | /// Item code
167 | /// True if item is a weapon
168 | public static bool IsWeapon(string itemCode)
169 | {
170 | return itemCodeSets["weapons"].Contains(itemCode);
171 | }
172 |
173 | ///
174 | /// Item is stackable
175 | ///
176 | /// Item code
177 | /// True if item is stackable
178 | public static bool IsStackable(string itemCode)
179 | {
180 | return itemCodeSets["stackable"].Contains(itemCode);
181 | }
182 |
183 | ///
184 | /// Item is a monster part
185 | ///
186 | /// Item code
187 | /// True if item is a monster part
188 | public static bool IsMonsterPart(string itemCode)
189 | {
190 | return itemCodeSets["monsterparts"].Contains(itemCode);
191 | }
192 |
193 | ///
194 | /// Item is a scroll or tome
195 | ///
196 | /// Item code
197 | /// True if item is a scroll or tome
198 | public static bool IsScrollOrTome(string itemCode)
199 | {
200 | return itemCodeSets["scrolltome"].Contains(itemCode);
201 | }
202 |
203 | ///
204 | /// Item is a charm
205 | ///
206 | /// Item code
207 | /// True if item is a charm
208 | public static bool IsCharm(string itemCode)
209 | {
210 | return itemCodeSets["charms"].Contains(itemCode);
211 | }
212 |
213 | ///
214 | /// Reads multiple sets of item codes from disk. Each set has a unique section name defined in brackets (eg. [sectionName]).
215 | /// If multiple identical section names are exist, then the data for these sections are combined into the same set.
216 | ///
217 | /// Table of sets to store data
218 | /// Path containing sets of item codes
219 | ///
220 | ///
221 | /// [armor]
222 | /// cap Cap/hat
223 | /// skp Skull Cap
224 | ///
225 | /// [weapons]
226 | /// hax Hand Axe
227 | /// axe Axe
228 | ///
229 | ///
230 | public static void ReadItemCodeSet(Dictionary> itemCodeSets, string filePath)
231 | {
232 | List lines = Resources.Instance.ReadAllLines(filePath);
233 | HashSet currentSection = null;
234 |
235 | foreach (var line in lines)
236 | {
237 | if (line.Length <= 2)
238 | {
239 | continue;
240 | }
241 |
242 | if (line[0] == '[' && line[line.Length - 1] == ']')
243 | {
244 | string sectionName = line.Substring(1, line.Length - 2).ToLower();
245 |
246 | if (!itemCodeSets.ContainsKey(sectionName))
247 | {
248 | itemCodeSets.Add(sectionName, new HashSet());
249 | }
250 |
251 | currentSection = itemCodeSets[sectionName];
252 | }
253 | else if (currentSection != null)
254 | {
255 | string itemCode = line.Substring(0, 3).ToLower();
256 |
257 | currentSection.Add(itemCode);
258 | }
259 | }
260 | }
261 | }
262 | }
263 |
--------------------------------------------------------------------------------
/tools/esCharView/CharacterEditor/BitStream.resx:
--------------------------------------------------------------------------------
1 |
2 |
3 |
62 |
63 |
64 |
65 |
66 |
67 |
68 |
69 |
70 |
71 |
72 |
73 |
74 |
75 |
76 |
77 |
78 |
79 |
80 |
81 |
82 |
83 |
84 |
85 |
86 |
87 |
88 |
89 |
90 |
91 |
92 |
93 |
94 |
95 |
96 |
97 |
98 |
99 |
100 |
101 |
102 |
103 |
104 |
105 |
106 |
107 |
108 |
109 | text/microsoft-resx
110 |
111 |
112 | 2.0
113 |
114 |
115 | System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089
116 |
117 |
118 | System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089
119 |
120 |
121 | BitStream lengths must be the same.
122 |
123 |
124 | count + bitIndex exceeds the length of the 8-bit value.
125 |
126 |
127 | count + bitIndex exceeds the length of the 16-bit value.
128 |
129 |
130 | count + bitIndex exceeds the length of the 32-bit value.
131 |
132 |
133 | count + bitIndex exceeds the length of the 64-bit value.
134 |
135 |
136 | count + offset were out of bounds for the BitStream or count is greater than the number of elements from bitIndex to the end of the BitStream.
137 |
138 |
139 | count + offset were out of bounds for the array or count is greater than the number of elements from offset to the end of the array.
140 |
141 |
142 | The bit buffer cannot be null.
143 |
144 |
145 | The BitStream cannot be null.
146 |
147 |
148 | The Stream cannot be null.
149 |
150 |
151 | Capacity must be greater than zero.
152 |
153 |
154 | Parameter must be greater than or equal to zero.
155 |
156 |
157 | Position must be greater than or equal to zero.
158 |
159 |
160 | Position must be less than or equal to the Bit Stream Length.
161 |
162 |
163 | The internal bit buffer's bit index cannot be greater than 32.
164 |
165 |
166 | Asynchronous operations are not supported by the BitStream class.
167 |
168 |
169 | Cannot Flush a BitStream.
170 |
171 |
172 | Cannot Seek on a BitStream. Use Position property instead.
173 |
174 |
175 | Cannot SetLength of a BitStream.
176 |
177 |
178 | The inherited ReadByte method is not supported by the BitStream class. Use one of the overloaded Read methods instead.
179 |
180 |
181 | The inherited WriteByte method is not supported by the BitStream class. Use one of the overloaded Write methods instead.
182 |
183 |
184 | Cannot access a closed BitStream.
185 |
186 |
187 | count + bitIndex exceeds the length of the 128-bit value.
188 |
189 |
190 | count + bitIndex exceeds the length of the 16-bit value.
191 |
192 |
193 | The MemoryStream cannot be null.
194 |
195 |
196 | The FileStream cannot be null.
197 |
198 |
199 | The BufferedStream cannot be null.
200 |
201 |
202 | The NetworkStream cannot be null.
203 |
204 |
205 | The CryptoStream cannot be null.
206 |
207 |
--------------------------------------------------------------------------------
/tools/esCharView/CharacterEditor/Stat.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Linq;
4 | using System.Text;
5 | using System.Collections;
6 | using BKSystem.IO;
7 | using System.ComponentModel;
8 |
9 | namespace CharacterEditor
10 | {
11 | ///
12 | /// Controls access to character's stats
13 | ///
14 | public class Stat : INotifyPropertyChanged
15 | {
16 | ///
17 | /// Raw stat data from save file
18 | ///
19 | private byte[] statsBytes;
20 | ///
21 | /// Decoded stat values
22 | ///
23 | private Dictionary statValues = new Dictionary();
24 |
25 | public Stat(byte[] statsBytes)
26 | {
27 | if (statsBytes[0] != 'g' || statsBytes[1] != 'f')
28 | {
29 | throw new Exception("StatsByte data missing gf header");
30 | }
31 |
32 | this.statsBytes = statsBytes;
33 | ReadStats();
34 | }
35 |
36 | // TODO: Get rid of all of these individual properties?
37 | ///
38 | /// Base value of strength
39 | ///
40 | public int Strength
41 | {
42 | get { return GetStatValue("strength"); }
43 | set
44 | {
45 | SetStatValue("strength", value);
46 | OnPropertyChange("Strength");
47 | }
48 | }
49 | ///
50 | /// Base value of energy
51 | ///
52 | public int Energy
53 | {
54 | get { return GetStatValue("energy"); }
55 | set
56 | {
57 | SetStatValue("energy", value);
58 | OnPropertyChange("Energy");
59 | }
60 | }
61 | ///
62 | /// Base value of dexterity
63 | ///
64 | public int Dexterity
65 | {
66 | get { return GetStatValue("dexterity"); }
67 | set
68 | {
69 | SetStatValue("dexterity", value);
70 | OnPropertyChange("Dexterity");
71 | }
72 | }
73 | ///
74 | /// Base value of vitality
75 | ///
76 | public int Vitality
77 | {
78 | get { return GetStatValue("vitality"); }
79 | set
80 | {
81 | SetStatValue("vitality", value);
82 | OnPropertyChange("Vitality");
83 | }
84 | }
85 | ///
86 | /// Number of unallocated stat points
87 | ///
88 | public int StatPoints
89 | {
90 | get { return GetStatValue("statpts"); }
91 | set
92 | {
93 | SetStatValue("statpts", value);
94 | OnPropertyChange("StatPoints");
95 | }
96 | }
97 | ///
98 | /// Number of unallocated skill points
99 | ///
100 | public int SkillPoints
101 | {
102 | get { return GetStatValue("newskills"); }
103 | set
104 | {
105 | SetStatValue("newskills", value);
106 | OnPropertyChange("SkillPoints");
107 | }
108 | }
109 | ///
110 | /// Current value of hitpoints
111 | ///
112 | /// Current value is usually higher than base value
113 | public int Hitpoints
114 | {
115 | get { return GetStatValue("hitpoints"); }
116 | set
117 | {
118 | SetStatValue("hitpoints", value);
119 | OnPropertyChange("Hitpoints");
120 | }
121 | }
122 | ///
123 | /// Base value of hitpoints
124 | ///
125 | public int BaseHitpoints
126 | {
127 | get { return GetStatValue("maxhp"); }
128 | set
129 | {
130 | SetStatValue("maxhp", value);
131 | OnPropertyChange("BaseHitpoints");
132 | }
133 | }
134 | ///
135 | /// Current value of mana
136 | ///
137 | /// Current value is usually higher than base value
138 | public int Mana
139 | {
140 | get { return GetStatValue("mana"); }
141 | set
142 | {
143 | SetStatValue("mana", value);
144 | OnPropertyChange("Mana");
145 | }
146 | }
147 | ///
148 | /// Base value of mana
149 | ///
150 | public int BaseMana
151 | {
152 | get { return GetStatValue("maxmana"); }
153 | set
154 | {
155 | SetStatValue("maxmana", value);
156 | OnPropertyChange("BaseMana");
157 | }
158 | }
159 | ///
160 | /// Current value of stamina.
161 | ///
162 | /// Current value is usually higher than base value
163 | public int Stamina
164 | {
165 | get { return GetStatValue("stamina"); }
166 | set
167 | {
168 | SetStatValue("stamina", value);
169 | OnPropertyChange("Stamina");
170 | }
171 | }
172 | ///
173 | /// Base value of stamina
174 | ///
175 | public int BaseStamina
176 | {
177 | get { return GetStatValue("maxstamina"); }
178 | set
179 | {
180 | SetStatValue("maxstamina", value);
181 | OnPropertyChange("BaseStamina");
182 | }
183 | }
184 | ///
185 | /// Character's level
186 | ///
187 | public int Level
188 | {
189 | get { return GetStatValue("level"); }
190 | set
191 | {
192 | SetStatValue("level", value);
193 | OnPropertyChange("Level");
194 | }
195 | }
196 | ///
197 | /// Number of experience points character has
198 | ///
199 | public uint Experience
200 | {
201 | get { return (uint)GetStatValue("experience"); }
202 | set
203 | {
204 | SetStatValue("experience", (int)value);
205 | OnPropertyChange("Experience");
206 | }
207 | }
208 | ///
209 | /// Amount of gold character has in inventory
210 | ///
211 | public uint Gold
212 | {
213 | get { return (uint)GetStatValue("gold"); }
214 | set
215 | {
216 | SetStatValue("gold", (int)value);
217 | OnPropertyChange("Gold");
218 | }
219 | }
220 | ///
221 | /// Amount of gold character has in the bank
222 | ///
223 | public uint GoldBank
224 | {
225 | get { return (uint)GetStatValue("goldbank"); }
226 | set
227 | {
228 | SetStatValue("goldbank", (int)value);
229 | OnPropertyChange("GoldBank");
230 | }
231 | }
232 | ///
233 | /// Number of kills (Eastern sun only!)
234 | ///
235 | public int KillCount
236 | {
237 | get
238 | {
239 | if (Resources.Instance.ResourceSet == "es300_r6d")
240 | {
241 | return GetStatValue("kill_counter");
242 | }
243 | return 0;
244 | }
245 | set
246 | {
247 | if (Resources.Instance.ResourceSet == "es300_r6d")
248 | {
249 | SetStatValue("kill_counter", value);
250 | OnPropertyChange("KillCount");
251 | }
252 | }
253 | }
254 | ///
255 | /// Times character has died (Eastern sun only!)
256 | ///
257 | public int DeathCount
258 | {
259 | get
260 | {
261 | if (Resources.Instance.ResourceSet == "es300_r6d")
262 | {
263 | return GetStatValue("death_counter");
264 | }
265 | return 0;
266 | }
267 | set
268 | {
269 | if (Resources.Instance.ResourceSet == "es300_r6d")
270 | {
271 | SetStatValue("death_counter", value);
272 | OnPropertyChange("DeathCount");
273 | }
274 | }
275 | }
276 |
277 | ///
278 | /// Gets the specified stat's value
279 | ///
280 | /// Name of stat
281 | /// Value of stat or 0 if stat is not present
282 | private int GetStatValue(string name)
283 | {
284 | int statId = ItemDefs.ItemStatCostsByName[name].ID;
285 |
286 | if (!statValues.ContainsKey(statId))
287 | {
288 | return 0;
289 | }
290 |
291 | return statValues[statId];
292 | }
293 |
294 | ///
295 | /// Sets the specified stat to a given value or do nothing if stat is not present
296 | ///
297 | /// Name of stat
298 | /// Value to set stat to
299 | private void SetStatValue(string name, int value)
300 | {
301 | if (!ItemDefs.ItemStatCostsByName.ContainsKey(name))
302 | {
303 | throw new Exception("SetStatValue: Invalid stat name");
304 | }
305 |
306 | int statId = ItemDefs.ItemStatCostsByName[name].ID;
307 |
308 | // If value is 0, we assume user wants to delete the entry for that stat. 0 should
309 | // be default if no record exists when diablo loads the save so it should work out?
310 | if (value == 0)
311 | {
312 | statValues.Remove(statId);
313 | }
314 | else
315 | {
316 | statValues[statId] = value;
317 | }
318 | }
319 |
320 | ///
321 | /// Parses raw character stat data
322 | ///
323 | /// Raw characte stat data found between "gf" and "if" near offset 765 in save file
324 | /// Bit lengths of stat types are found in the CSvBits column of ItemStatCost.txt
325 | /// Source: http://phrozenkeep.hugelaser.com/forum/viewtopic.php?f=8&t=9011&start=50
326 | private void ReadStats()
327 | {
328 | BitStream bs = new BitStream(statsBytes);
329 |
330 | // Skip header bytes
331 | bs.SkipBits(8);
332 | bs.SkipBits(8);
333 |
334 | while (bs.RemainingBits >= 9)
335 | {
336 | // ID of stat (See ItemStatCost.txt)
337 | int statIndex = (int)bs.ReadReversed(9);
338 | // Value contains this many bits (See CSvBits in ItemStatCost.txt)
339 | int statValueBits = 0;
340 | // Value needs to be shifted by this amount
341 | int valShift = 0;
342 |
343 | // Terminating stat index
344 | if (statIndex == 0x1ff)
345 | {
346 | break;
347 | }
348 |
349 | statValueBits = ItemDefs.ItemStatCostsById[statIndex].CSvBits;
350 | if (statValueBits == 0)
351 | {
352 | break;
353 | }
354 |
355 | valShift = ItemDefs.ItemStatCostsById[(int)statIndex].ValShift;
356 |
357 | int statValue = (int)bs.ReadReversed(statValueBits);
358 | if (!statValues.ContainsKey(statIndex))
359 | {
360 | statValues.Add(statIndex, (statValue >> valShift));
361 | }
362 | }
363 | }
364 |
365 | ///
366 | /// Converts all stat data into raw data for save file
367 | ///
368 | /// Raw stat data ready for insertion into save file
369 | public byte[] GetStatBytes()
370 | {
371 | BitStream bits = new BitStream();
372 |
373 | bits.WriteReversed('g', 8);
374 | bits.WriteReversed('f', 8);
375 |
376 | var sortedValues = from n in statValues where true orderby n.Key select n;
377 |
378 | foreach (var stat in sortedValues)
379 | {
380 | bits.WriteReversed(stat.Key, 9);
381 |
382 | int valShift = 0;
383 | int bitCount = ItemDefs.ItemStatCostsById[stat.Key].CSvBits;
384 |
385 | if (ItemDefs.ItemStatCostsById.ContainsKey(stat.Key))
386 | {
387 | valShift = ItemDefs.ItemStatCostsById[stat.Key].ValShift;
388 | }
389 |
390 | bits.WriteReversed((uint)((stat.Value << valShift)), bitCount);
391 | }
392 |
393 | // Write termining stat index
394 | bits.WriteReversed(0x1ff, 9);
395 |
396 | // Add 0 padding to align to byte, if needed
397 | int remainingBitsForAlignment = 8 - (int)(bits.Position % 8);
398 | if (remainingBitsForAlignment > 0)
399 | {
400 | bits.WriteReversed(0, remainingBitsForAlignment);
401 | }
402 |
403 | return bits.ToReversedByteArray();
404 | }
405 |
406 | #region INotifyPropertyChanged Members
407 |
408 | public event PropertyChangedEventHandler PropertyChanged;
409 |
410 | ///
411 | /// Used to notify listeners that a property has changed. Mainly for data binding
412 | /// on the GUI
413 | ///
414 | /// Name of property that was changed
415 | private void OnPropertyChange(string propertyName)
416 | {
417 | if (PropertyChanged != null)
418 | {
419 | PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
420 | }
421 | }
422 |
423 | #endregion
424 | }
425 | }
426 |
--------------------------------------------------------------------------------
/tools/esCharView/CharacterEditor/SaveReader.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Linq;
4 | using System.Text;
5 | using System.IO;
6 |
7 | namespace CharacterEditor
8 | {
9 | public class SaveReader : ICloneable
10 | {
11 | ///
12 | /// Character's inventory
13 | ///
14 | private Inventory inventory;
15 | ///
16 | /// General character information
17 | ///
18 | private Character character;
19 | ///
20 | /// Character's stats
21 | ///
22 | private Stat stat;
23 | ///
24 | /// Character's skills
25 | ///
26 | private Skill skill;
27 | ///
28 | /// Unmodified character data from save file
29 | ///
30 | private byte[] OriginalCharacterBytes;
31 | ///
32 | /// Unmodified skill data from save file
33 | ///
34 | private byte[] OriginalSkillBytes;
35 | ///
36 | /// Unmodified inventory data from save file
37 | ///
38 | private byte[] OriginalInventoryBytes;
39 |
40 | ///
41 | /// Character's inventory
42 | ///
43 | public Inventory Inventory
44 | {
45 | get { return inventory; }
46 | }
47 |
48 | ///
49 | /// General character information
50 | ///
51 | public Character Character
52 | {
53 | get { return character; }
54 | }
55 |
56 | ///
57 | /// Character's stats (Str, dex, etc)
58 | ///
59 | public Stat Stat
60 | {
61 | get { return stat; }
62 | }
63 |
64 | ///
65 | /// Character's skills
66 | ///
67 | public Skill Skill
68 | {
69 | get { return skill; }
70 | }
71 |
72 | ///
73 | /// Position of the start of stat information (This should be hardcoded in all save files)
74 | ///
75 | private static int StatListBegin
76 | {
77 | get { return 765; }
78 | }
79 |
80 | ///
81 | /// Failed to decode character data
82 | ///
83 | public bool FailedCharacterDecoding { get; protected set; }
84 |
85 | ///
86 | /// Failed to decode skill data
87 | ///
88 | public bool FailedSkillDecoding { get; protected set; }
89 |
90 | ///
91 | /// Failed to decode inventory data
92 | ///
93 | public bool FailedInventoryDecoding { get; protected set; }
94 |
95 | ///
96 | /// Creates a new SaveReader
97 | ///
98 | public SaveReader(string resourceSet)
99 | {
100 | Resources.Instance.ResourceSet = resourceSet;
101 | ItemDefs.LoadItemDefs();
102 | }
103 |
104 | ///
105 | /// Creates a new SaveReader with specified save file bytes and begins to process the data
106 | ///
107 | /// Raw bytes from save file
108 | public SaveReader(byte[] rawCharacterData)
109 | {
110 | Read(rawCharacterData);
111 | }
112 |
113 | ///
114 | /// Read character save from disk
115 | ///
116 | /// Path of save file
117 | public void Read(byte[] rawCharacterData)
118 | {
119 | ReadHeaders(rawCharacterData);
120 | }
121 |
122 | public byte[] GetBytes(bool skipFailedData = false)
123 | {
124 | byte[] characterBytes = (skipFailedData && FailedCharacterDecoding) ? OriginalCharacterBytes : Character.GetCharacterBytes();
125 | byte[] statsBytes = Stat.GetStatBytes();
126 | byte[] skillBytes = (skipFailedData && FailedSkillDecoding) ? OriginalSkillBytes : Skill.GetSkillBytes();
127 | byte[] inventoryBytes = (skipFailedData && FailedInventoryDecoding) ? OriginalInventoryBytes : Inventory.GetInventoryBytes(Character.HasMercenary);
128 | byte[] rawCharacterData = new byte[characterBytes.Length + statsBytes.Length + skillBytes.Length + inventoryBytes.Length];
129 |
130 | Array.Copy(characterBytes, rawCharacterData, characterBytes.Length);
131 | Array.Copy(statsBytes, 0, rawCharacterData, characterBytes.Length, statsBytes.Length);
132 | Array.Copy(skillBytes, 0, rawCharacterData, characterBytes.Length + statsBytes.Length, skillBytes.Length);
133 | Array.Copy(inventoryBytes, 0, rawCharacterData, characterBytes.Length + statsBytes.Length + skillBytes.Length, inventoryBytes.Length);
134 |
135 | FixHeaders(ref rawCharacterData);
136 |
137 | return rawCharacterData;
138 | }
139 |
140 | ///
141 | /// Saves player data to specified path
142 | ///
143 | /// Path to save character data as
144 | public void Write(Stream saveFile, bool skipFailedData = false)
145 | {
146 | var rawCharacterData = GetBytes();
147 |
148 | using (BinaryWriter bw = new BinaryWriter(saveFile))
149 | {
150 | bw.Write(rawCharacterData);
151 | }
152 |
153 | //File.WriteAllBytes(filePath, rawCharacterData);
154 | }
155 |
156 | ///
157 | /// Splits character data into several sections for easier parsing
158 | ///
159 | private void ReadHeaders(byte[] rawCharacterData)
160 | {
161 | if (rawCharacterData[0] != 0x55 || rawCharacterData[1] != 0xAA || rawCharacterData[2] != 0x55 || rawCharacterData[3] != 0xAA)
162 | {
163 | throw new Exception("Not a Diablo II Save file");
164 | }
165 |
166 | OriginalCharacterBytes = null;
167 | OriginalSkillBytes = null;
168 | OriginalInventoryBytes = null;
169 |
170 | byte[] statBytes = GetStatBytes(rawCharacterData);
171 | byte[] characterBytes = GetCharacterBytes(rawCharacterData);
172 | byte[] skillBytes = GetSkillBytes(rawCharacterData);
173 | byte[] inventoryBytes = GetInventoryBytes(rawCharacterData);
174 |
175 | inventory = new Inventory(inventoryBytes);
176 | character = new Character(characterBytes);
177 | stat = new Stat(statBytes);
178 | skill = new Skill(skillBytes);
179 |
180 | // Stats will always be different, we're not reading the fractional portion of hp/mana/stamina
181 | FailedCharacterDecoding = !characterBytes.SequenceEqual(character.GetCharacterBytes());
182 | FailedSkillDecoding = !skillBytes.SequenceEqual(skill.GetSkillBytes());
183 | FailedInventoryDecoding = !inventoryBytes.SequenceEqual(inventory.GetInventoryBytes(character.HasMercenary));
184 |
185 | if (FailedCharacterDecoding)
186 | {
187 | OriginalCharacterBytes = characterBytes;
188 | }
189 | if (FailedInventoryDecoding)
190 | {
191 | OriginalInventoryBytes = inventoryBytes;
192 | }
193 | if (FailedSkillDecoding)
194 | {
195 | OriginalSkillBytes = skillBytes;
196 | }
197 | }
198 |
199 | ///
200 | /// Obtains general character information from raw save file data
201 | ///
202 | ///
203 | ///
204 | private static byte[] GetCharacterBytes(byte[] rawCharacterData)
205 | {
206 | byte[] characterBytes = new byte[StatListBegin];
207 | Array.Copy(rawCharacterData, characterBytes, characterBytes.Length);
208 |
209 | return characterBytes;
210 | }
211 |
212 | ///
213 | /// Copies character's raw stat data from raw header bytes
214 | ///
215 | /// Raw header data from save file
216 | /// Raw stat data
217 | private static byte[] GetStatBytes(byte[] rawCharacterBytes)
218 | {
219 | byte[] statsSection;
220 | int statsSectionLength = FindStatListEnd(rawCharacterBytes) - StatListBegin;
221 |
222 | statsSection = new byte[statsSectionLength];
223 | Array.Copy(rawCharacterBytes, StatListBegin, statsSection, 0, statsSection.Length);
224 |
225 | return statsSection;
226 | }
227 |
228 | ///
229 | /// Obtains skill information from raw save file data
230 | ///
231 | ///
232 | ///
233 | private static byte[] GetSkillBytes(byte[] rawCharacterData)
234 | {
235 | int itemListBegin = FindItemListBegin(rawCharacterData);
236 | int statListEnd = FindStatListEnd(rawCharacterData);
237 |
238 | byte[] skillBytes = new byte[itemListBegin - statListEnd];
239 | Array.Copy(rawCharacterData, statListEnd, skillBytes, 0, skillBytes.Length);
240 |
241 | return skillBytes;
242 | }
243 |
244 | ///
245 | /// Obtains inventory information from raw save file data
246 | ///
247 | ///
248 | ///
249 | private static byte[] GetInventoryBytes(byte[] rawCharacterData)
250 | {
251 | int itemListBegin = FindItemListBegin(rawCharacterData);
252 |
253 | byte[] inventoryBytes = new byte[rawCharacterData.Length - itemListBegin];
254 | Array.Copy(rawCharacterData, itemListBegin, inventoryBytes, 0, inventoryBytes.Length);
255 |
256 | return inventoryBytes;
257 | }
258 |
259 | ///
260 | /// Corrects checksum of new player data
261 | ///
262 | /// Raw player save data
263 | private void FixHeaders(ref byte[] rawCharacterData)
264 | {
265 | byte[] fileSizeBytes = BitConverter.GetBytes(rawCharacterData.Length);
266 | Array.Copy(fileSizeBytes, 0, rawCharacterData, 8, 4);
267 |
268 | uint checksum = CalculateChecksum(rawCharacterData);
269 |
270 | byte[] checksumBytes = BitConverter.GetBytes(checksum);
271 | Array.Copy(checksumBytes, 0, rawCharacterData, 12, 4);
272 | }
273 |
274 | //
275 | ///
276 | /// Calculates a new checksum for specified data
277 | ///
278 | /// Raw character data
279 | /// Checksum for specified data
280 | /// Source: ehertlein ( http://forums.diii.net/showthread.php?t=532037&page=41 )
281 | private static uint CalculateChecksum(byte[] fileBytes)
282 | {
283 | uint hexTest = 0x80000000;
284 | uint checksum = 0;
285 |
286 | // clear out the old checksum
287 | fileBytes[12] = 0;
288 | fileBytes[13] = 0;
289 | fileBytes[14] = 0;
290 | fileBytes[15] = 0;
291 |
292 | foreach (byte currentByte in fileBytes)
293 | {
294 | if ((checksum & hexTest) == hexTest)
295 | {
296 | checksum = checksum << 1;
297 | checksum = checksum + 1;
298 | }
299 | else
300 | {
301 | checksum = checksum << 1;
302 | }
303 |
304 | checksum += currentByte;
305 | }
306 |
307 | return checksum;
308 | }
309 |
310 | ///
311 | /// Returns the location of the inventory data
312 | ///
313 | /// Raw bytes from save file
314 | /// Location of inventory data
315 | private static int FindItemListBegin(byte[] rawCharacterData)
316 | {
317 | for (int i = StatListBegin; i < rawCharacterData.Length - 5; i++)
318 | {
319 | if (rawCharacterData[i] == 'J' && rawCharacterData[i + 1] == 'M')
320 | {
321 | // JM..JM is the pattern we're looking for
322 | if (rawCharacterData[i + 4] == 'J' && rawCharacterData[i + 5] == 'M')
323 | {
324 | return i;
325 | }
326 | }
327 | }
328 |
329 | return 0;
330 | }
331 |
332 | ///
333 | /// Returns location right after the end of the character's stat list
334 | ///
335 | /// Raw data from save file
336 | /// Location of the end of character's stat list
337 | private static int FindStatListEnd(byte[] rawCharacterBytes)
338 | {
339 | int itemListBegin = FindItemListBegin(rawCharacterBytes);
340 |
341 | if (rawCharacterBytes[itemListBegin - 37] == 'i' && rawCharacterBytes[itemListBegin - 36] == 'f')
342 | {
343 | return itemListBegin - 37;
344 | }
345 |
346 | for (int i = FindItemListBegin(rawCharacterBytes); i > StatListBegin; i--)
347 | {
348 | if (rawCharacterBytes[i] == 'i' && rawCharacterBytes[i + 1] == 'f')
349 | {
350 | return i;
351 | }
352 | }
353 |
354 | throw new Exception("End of stat list not found!");
355 | }
356 |
357 | ///
358 | /// Move all allocated skill and stat points to pool of unspent points. Fails if golem exists
359 | ///
360 | /// TODO: Untested!
361 | public void Respec()
362 | {
363 | if (Inventory.GolemItems.Count > 0)
364 | {
365 | throw new Exception("Respec: Cannot respec with an active golem");
366 | }
367 |
368 | int totalSkillPoints = Stat.SkillPoints;
369 | int totalStatPoints = stat.StatPoints;
370 |
371 | for (int i = 0; i < Skill.Length; i++)
372 | {
373 | totalSkillPoints += Skill[i];
374 | Skill[i] = 0;
375 | }
376 |
377 | totalStatPoints += Stat.Strength;
378 | totalStatPoints += Stat.Dexterity;
379 | totalStatPoints += Stat.Vitality;
380 | totalStatPoints += Stat.Energy;
381 |
382 | Stat.Strength = 0;
383 | Stat.Dexterity = 0;
384 | Stat.Vitality = 0;
385 | Stat.Energy = 0;
386 |
387 | Stat.SkillPoints = totalSkillPoints;
388 | Stat.StatPoints = totalStatPoints;
389 | }
390 |
391 | public object Clone()
392 | {
393 | return this.MemberwiseClone();
394 | }
395 | }
396 | }
397 |
--------------------------------------------------------------------------------
/tools/esCharView/CharacterEditor/Resources/1.13c/AllItems.txt:
--------------------------------------------------------------------------------
1 | elx elixir
2 | hpo Healing Potion
3 | mpo Mana Potion
4 | hpf Full Healing Potion
5 | mpf Full Mana Potion
6 | vps Stamina Potion
7 | yps Antidote Potion
8 | rvs Rejuv Potion
9 | rvl Full Rejuv Potion
10 | wms Thawing Potion
11 | tbk Town Portal Book
12 | ibk Identify Book
13 | amu amulet
14 | vip viper amulet
15 | rin ring
16 | gld gold
17 | bks Bark Scroll
18 | bkd deciphered Bark Scroll
19 | aqv Arrows
20 | tch Torch
21 | cqv Bolts
22 | tsc Town Portal Scroll
23 | isc Identify Scroll
24 | hrt Heart
25 | brz Brain
26 | jaw Jawbone
27 | eyz Eye
28 | hrn Horn
29 | tal Tail
30 | flg Flag
31 | fng Fang
32 | qll Quill
33 | sol Soul
34 | scz Scalp
35 | spe Spleen
36 | key Skeleton Key
37 | luv Mephisto Key
38 | xyz scroll of self resurrect
39 | j34 jade figurine
40 | g34 gold bird
41 | bbb lam esen's tome
42 | box Horadric Cube
43 | tr1 Scroll of Horadric Quest Info
44 | mss Mephisto SoulStone
45 | ass Book of Skill
46 | qey KhalimEye
47 | qhr KhalimHeart
48 | qbr KhalimBrain
49 | ear Player Ear
50 | gcv Chipped Amethyst
51 | gfv Flawed Amethyst
52 | gsv Amethyst
53 | gzv Flawless Amethyst
54 | gpv Perfect Amethyst
55 | gcy Chipped Topaz
56 | gfy Flawed Topaz
57 | gsy Topaz
58 | gly Flawless Topaz
59 | gpy Perfect Topaz
60 | gcb Chipped Saphire
61 | gfb Flawed Saphire
62 | gsb Saphire
63 | glb Flawless Saphire
64 | gpb Perfect Saphire
65 | gcg Chipped Emerald
66 | gfg Flawed Emerald
67 | gsg Emerald
68 | glg Flawless Emerald
69 | gpg Perfect Emerald
70 | gcr Chipped Ruby
71 | gfr Flawed Ruby
72 | gsr Ruby
73 | glr Flawless Ruby
74 | gpr Perfect Ruby
75 | gcw Chipped Diamond
76 | gfw Flawed Diamond
77 | gsw Diamond
78 | glw Flawless Diamond
79 | gpw Perfect Diamond
80 | hp1 Lesser Healing Potion
81 | hp2 Light Healing Potion
82 | hp3 Healing Potion
83 | hp4 Strong Healing Potion
84 | hp5 Greater Healing Potion
85 | mp1 Lesser Mana Potion
86 | mp2 Light Mana Potion
87 | mp3 Mana Potion
88 | mp4 Strong Mana Potion
89 | mp5 Greater Mana Potion
90 | skc Chipped Skull
91 | skf Flawed Skull
92 | sku Skull
93 | skl Flawless Skull
94 | skz Perfect Skull
95 | hrb herb
96 | cm1 Charm Small
97 | cm2 Charm Medium
98 | cm3 Charm Large
99 | rps Small Red Potion
100 | rpl Large Red Potion
101 | bps Small Blue Potion
102 | bpl Large Blue Potion
103 | r01 El
104 | r02 Eld
105 | r03 Tir
106 | r04 Nef
107 | r05 Eth
108 | r06 Ith
109 | r07 Tal
110 | r08 Ral
111 | r09 Ort
112 | r10 Thul
113 | r11 Amn
114 | r12 Sol
115 | r13 Shael
116 | r14 Dol
117 | r15 Hel
118 | r16 Io
119 | r17 Lum
120 | r18 Ko
121 | r19 Fal
122 | r20 Lem
123 | r21 Pul
124 | r22 Um
125 | r23 Mal
126 | r24 Ist
127 | r25 Gul
128 | r26 Vex
129 | r27 Ohm
130 | r28 Lo
131 | r29 Sur
132 | r30 Ber
133 | r31 Jah
134 | r32 Cham
135 | r33 Zod
136 | jew Jewel
137 | ice ice
138 | 0sc Scroll
139 | tr2 Scroll of Malah - Boost Resistances
140 | pk1 Pandemonium Key 1
141 | pk2 Pandemonium Key 2
142 | pk3 Pandemonium Key 3
143 | dhn Diablo's Horn
144 | bey Baal's Eye
145 | mbr Mephisto's Brain
146 | toa Token of Absolution
147 | tes Twisted Essence of Suffering
148 | ceh Charged Essense of Hatred
149 | bet Burning Essence of Terror
150 | fed Festering Essence of Destruction
151 | std Standard
152 | cap Cap/hat
153 | skp Skull Cap
154 | hlm Helm
155 | fhl Full Helm
156 | ghm Great Helm
157 | crn Crown
158 | msk Mask
159 | qui Quilted Armor
160 | lea Leather Armor
161 | hla Hard Leather Armor
162 | stu Studded Leather
163 | rng Ring Mail
164 | scl Scale Mail
165 | chn Chain Mail
166 | brs Breast Plate
167 | spl Splint Mail
168 | plt Plate Mail
169 | fld Field Plate
170 | gth Gothic Plate
171 | ful Full Plate Mail
172 | aar Ancient Armor
173 | ltp Light Plate
174 | buc Buckler
175 | sml Small Shield
176 | lrg Large Shield
177 | kit Kite Shield
178 | tow Tower Shield
179 | gts Gothic Shield
180 | lgl Gloves(L)
181 | vgl Heavy Gloves
182 | mgl Bracers(M)
183 | tgl Light Gauntlets
184 | hgl Gaunlets(H)
185 | lbt Leather Boots
186 | vbt Heavy Boots
187 | mbt Chain Boots
188 | tbt Light Plate Boots
189 | hbt Plate Boots
190 | lbl Sash(L)
191 | vbl Light Belt
192 | mbl Belt(M)
193 | tbl Heavy Belt
194 | hbl Girdle(H)
195 | bhm Bone Helm
196 | bsh Bone Shield
197 | spk Spiked Shield
198 | xap War Hat
199 | xkp Sallet
200 | xlm Casque
201 | xhl Basinet
202 | xhm Winged Helm
203 | xrn Grand Crown
204 | xsk Death Mask
205 | xui Ghost Armor
206 | xea Serpentskin Armor
207 | xla Demonhide Armor
208 | xtu Trellised Armor
209 | xng Linked Mail
210 | xcl Tigulated Mail
211 | xhn Mesh Armor
212 | xrs Cuirass
213 | xpl Russet Armor
214 | xlt Templar Coat
215 | xld Sharktooth Armor
216 | xth Embossed Plate
217 | xul Chaos Armor
218 | xar Ornate Armor
219 | xtp Mage Plate
220 | xuc Defender
221 | xml Round Shield
222 | xrg Scutum
223 | xit Dragon Shield
224 | xow Pavise
225 | xts Ancient Shield
226 | xlg Demonhide Gloves
227 | xvg Sharkskin Gloves
228 | xmg Heavy Bracers
229 | xtg Battle Gauntlets
230 | xhg War Gauntlets
231 | xlb Demonhide Boots
232 | xvb Sharkskin Boots
233 | xmb Mesh Boots
234 | xtb Battle Boots
235 | xhb War Boots
236 | zlb Demonhide Sash
237 | zvb Sharkskin Belt
238 | zmb Mesh Belt
239 | ztb Battle Belt
240 | zhb War Belt
241 | xh9 Grim Helm
242 | xsh Grim Shield
243 | xpk Barbed Shield
244 | dr1 Wolf Head
245 | dr2 Hawk Helm
246 | dr3 Antlers
247 | dr4 Falcon Mask
248 | dr5 Spirit Mask
249 | ba1 Jawbone Cap
250 | ba2 Fanged Helm
251 | ba3 Horned Helm
252 | ba4 Assault Helmet
253 | ba5 Avenger Guard
254 | pa1 Targe
255 | pa2 Rondache
256 | pa3 Heraldic Shield
257 | pa4 Aerin Shield
258 | pa5 Crown Shield
259 | ne1 Preserved Head
260 | ne2 Zombie Head
261 | ne3 Unraveller Head
262 | ne4 Gargoyle Head
263 | ne5 Demon Head
264 | ci0 Circlet
265 | ci1 Coronet
266 | ci2 Tiara
267 | ci3 Diadem
268 | uap Shako
269 | ukp Hydraskull
270 | ulm Armet
271 | uhl Giant Conch
272 | uhm Spired Helm
273 | urn Corona
274 | usk Demonhead
275 | uui Dusk Shroud
276 | uea Wyrmhide
277 | ula Scarab Husk
278 | utu Wire Fleece
279 | ung Diamond Mail
280 | ucl Loricated Mail
281 | uhn Boneweave
282 | urs Great Hauberk
283 | upl Balrog Skin
284 | ult Hellforged Plate
285 | uld Kraken Shell
286 | uth Lacquered Plate
287 | uul Shadow Plate
288 | uar Sacred Armor
289 | utp Archon Plate
290 | uuc Heater
291 | uml Luna
292 | urg Hyperion
293 | uit Monarch
294 | uow Aegis
295 | uts Ward
296 | ulg Bramble Mitts
297 | uvg Vampirebone Gloves
298 | umg Vambraces
299 | utg Crusader Gauntlets
300 | uhg Ogre Gauntlets
301 | ulb Wyrmhide Boots
302 | uvb Scarabshell Boots
303 | umb Boneweave Boots
304 | utb Mirrored Boots
305 | uhb Myrmidon Greaves
306 | ulc Spiderweb Sash
307 | uvc Vampirefang Belt
308 | umc Mithril Coil
309 | utc Troll Belt
310 | uhc Colossus Girdle
311 | uh9 Bone Visage
312 | ush Troll Nest
313 | upk Blade Barrier
314 | dr6 Alpha Helm
315 | dr7 Griffon Headress
316 | dr8 Hunter's Guise
317 | dr9 Sacred Feathers
318 | dra Totemic Mask
319 | ba6 Jawbone Visor
320 | ba7 Lion Helm
321 | ba8 Rage Mask
322 | ba9 Savage Helmet
323 | baa Slayer Guard
324 | pa6 Akaran Targe
325 | pa7 Akaran Rondache
326 | pa8 Protector Shield
327 | pa9 Guilded Shield
328 | paa Royal Shield
329 | ne6 Mummified Trophy
330 | ne7 Fetish Trophy
331 | ne8 Sexton Trophy
332 | ne9 Cantor Trophy
333 | nea Heirophant Trophy
334 | drb Blood Spirt
335 | drc Sun Spirit
336 | drd Earth Spirit
337 | dre Sky Spirit
338 | drf Dream Spirit
339 | bab Carnage Helm
340 | bac Fury Visor
341 | bad Destroyer Helm
342 | bae Conquerer Crown
343 | baf Guardian Crown
344 | pab Sacred Targe
345 | pac Sacred Rondache
346 | pad Ancient Shield
347 | pae Zakarum Shield
348 | paf Vortex Shield
349 | neb Minion Skull
350 | neg Hellspawn Skull
351 | ned Overseer Skull
352 | nee Succubae Skull
353 | nef Bloodlord Skull
354 | hax Hand Axe
355 | axe Axe
356 | 2ax Double Axe
357 | mpi Military Pick
358 | wax War Axe
359 | lax Large Axe
360 | bax Broad Axe
361 | btx Battle Axe
362 | gax Great Axe
363 | gix Giant Axe
364 | wnd Wand
365 | ywn Yew Wand
366 | bwn Bone Wand
367 | gwn Grim Wand
368 | clb Club
369 | scp Scepter
370 | gsc Grand Scepter
371 | wsp War Scepter
372 | spc Spiked Club
373 | mac Mace
374 | mst Morning Star
375 | fla Flail
376 | whm War Hammer
377 | mau Maul
378 | gma Great Maul
379 | ssd Short Sword
380 | scm Scimitar
381 | sbr Saber
382 | flc Falchion
383 | crs Crystal Sword
384 | bsd Broad Sword
385 | lsd Long Sword
386 | wsd War Sword
387 | 2hs Two-Handed Sword
388 | clm Claymore
389 | gis Giant Sword
390 | bsw Bastard Sword
391 | flb Flamberge
392 | gsd Great Sword
393 | dgr Dagger
394 | dir Dirk
395 | kri Kriss
396 | bld Blade
397 | tkf Throwing Knife
398 | tax Throwing Axe
399 | bkf Balanced Knife
400 | bal Balanced Axe
401 | jav Javelin
402 | pil Pilum
403 | ssp Short Spear
404 | glv Glaive
405 | tsp Throwing Spear
406 | spr Spear
407 | tri Trident
408 | brn Brandistock
409 | spt Spetum
410 | pik Pike
411 | bar Bardiche
412 | vou Voulge
413 | scy Scythe
414 | pax Poleaxe
415 | hal Halberd
416 | wsc War Scythe
417 | sst Short Staff
418 | lst Long Staff
419 | cst Gnarled Staff
420 | bst Battle Staff
421 | wst War Staff
422 | sbw Short Bow
423 | hbw Hunter's Bow
424 | lbw Long Bow
425 | cbw Composite Bow
426 | sbb Short Battle Bow
427 | lbb Long Battle Bow
428 | swb Short War Bow
429 | lwb Long War Bow
430 | lxb Light Crossbow
431 | mxb Crossbow
432 | hxb Heavy Crossbow
433 | rxb Repeating Crossbow
434 | gps Rancid Gas Potion
435 | ops Oil Potion
436 | gpm Choking Gas Potion
437 | opm Exploding Potion
438 | gpl Strangling Gas Potion
439 | opl Fulminating Potion
440 | d33 decoy dagger
441 | g33 Gidbinn
442 | leg Wirt's Leg
443 | hdm Horadric Malus
444 | hfh Hellforge Hammer
445 | hst Horadric Staff
446 | msf Staff of the Kings
447 | 9ha Hatchet
448 | 9ax Cleaver
449 | 92a Twin Axe
450 | 9mp Crowbill
451 | 9wa Naga
452 | 9la Military Axe
453 | 9ba Bearded Axe
454 | 9bt Tabar
455 | 9ga Gothic Axe
456 | 9gi Ancient Axe
457 | 9wn Burnt Wand
458 | 9yw Petrified Wand
459 | 9bw Tomb Wand
460 | 9gw Grave Wand
461 | 9cl Cudgel
462 | 9sc Rune Scepter
463 | 9qs Holy Water Sprinkler
464 | 9ws Divine Scepter
465 | 9sp Barbed Club
466 | 9ma Flanged Mace
467 | 9mt Jagged Star
468 | 9fl Knout
469 | 9wh Battle Hammer
470 | 9m9 War Club
471 | 9gm Martel de Fer
472 | 9ss Gladius
473 | 9sm Cutlass
474 | 9sb Shamshir
475 | 9fc Tulwar
476 | 9cr Dimensional Blade
477 | 9bs Battle Sword
478 | 9ls Rune Sword
479 | 9wd Ancient Sword
480 | 92h Espadon
481 | 9cm Dacian Falx
482 | 9gs Tusk Sword
483 | 9b9 Gothic Sword
484 | 9fb Zweihander
485 | 9gd Executioner Sword
486 | 9dg Poignard
487 | 9di Rondel
488 | 9kr Cinquedeas
489 | 9bl Stilleto
490 | 9tk Battle Dart
491 | 9ta Francisca
492 | 9bk War Dart
493 | 9b8 Hurlbat
494 | 9ja War Javelin
495 | 9pi Great Pilum
496 | 9s9 Simbilan
497 | 9gl Spiculum
498 | 9ts Harpoon
499 | 9sr War Spear
500 | 9tr Fuscina
501 | 9br War Fork
502 | 9st Yari
503 | 9p9 Lance
504 | 9b7 Lochaber Axe
505 | 9vo Bill
506 | 9s8 Battle Scythe
507 | 9pa Partizan
508 | 9h9 Bec-de-Corbin
509 | 9wc Grim Scythe
510 | 8ss Jo Staff
511 | 8ls Quarterstaff
512 | 8cs Cedar Staff
513 | 8bs Gothic Staff
514 | 8ws Rune Staff
515 | 8sb Edge Bow
516 | 8hb Razor Bow
517 | 8lb Cedar Bow
518 | 8cb Double Bow
519 | 8s8 Short Siege Bow
520 | 8l8 Long Siege Bow
521 | 8sw Rune Bow
522 | 8lw Gothic Bow
523 | 8lx Arbalest
524 | 8mx Siege Crossbow
525 | 8hx Balista
526 | 8rx Chu-Ko-Nu
527 | qf1 KhalimFlail
528 | qf2 SuperKhalimFlail
529 | ktr Katar
530 | wrb Wrist Blade
531 | axf Hatchet Hands
532 | ces Cestus
533 | clw Claws
534 | btl Blade Talons
535 | skr Scissors Katar
536 | 9ar Quhab
537 | 9wb Wrist Spike
538 | 9xf Fascia
539 | 9cs Hand Scythe
540 | 9lw Greater Claws
541 | 9tw Greater Talons
542 | 9qr Scissors Quhab
543 | 7ar Suwayyah
544 | 7wb Wrist Sword
545 | 7xf War Fist
546 | 7cs Battle Cestus
547 | 7lw Feral Claws
548 | 7tw Runic Talons
549 | 7qr Scissors Suwayyah
550 | 7ha Tomahawk
551 | 7ax Small Crescent
552 | 72a Ettin Axe
553 | 7mp War Spike
554 | 7wa Berserker Axe
555 | 7la Feral Axe
556 | 7ba Silver Edged Axe
557 | 7bt Decapitator
558 | 7ga Champion Axe
559 | 7gi Glorious Axe
560 | 7wn Polished Wand
561 | 7yw Ghost Wand
562 | 7bw Lich Wand
563 | 7gw Unearthed Wand
564 | 7cl Truncheon
565 | 7sc Mighty Scepter
566 | 7qs Seraph Rod
567 | 7ws Caduceus
568 | 7sp Tyrant Club
569 | 7ma Reinforced Mace
570 | 7mt Devil Star
571 | 7fl Scourge
572 | 7wh Legendary Mallet
573 | 7m7 Ogre Maul
574 | 7gm Thunder Maul
575 | 7ss Falcata
576 | 7sm Ataghan
577 | 7sb Elegant Blade
578 | 7fc Hydra Edge
579 | 7cr Phase Blade
580 | 7bs Conquest Sword
581 | 7ls Cryptic Sword
582 | 7wd Mythical Sword
583 | 72h Legend Sword
584 | 7cm Highland Blade
585 | 7gs Balrog Blade
586 | 7b7 Champion Sword
587 | 7fb Colossal Sword
588 | 7gd Colossus Blade
589 | 7dg Bone Knife
590 | 7di Mithral Point
591 | 7kr Fanged Knife
592 | 7bl Legend Spike
593 | 7tk Flying Knife
594 | 7ta Flying Axe
595 | 7bk Winged Knife
596 | 7b8 Winged Axe
597 | 7ja Hyperion Javelin
598 | 7pi Stygian Pilum
599 | 7s7 Balrog Spear
600 | 7gl Ghost Glaive
601 | 7ts Winged Harpoon
602 | 7sr Hyperion Spear
603 | 7tr Stygian Pike
604 | 7br Mancatcher
605 | 7st Ghost Spear
606 | 7p7 War Pike
607 | 7o7 Ogre Axe
608 | 7vo Colossus Voulge
609 | 7s8 Thresher
610 | 7pa Cryptic Axe
611 | 7h7 Great Poleaxe
612 | 7wc Giant Thresher
613 | 6ss Walking Stick
614 | 6ls Stalagmite
615 | 6cs Elder Staff
616 | 6bs Shillelah
617 | 6ws Archon Staff
618 | 6sb Spider Bow
619 | 6hb Blade Bow
620 | 6lb Shadow Bow
621 | 6cb Great Bow
622 | 6s7 Diamond Bow
623 | 6l7 Crusader Bow
624 | 6sw Ward Bow
625 | 6lw Hydra Bow
626 | 6lx Pellet Bow
627 | 6mx Gorgon Crossbow
628 | 6hx Colossus Crossbow
629 | 6rx Demon Crossbow
630 | ob1 Eagle Orb
631 | ob2 Sacred Globe
632 | ob3 Smoked Sphere
633 | ob4 Clasped Orb
634 | ob5 Dragon Stone
635 | am1 Stag Bow
636 | am2 Reflex Bow
637 | am3 Maiden Spear
638 | am4 Maiden Pike
639 | am5 Maiden Javelin
640 | ob6 Glowing Orb
641 | ob7 Crystalline Globe
642 | ob8 Cloudy Sphere
643 | ob9 Sparkling Ball
644 | oba Swirling Crystal
645 | am6 Ashwood Bow
646 | am7 Ceremonial Bow
647 | am8 Ceremonial Spear
648 | am9 Ceremonial Pike
649 | ama Ceremonial Javelin
650 | obb Heavenly Stone
651 | obc Eldritch Orb
652 | obd Demon Heart
653 | obe Vortex Orb
654 | obf Dimensional Shard
655 | amb Matriarchal Bow
656 | amc Grand Matron Bow
657 | amd Matriarchal Spear
658 | ame Matriarchal Pike
659 | amf MatriarchalJavelin
--------------------------------------------------------------------------------
/tools/esCharView/CharacterEditor/Inventory.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 |
4 | namespace CharacterEditor
5 | {
6 | public class Inventory
7 | {
8 | public Inventory(byte[] inventoryBytes)
9 | {
10 | ProcessInventoryBytes(inventoryBytes);
11 | }
12 |
13 | enum ItemContainer
14 | {
15 | Player,
16 | Corpse,
17 | Mercenary,
18 | Golem
19 | }
20 |
21 | private byte[] unknownCorpseData = new byte[12];
22 | private List
- playerItems = new List
- ();
23 | private List
- corpseItems = new List
- ();
24 | private List
- mercItems = new List
- ();
25 | private List
- golemItems = new List
- ();
26 |
27 | ///
28 | /// All player items
29 | ///
30 | public List
- PlayerItems
31 | {
32 | get { return playerItems; }
33 | set { playerItems = value; }
34 | }
35 |
36 | ///
37 | /// Items in corpse
38 | ///
39 | public List
- CorpseItems
40 | {
41 | get { return corpseItems; }
42 | set { corpseItems = value; }
43 | }
44 |
45 | ///
46 | /// Mercenary equipment
47 | ///
48 | public List
- MercItems
49 | {
50 | get { return mercItems; }
51 | set { mercItems = value; }
52 | }
53 |
54 | ///
55 | /// Item(s) golem was created from
56 | ///
57 | public List
- GolemItems
58 | {
59 | get { return golemItems; }
60 | set { golemItems = value; }
61 | }
62 |
63 | ///
64 | /// Number of items failed to be parsed, items will not be included when saving data
65 | ///
66 | public int FailedItemCount
67 | {
68 | get;
69 | protected set;
70 | }
71 |
72 | ///
73 | /// Obtains the length of next Item in raw inventory data at specified position
74 | ///
75 | /// Raw inventory data
76 | /// Position in raw inventory data to start looking for item
77 | /// Length in bytes of next item
78 | private int GetNextItemSize(byte[] inventoryBytes, int begin)
79 | {
80 | for (int i = begin + 2; i < inventoryBytes.Length - 1; i++)
81 | {
82 | // Header of next item record or end of inventory list reached
83 | if (inventoryBytes[i] == 'J' && inventoryBytes[i + 1] == 'M')
84 | {
85 | return i - begin;
86 | }
87 | }
88 |
89 | return inventoryBytes.Length - begin;
90 | }
91 |
92 | ///
93 | /// Retrieves the next item from specified position in raw inventory data
94 | ///
95 | /// Raw inventory data
96 | /// Position in raw inventory data to start looking for item
97 | /// Next item in raw inventory data
98 | private Item GetNextItem(byte[] inventoryBytes, ref int begin)
99 | {
100 | int itemDataSize = GetNextItemSize(inventoryBytes, begin);
101 | byte[] itemData = new byte[itemDataSize];
102 | Array.Copy(inventoryBytes, begin, itemData, 0, itemDataSize);
103 |
104 | Item item;
105 |
106 | // TODO: This is a horror - should be rewritten soon
107 | try
108 | {
109 | item = new Item(itemData);
110 | }
111 | catch (IndexOutOfRangeException)
112 | {
113 | // Using a new itemDataSize because if this fails we need to increase begin by the original
114 | // itemDataSize
115 | int itemDataSizeNew = itemDataSize + GetNextItemSize(inventoryBytes, begin + itemDataSize);
116 |
117 | try
118 | {
119 | // Assume the JM found by GetNextItemSize was just part of the item's data.
120 | // Recalculate the length of the item ignoring the first JM it encounters
121 | itemData = new byte[itemDataSizeNew];
122 | Array.Copy(inventoryBytes, begin, itemData, 0, itemData.Length);
123 | item = new Item(itemData);
124 | }
125 | catch (IndexOutOfRangeException)
126 | {
127 | // Not recoverable, handled by code below
128 | item = null;
129 | }
130 |
131 | if (item == null)
132 | {
133 | // Item not recoverable, skip it
134 | FailedItemCount++;
135 | begin += itemDataSize;
136 | return null;
137 | }
138 | else
139 | {
140 | // Set the new itemDataSize since the we fixed the problem
141 | itemDataSize = itemDataSizeNew;
142 | }
143 | }
144 |
145 | begin += itemDataSize;
146 | if (item.IsSocketed)
147 | {
148 | uint failedSockets = 0;
149 |
150 | for (int i = 0; i < item.SocketsFilled; i++)
151 | {
152 | Item nextItem = GetNextItem(inventoryBytes, ref begin);
153 |
154 | if (nextItem == null)
155 | {
156 | failedSockets++;
157 | continue;
158 | }
159 |
160 | item.Sockets.Add(nextItem);
161 | }
162 |
163 | if (failedSockets > 0)
164 | {
165 | item.ClearRunewordData();
166 |
167 | for (int i = 0; i < item.Sockets.Count; i++)
168 | {
169 | Item socketedItem = item.Sockets[i].RemoveSocketedItem(i);
170 | CorpseItems.Add(socketedItem);
171 | }
172 | }
173 | }
174 |
175 | return item;
176 | }
177 |
178 | ///
179 | /// Separates raw inventory data into more specific chunks of data
180 | ///
181 | /// Raw inventory data from save file
182 | /// Inventory data for player
183 | /// Unknown data for corpse
184 | /// Inventory data for corpse
185 | /// Inventory data for mercenary
186 | /// Inventory data for golem
187 | private void SplitInventoryBytes(byte[] inventoryBytes,
188 | out byte[] playerInventoryBytes,
189 | out byte[] unknownCorpseDataBytes,
190 | out byte[] corpseInventoryBytes,
191 | out byte[] mercInventoryBytes,
192 | out byte[] golemInventoryBytes)
193 | {
194 | int playerInventoryLength = 0;
195 | int unknownCorpseDataLength = 0;
196 | int corpseInventoryLength = 0;
197 | int mercInventoryLength = 0;
198 | int golemInventoryLength = 0;
199 |
200 | int playerInventoryStart = 0;
201 | int unknownCorpseDataStart = 0;
202 | int corpseInventoryStart = 0;
203 | int mercInventoryStart = 0;
204 | int golemInventoryStart = 0;
205 |
206 | bool hasCorpseData = false;
207 |
208 | //TODO: Trust item count header and use it to detect player/corpse/merc/golem sections
209 |
210 | // Player inventory data ends with "JM\x00\x00" or "JM\x01\x00". Using +4 because we want to skip the initial JM## bytes.
211 | playerInventoryStart = 0;
212 | for (int i = playerInventoryStart + 4; i < inventoryBytes.Length; i++)
213 | {
214 | // End of player inventory list
215 | if (inventoryBytes[i] == 'J' && inventoryBytes[i + 1] == 'M' && inventoryBytes[i + 3] == 0x00)
216 | {
217 | // Corpse exists if JM\x01\x00 followed by 12 unknown bytes and JM (the first corpse item entry)
218 | if (inventoryBytes[i + 2] == 0x01 && inventoryBytes[i + 16] == 'J' && inventoryBytes[i + 17] == 'M')
219 | {
220 | hasCorpseData = true;
221 | playerInventoryLength = i - playerInventoryStart;
222 | break;
223 | }
224 | // No corpse exists if JM\x00\x00 followed by jf (ending tag of corpse data)
225 | else if (inventoryBytes[i + 2] == 0x00 && inventoryBytes[i + 4] == 'j' && inventoryBytes[i + 5] == 'f')
226 | {
227 | playerInventoryLength = i - playerInventoryStart;
228 | break;
229 | }
230 | }
231 | }
232 |
233 | // When corpse data is present, 4 bytes from last player inventory JM header and 12 bytes
234 | // of unknown corpse data exist. Must keep a copy of these 12 bytes for when we go to save
235 | // the file
236 | unknownCorpseDataStart = playerInventoryStart + playerInventoryLength + 4;
237 | if (hasCorpseData)
238 | {
239 | for (int i = unknownCorpseDataStart; i < inventoryBytes.Length - 1; i++)
240 | {
241 | if (inventoryBytes[i] == 'J' && inventoryBytes[i + 1] == 'M')
242 | {
243 | unknownCorpseDataLength = i - unknownCorpseDataStart;
244 | break;
245 | }
246 | }
247 | }
248 |
249 | // Corpse inventory data exists between the end of player inventory list "JM\x0#\x00" and ends with "jf"
250 | // 12 bytes of unknown data are at the beginning of corpseInventoryBytes whenever corpse data is present
251 | corpseInventoryStart = unknownCorpseDataStart + unknownCorpseDataLength;
252 | if (!hasCorpseData)
253 | {
254 | corpseInventoryLength = 0;
255 | }
256 | else
257 | {
258 | for (int i = corpseInventoryStart + 4; i < inventoryBytes.Length - 1; i++)
259 | {
260 | if (inventoryBytes[i] == 'j' && inventoryBytes[i + 1] == 'f')
261 | {
262 | corpseInventoryLength = i - corpseInventoryStart;
263 | break;
264 | }
265 | }
266 | }
267 |
268 | // Merc inventory data is everything between "jf" and "kf", start searching for "kf" from end of file
269 | mercInventoryStart = corpseInventoryStart + corpseInventoryLength + 2;
270 | for (int i = inventoryBytes.Length - 3; i > mercInventoryStart; i--)
271 | {
272 | if (inventoryBytes[i] == 'k' && inventoryBytes[i + 1] == 'f' && (inventoryBytes[i + 2] == 0 || inventoryBytes[i + 2] == 1))
273 | {
274 | mercInventoryLength = i - mercInventoryStart;
275 | break;
276 | }
277 | }
278 |
279 | // Golem inventory exists iff the byte after the end of Merc inventory is set to 1
280 | golemInventoryStart = mercInventoryStart + mercInventoryLength + 2;
281 | if (golemInventoryStart < inventoryBytes.Length && inventoryBytes[golemInventoryStart] == '\x01')
282 | {
283 | golemInventoryStart++; // Skip the 01 flag, useless to us
284 | golemInventoryLength = inventoryBytes.Length - golemInventoryStart;
285 | }
286 |
287 | playerInventoryBytes = new byte[playerInventoryLength];
288 | unknownCorpseDataBytes = new byte[unknownCorpseDataLength];
289 | corpseInventoryBytes = new byte[corpseInventoryLength];
290 | mercInventoryBytes = new byte[mercInventoryLength];
291 | golemInventoryBytes = new byte[golemInventoryLength];
292 |
293 | Array.Copy(inventoryBytes, playerInventoryStart, playerInventoryBytes, 0, playerInventoryBytes.Length);
294 | Array.Copy(inventoryBytes, unknownCorpseDataStart, unknownCorpseDataBytes, 0, unknownCorpseData.Length);
295 | Array.Copy(inventoryBytes, corpseInventoryStart, corpseInventoryBytes, 0, corpseInventoryBytes.Length);
296 | Array.Copy(inventoryBytes, mercInventoryStart, mercInventoryBytes, 0, mercInventoryBytes.Length);
297 | Array.Copy(inventoryBytes, golemInventoryStart, golemInventoryBytes, 0, golemInventoryBytes.Length);
298 | }
299 |
300 | ///
301 | /// Parses raw inventory data into Items
302 | ///
303 | /// Raw inventory data from save file
304 | private void ProcessInventoryBytes(byte[] inventoryBytes)
305 | {
306 | byte[] playerInventoryBytes;
307 | byte[] corpseInventoryBytes;
308 | byte[] mercInventoryBytes;
309 | byte[] golemInventoryBytes;
310 |
311 | SplitInventoryBytes(inventoryBytes,
312 | out playerInventoryBytes,
313 | out unknownCorpseData,
314 | out corpseInventoryBytes,
315 | out mercInventoryBytes,
316 | out golemInventoryBytes);
317 |
318 | int currentPosition;
319 |
320 | // Parse player's inventory items, skipping 4 byte header
321 | currentPosition = 4;
322 | while (currentPosition < playerInventoryBytes.Length)
323 | {
324 | Item currentItem = GetNextItem(playerInventoryBytes, ref currentPosition);
325 | if (currentItem == null)
326 | {
327 | continue;
328 | }
329 |
330 | playerItems.Add(currentItem);
331 | }
332 |
333 | // Parse corpse inventory, skipping 4 byte header and 12 byte unknown corpse data
334 | currentPosition = 4;
335 | while (currentPosition < corpseInventoryBytes.Length)
336 | {
337 | Item currentItem = GetNextItem(corpseInventoryBytes, ref currentPosition);
338 | if (currentItem == null)
339 | {
340 | continue;
341 | }
342 |
343 | corpseItems.Add(currentItem);
344 | }
345 |
346 | // Parse merc items
347 | currentPosition = 4;
348 | while (currentPosition < mercInventoryBytes.Length)
349 | {
350 | Item currentItem = GetNextItem(mercInventoryBytes, ref currentPosition);
351 | if (currentItem == null)
352 | {
353 | continue;
354 | }
355 |
356 | mercItems.Add(currentItem);
357 | }
358 |
359 | // Parse golem item(s)
360 | currentPosition = 0;
361 | while (currentPosition < golemInventoryBytes.Length)
362 | {
363 | Item currentItem = GetNextItem(golemInventoryBytes, ref currentPosition);
364 | if (currentItem == null)
365 | {
366 | continue;
367 | }
368 |
369 | golemItems.Add(currentItem);
370 | }
371 | }
372 |
373 | ///
374 | /// Adds raw data from an item to a list of raw data
375 | ///
376 | /// List of raw data to add item to
377 | /// Item to add
378 | private void AddItemsToInventoryBytes(ref List inventoryBytes, List
- items)
379 | {
380 | foreach (Item item in items)
381 | {
382 | inventoryBytes.AddRange(item.GetItemBytes());
383 | }
384 | }
385 |
386 | ///
387 | /// Converts all item data into raw data for the save file
388 | ///
389 | /// Character has a mercenary
390 | /// Byte array containing raw inventory data
391 | public byte[] GetInventoryBytes(bool hasMercenary)
392 | {
393 | List inventoryBytes = new List();
394 | byte[] magic = new byte[] { 0x4A, 0x4D };
395 |
396 | inventoryBytes.AddRange(magic);
397 | inventoryBytes.AddRange(BitConverter.GetBytes((short)playerItems.Count));
398 |
399 | // Dump inventory data
400 | AddItemsToInventoryBytes(ref inventoryBytes, playerItems);
401 |
402 | // Closing player inventory list header
403 | inventoryBytes.AddRange(magic);
404 | if (corpseItems.Count > 0)
405 | {
406 | inventoryBytes.Add(0x01);
407 | }
408 | else
409 | {
410 | inventoryBytes.Add(0x00);
411 | }
412 | inventoryBytes.Add(0x00);
413 |
414 |
415 | // Dump corpse data
416 | if (corpseItems.Count > 0)
417 | {
418 | if (unknownCorpseData.Length == 0)
419 | {
420 | // I don't know what the 12 bytes are, but 0 seems to work
421 | unknownCorpseData = new byte[12];
422 | }
423 |
424 | if (unknownCorpseData[2] == 0)
425 | {
426 | // This byte has to be flagged to make the corpse appear, might be corpse count
427 | unknownCorpseData[2] = 1;
428 | }
429 |
430 | inventoryBytes.AddRange(unknownCorpseData);
431 | inventoryBytes.AddRange(magic);
432 | inventoryBytes.AddRange(BitConverter.GetBytes((short)corpseItems.Count));
433 |
434 | AddItemsToInventoryBytes(ref inventoryBytes, corpseItems);
435 | }
436 |
437 | // Closing corpse inventory header
438 | inventoryBytes.Add(0x6a); // j
439 | inventoryBytes.Add(0x66); // f
440 |
441 | // Dump merc inventory
442 | if (hasMercenary)
443 | {
444 | inventoryBytes.AddRange(magic);
445 | inventoryBytes.AddRange(BitConverter.GetBytes((short)mercItems.Count));
446 |
447 | AddItemsToInventoryBytes(ref inventoryBytes, mercItems);
448 | }
449 |
450 | // Closing merc inventory header
451 | inventoryBytes.Add(0x6b); // k
452 | inventoryBytes.Add(0x66); // f
453 |
454 | if (golemItems.Count == 0)
455 | {
456 | // No iron golem, finish file off with 0x00
457 | inventoryBytes.Add(0x00);
458 | }
459 | else
460 | {
461 | // Yes iron golem, finish file off with 0x01 followed by item golem was
462 | // spawned from
463 | inventoryBytes.Add((byte)golemItems.Count);
464 | AddItemsToInventoryBytes(ref inventoryBytes, golemItems);
465 | }
466 |
467 | return inventoryBytes.ToArray();
468 | }
469 | }
470 | }
471 |
--------------------------------------------------------------------------------
/tools/esCharView/CharacterEditor/Resources/1.13c/ItemStatCost.txt:
--------------------------------------------------------------------------------
1 | Stat ID Send Other Signed Send Bits Send Param Bits UpdateAnimRate Saved CSvSigned CSvBits CSvParam fCallback fMin MinAccr Encode Add Multiply Divide ValShift 1.09-Save Bits 1.09-Save Add Save Bits Save Add Save Param Bits keepzero op op param op base op stat1 op stat2 op stat3 direct maxstat itemspecific damagerelated itemevent1 itemeventfunc1 itemevent2 itemeventfunc2 descpriority descfunc descval descstrpos descstrneg descstr2 dgrp dgrpfunc dgrpval dgrpstrpos dgrpstrneg dgrpstr2 stuff *eol
2 | strength 0 1 11 1 0 10 1 1 125 55 1024 7 32 8 32 67 1 1 ModStr1a ModStr1a 1 1 1 Moditem2allattrib Moditem2allattrib 6 0
3 | energy 1 11 1 0 10 1 1 100 55 1024 7 32 7 32 8 maxmana 61 1 1 ModStr1d ModStr1d 1 1 1 Moditem2allattrib Moditem2allattrib 0
4 | dexterity 2 1 11 1 0 10 1 1 125 55 1024 7 32 7 32 65 1 1 ModStr1b ModStr1b 1 1 1 Moditem2allattrib Moditem2allattrib 0
5 | vitality 3 11 1 0 10 1 1 100 55 1024 7 32 7 32 9 maxhp maxstamina 63 1 1 ModStr1c ModStr1c 1 1 1 Moditem2allattrib Moditem2allattrib 0
6 | statpts 4 9 1 0 10 1024 0
7 | newskills 5 9 1 0 8 1024 0
8 | hitpoints 6 32 1 0 21 1024 8 1 maxhp 0
9 | maxhp 7 32 1 0 21 1 1 1 56 20 1024 8 8 32 9 32 59 1 1 ModStr1u ModStr1u 0
10 | mana 8 32 1 0 21 1024 8 1 1 maxmana 0
11 | maxmana 9 32 1 0 21 1 1 0 81 20 1024 8 8 32 8 32 55 1 1 ModStr1e ModStr1e 0
12 | stamina 10 32 1 0 21 1024 8 1 1 maxstamina 0
13 | maxstamina 11 32 1 0 21 1 1 0 75 20 1024 8 8 32 8 32 51 1 1 ModStr5d ModStr5d 0
14 | level 12 9 1 0 7 1024 0
15 | experience 13 32 1 0 32 1024 0
16 | gold 14 32 1 0 25 1024 0
17 | goldbank 15 32 1 0 25 1024 0
18 | item_armor_percent 16 1 11 47 20 1024 9 0 9 0 13 armorclass 74 4 1 Modstr2v Modstr2v 0
19 | item_maxdamage_percent 17 1 11 45 20 1024 9 0 9 0 13 maxdamage secondary_maxdamage item_throw_maxdamage 1 129 3 0 ModStr2j ModStr2j 0
20 | item_mindamage_percent 18 1 11 45 20 1024 9 0 9 0 13 mindamage secondary_mindamage item_throw_mindamage 1 130 3 0 ModStr2k ModStr2k 0
21 | tohit 19 1 16 15 10 1024 10 10 1 115 1 1 ModStr1h ModStr1h 0
22 | toblock 20 1 10 89 204 1024 6 0 6 0 134 2 1 ModStr3g ModStr3g 0
23 | mindamage 21 1 16 122 25 1024 6 0 6 0 1 127 1 1 ModStr1g ModStr1g 0
24 | maxdamage 22 1 16 94 16 1024 7 0 7 0 1 126 1 1 ModStr1f ModStr1f 0
25 | secondary_mindamage 23 1 16 97 15 1024 6 0 6 0 1 124 1 1 ModStr1g ModStr1g 0
26 | secondary_maxdamage 24 1 16 85 11 1024 7 0 7 0 1 123 1 1 ModStr1f ModStr1f 0
27 | damagepercent 25 1 12 45 40 1024 8 0 8 0 1 0
28 | manarecovery 26 1024 8 0 8 0 0
29 | manarecoverybonus 27 1 16 1024 8 0 8 0 52 2 2 ModStr4g ModStr4g 0
30 | staminarecoverybonus 28 1 16 1024 8 0 8 0 48 2 2 ModStr3v ModStr3v 0
31 | lastexp 29 32 1024 0
32 | nextexp 30 32 1024 0
33 | armorclass 31 1 16 17 10 1024 10 10 11 10 71 1 1 ModStr1i ModStr1i 0
34 | armorclass_vs_missile 32 1 16 11 5 1024 8 0 9 0 69 1 1 ModStr6a ModStr6a 0
35 | armorclass_vs_hth 33 1 16 13 7 1024 8 0 8 0 70 1 1 ModStr6b ModStr6b 0
36 | normal_damage_reduction 34 1 10 188 200 1024 6 0 6 0 22 3 2 ModStr2u ModStr2u 0
37 | magic_damage_reduction 35 1 10 397 340 1024 6 0 6 0 21 3 2 ModStr2t ModStr2t 0
38 | damageresist 36 1 9 152 68 1024 8 0 8 0 22 2 2 ModStr2u ModStr2u 0
39 | magicresist 37 1 9 164 68 1024 8 0 8 0 41 4 2 ModStr1m ModStr1m 0
40 | maxmagicresist 38 1 9 1091 409 1024 5 0 5 0 46 4 1 ModStr5x ModStr5x 0
41 | fireresist 39 1 9 43 20 1024 8 0 8 50 36 4 2 ModStr1j ModStr1j 2 19 strModAllResistances strModAllResistances 0
42 | maxfireresist 40 1 9 584 256 1024 5 0 5 0 42 4 1 ModStr5u ModStr5u 0
43 | lightresist 41 1 9 43 20 1024 8 0 8 50 38 4 2 ModStr1l ModStr1l 2 19 strModAllResistances strModAllResistances 0
44 | maxlightresist 42 1 9 584 256 1024 5 0 5 0 43 4 1 ModStr5w ModStr5w 0
45 | coldresist 43 1 9 43 20 1024 8 0 8 50 40 4 2 ModStr1k ModStr1k 2 19 strModAllResistances strModAllResistances 0
46 | maxcoldresist 44 1 9 584 256 1024 5 0 5 0 44 4 1 ModStr5v ModStr5v 0
47 | poisonresist 45 1 9 43 20 1024 8 0 8 50 34 4 2 ModStr1n ModStr1n 2 19 strModAllResistances strModAllResistances 0
48 | maxpoisonresist 46 1 9 526 256 1024 5 0 5 0 45 4 1 ModStr5y ModStr5y 0
49 | damageaura 47 1 16 1024 0
50 | firemindam 48 1 16 11 10 1024 8 0 8 0 1 102 1 1 ModStr1p ModStr1p 0
51 | firemaxdam 49 1 16 19 10 1024 8 0 9 0 1 101 1 1 ModStr1o ModStr1o 0
52 | lightmindam 50 1 16 12 10 1024 6 0 6 0 1 99 1 1 ModStr1r ModStr1r 0
53 | lightmaxdam 51 1 16 17 10 1024 9 0 10 0 1 98 1 1 ModStr1q ModStr1q 0
54 | magicmindam 52 1 16 196 20 1024 6 0 8 0 1 104 1 1 strModMagicDamage strModMagicDamage 0
55 | magicmaxdam 53 1 16 183 20 1024 7 0 9 0 1 103 1 1 strModMagicDamage strModMagicDamage 0
56 | coldmindam 54 1 16 451 512 1024 6 0 8 0 1 96 1 1 ModStr1t ModStr1t 0
57 | coldmaxdam 55 1 16 128 340 1024 8 0 9 0 1 95 1 1 ModStr1s ModStr1s 0
58 | coldlength 56 1 16 77 4 1024 8 0 8 0 1 0
59 | poisonmindam 57 1 19 12 28 1024 9 0 10 0 1 92 1 1 ModStr4i ModStr4i 0
60 | poisonmaxdam 58 1 19 11 34 1024 9 0 10 0 1 91 1 1 ModStr4h ModStr4h 0
61 | poisonlength 59 1 16 0 4 1024 8 0 9 0 1 0
62 | lifedrainmindam 60 1 16 1044 341 1024 7 0 7 0 1 88 2 1 ModStr2z ModStr2z 0
63 | lifedrainmaxdam 61 1 16 1024 1 0
64 | manadrainmindam 62 1 16 1179 341 1024 7 0 7 0 1 89 2 1 ModStr2y ModStr2y 0
65 | manadrainmaxdam 63 1 16 1024 1 0
66 | stamdrainmindam 64 1 16 1024 1 0
67 | stamdrainmaxdam 65 1 16 1024 1 0
68 | stunlength 66 16 1024 1 0
69 | velocitypercent 67 1 1 10 1 1024 7 30 7 30 0
70 | attackrate 68 1 1 10 1 1024 7 30 7 30 1 0
71 | other_animrate 69 1 1 10 1 1024 0
72 | quantity 70 1 16 1024 1 1 0
73 | value 71 1 9 1024 8 100 8 100 1 0
74 | durability 72 1 9 1024 8 0 9 0 1 maxdurability 1 0
75 | maxdurability 73 1 9 9 4 1024 8 0 8 0 1 0
76 | hpregen 74 451 410 1024 6 30 6 30 56 1 2 ModStr2l ModStr2w 0
77 | item_maxdurability_percent 75 1 7 117 10 1024 7 20 7 20 13 maxdurability 3 2 2 ModStr2i ModStr2i 0
78 | item_maxhp_percent 76 1 16 32093 204 1024 6 10 6 10 11 maxhp 58 2 2 ModStr2g ModStr2g 0
79 | item_maxmana_percent 77 1 16 56452 204 1024 6 10 6 10 11 maxmana 54 2 2 ModStr2h ModStr2h 0
80 | item_attackertakesdamage 78 1 16 1 112 128 1024 7 0 7 0 damagedinmelee 6 13 3 2 ModStr1v ModStr1v 0
81 | item_goldbonus 79 1 10 187 34 1024 9 100 9 100 10 2 1 ModStr1w ModStr1w 0
82 | item_magicbonus 80 1 9 577 102 1024 8 100 8 100 8 2 1 ModStr1x ModStr1x 0
83 | item_knockback 81 1 8 1 105 0 1024 7 0 7 0 1 domeleedamage 7 domissiledamage 7 76 3 0 ModStr1y ModStr1y 0
84 | item_timeduration 82 1 10 1024 9 20 9 20 0
85 | item_addclassskills 83 1 4 3 1 49523 1560 1024 3 0 3 0 3 150 13 1 ModStr3a ModStr3a 0
86 | unsentparam1 84 1024 3 0 0
87 | item_addexperience 85 1 9 36015 519 1024 3 0 9 50 11 4 1 Moditem2ExpG Moditem2ExpG 0
88 | item_healafterkill 86 1 7 1 30 101 1024 3 0 7 0 kill 28 16 1 1 ModitemHPaK ModitemHPaK 0
89 | item_reducedprices 87 8 18957 203 1024 3 0 7 0 8 2 2 ModitemRedVendP ModitemRedVendP 0
90 | item_doubleherbduration 88 1 2 1024 1 0 1 0 0
91 | item_lightradius 89 1 5 1 15 51 1024 4 4 4 4 6 1 1 ModStr3f ModStr3f 0
92 | item_lightcolor 90 1 24 1 155 0 1024 5 0 24 0 0
93 | item_req_percent 91 1 8 26 -34 1024 8 100 8 100 0 4 2 ModStr3h ModStr3h 0
94 | item_levelreq 92 1024 6 20 7 0
95 | item_fasterattackrate 93 1 1 9 1042 156 1024 7 20 7 20 1 145 4 1 ModStr4m ModStr4m 0
96 | item_levelreqpct 94 1024 7 20 7 64 13 item_levelreq 0
97 | lastblockframe 95 1024 6 20 0
98 | item_fastermovevelocity 96 1 1 9 4083 156 1024 7 20 7 20 148 4 1 ModStr4s ModStr4s 0
99 | item_nonclassskill 97 1 15 9 1 1 181 327 1024 7 20 6 0 9 81 28 0
100 | state 98 1 1 8 1 415 64 1024 6 20 1 8 0
101 | item_fastergethitrate 99 1 1 9 1065 72 1024 7 20 7 20 139 4 1 ModStr4p ModStr4p 0
102 | monster_playercount 100 1024 7 20 0
103 | skill_poison_override_length 101 8 1024 6 20 0
104 | item_fasterblockrate 102 1 1 9 1484 72 1024 7 20 7 20 136 4 1 ModStr4y ModStr4y 0
105 | skill_bypass_undead 103 1 1024 7 20 0
106 | skill_bypass_demons 104 1 1024 6 20 0
107 | item_fastercastrate 105 1 1 9 3876 156 1024 7 20 7 20 142 4 1 ModStr4v ModStr4v 0
108 | skill_bypass_beasts 106 1 1024 7 20 0
109 | item_singleskill 107 1 15 9 1 1 181 256 1024 14 0 3 0 9 81 27 0
110 | item_restinpeace 108 1 1 1987 0 1024 14 0 1 0 1 kill 29 81 3 0 ModitemSMRIP ModitemSMRIP 0
111 | curse_resistance 109 9 159 33 1024 14 0 9 0 0
112 | item_poisonlengthresist 110 1 9 27 10 1024 8 20 8 20 18 2 2 ModStr3r ModStr3r 0
113 | item_normaldamage 111 1 8 94 100 1024 7 20 9 20 1 122 1 2 ModStr5b ModStr5b 0
114 | item_howl 112 1 8 1 55 10 1024 7 -1 7 -1 1 domeleedamage 8 domissiledamage 8 79 5 2 ModStr3u ModStr3u 0
115 | item_stupidity 113 1 8 1 332 1024 1024 7 0 7 0 1 domeleedamage 9 domissiledamage 9 80 12 2 ModStr6d ModStr6d 0
116 | item_damagetomana 114 1 7 1 43 20 1024 6 0 6 0 damagedinmelee 13 damagedbymissile 13 11 2 1 ModStr3w ModStr3w 0
117 | item_ignoretargetac 115 1 2 1088 1024 1024 1 0 1 0 1 119 3 0 ModStr3y ModStr3y 0
118 | item_fractionaltargetac 116 1 8 67 20 1024 7 0 7 0 1 118 20 1 ModStr5o ModStr5o 0
119 | item_preventheal 117 1 8 48 50 1024 7 0 7 0 1 81 3 0 ModStr4a ModStr4a 0
120 | item_halffreezeduration 118 1 2 5096 988 1024 1 0 1 0 19 3 0 ModStr4b ModStr4b 0
121 | item_tohit_percent 119 1 12 981 40 1024 9 20 9 20 1 117 2 1 ModStr4c ModStr4c 0
122 | item_damagetargetac 120 1 8 24 -20 1024 7 128 7 128 1 75 1 1 ModStr4d ModStr4d 0
123 | item_demondamage_percent 121 1 12 19 12 1024 9 20 9 20 1 112 4 1 ModStr4e ModStr4e 0
124 | item_undeaddamage_percent 122 1 12 13 12 1024 9 20 9 20 1 108 4 1 ModStr4f ModStr4f 0
125 | item_demon_tohit 123 1 13 15 7 1024 10 128 10 128 1 110 1 1 ModStr4j ModStr4j 0
126 | item_undead_tohit 124 1 13 11 7 1024 10 128 10 128 1 106 1 1 ModStr4k ModStr4k 0
127 | item_throwable 125 1 2 82 1024 1024 1 0 1 0 5 3 0 ModStr5a ModStr5a 0
128 | item_elemskill 126 1 3 3 1 76 1024 1024 4 0 3 0 3 157 1 1 ModStr3i ModStr3i 0
129 | item_allskills 127 1 8 1 15123 4096 1024 3 0 3 0 158 1 1 ModStr3k ModStr3k 0
130 | item_attackertakeslightdamage 128 1 6 1 4 102 1024 5 0 5 0 damagedinmelee 10 14 3 2 ModStr3j ModStr3j 0
131 | ironmaiden_level 129 1 10 1024 0
132 | lifetap_level 130 1 10 1024 0
133 | thorns_percent 131 12 1024 0
134 | bonearmor 132 1 32 1024 0
135 | bonearmormax 133 1 32 1024 0
136 | item_freeze 134 1 5 1 666 12 1024 5 0 5 0 1 domeleedamage 14 domissiledamage 14 78 12 2 ModStr3l ModStr3l 0
137 | item_openwounds 135 1 7 1 23 10 1024 7 0 7 0 1 domeleedamage 15 domissiledamage 15 83 2 1 ModStr3m ModStr3m 0
138 | item_crushingblow 136 1 7 1 98 40 1024 7 0 7 0 1 domeleedamage 16 domissiledamage 16 87 2 1 ModStr5c ModStr5c 0
139 | item_kickdamage 137 1 7 77 51 1024 7 0 7 0 121 1 1 ModStr5e ModStr5e 0
140 | item_manaafterkill 138 1 7 1 17 102 1024 7 0 7 0 kill 17 16 1 1 ModStr5f ModStr5f 0
141 | item_healafterdemonkill 139 1 7 1 18 102 1024 7 0 7 0 kill 18 15 1 1 ModStr6c ModStr6c 0
142 | item_extrablood 140 1 7 15 10 1024 7 0 7 0 1 0
143 | item_deadlystrike 141 1 7 31 25 1024 7 0 7 0 1 85 2 1 ModStr5q ModStr5q 0
144 | item_absorbfire_percent 142 1 7 5486 102 1024 7 0 7 0 23 2 2 ModStr5g ModStr5g 0
145 | item_absorbfire 143 1 7 1739 204 1024 7 0 7 0 27 1 1 ModStr5h ModStr5h 0
146 | item_absorblight_percent 144 1 7 5486 102 1024 7 0 7 0 24 2 2 ModStr5i ModStr5i 0
147 | item_absorblight 145 1 7 1739 204 1024 7 0 7 0 29 1 1 ModStr5j ModStr5j 0
148 | item_absorbmagic_percent 146 1 7 5486 102 1024 7 0 7 0 26 2 2 ModStr5k ModStr5k 0
149 | item_absorbmagic 147 1 7 1739 204 1024 7 0 7 0 33 1 1 ModStr5l ModStr5l 0
150 | item_absorbcold_percent 148 1 7 5486 102 1024 7 0 7 0 25 2 2 ModStr5m ModStr5m 0
151 | item_absorbcold 149 1 7 1739 204 1024 7 0 7 0 31 1 1 ModStr5n ModStr5n 0
152 | item_slow 150 1 7 1 101 40 1024 7 0 7 0 1 domeleedamage 19 domissiledamage 19 77 2 2 ModStr5r ModStr5r 0
153 | item_aura 151 1 1 1024 7 0 5 0 9 159 16 0 ModitemAura ModitemAura 0
154 | item_indesctructible 152 1 1 1024 7 0 1 160 3 0 ModStre9s ModStre9s 0
155 | item_cannotbefrozen 153 1 2 15011 2048 1024 1 1 20 3 0 ModStr5z ModStr5z 0
156 | item_staminadrainpct 154 1 7 102 20 1024 7 20 7 20 1 49 2 1 ModStr6e ModStr6e 0
157 | item_reanimate 155 7 10 1 1024 7 0 7 0 10 1 kill 31 17 23 1 Moditemreanimas Moditemreanimas 0
158 | item_pierce 156 1 7 1924 2048 1024 7 0 7 0 1 132 3 0 ModStr6g ModStr6g 0
159 | item_magicarrow 157 1 7 511 1024 1024 7 0 7 0 131 3 0 ModStr6h ModStr6h 0
160 | item_explosivearrow 158 1 7 492 1536 1024 7 0 7 0 133 3 0 ModStr6i ModStr6i 0
161 | item_throw_mindamage 159 1 6 76 128 1024 6 0 6 0 1 0
162 | item_throw_maxdamage 160 1 7 88 128 1024 7 0 7 0 1 0
163 | skill_handofathena 161 1 12 1024 0
164 | skill_staminapercent 162 1 13 1024 1 maxstamina 0
165 | skill_passive_staminapercent 163 1 12 1024 1 maxstamina 0
166 | skill_concentration 164 1 12 1024 0
167 | skill_enchant 165 1 12 1024 0
168 | skill_pierce 166 1 12 1024 0
169 | skill_conviction 167 1 12 1024 0
170 | skill_chillingarmor 168 1 12 1024 0
171 | skill_frenzy 169 1 12 1024 0
172 | skill_decrepify 170 1 12 1024 0
173 | skill_armor_percent 171 1 16 1024 0
174 | alignment 172 1 2 1024 0
175 | target0 173 32 1024 0
176 | target1 174 32 1024 0
177 | goldlost 175 24 1024 0
178 | conversion_level 176 8 1024 0
179 | conversion_maxhp 177 16 1024 0
180 | unit_dooverlay 178 16 1024 0
181 | attack_vs_montype 179 9 10 19 14 1024 3 0 9 10 1 108 22 1 ModitemAttratvsM ModitemAttratvsM 0
182 | damage_vs_montype 180 9 10 27 17 1024 3 0 9 10 1 106 22 1 Moditemdamvsm Moditemdamvsm 0
183 | fade 181 1 7 14 0 3 0
184 | armor_override_percent 182 1 1 8 14 0 0
185 | unused183 183 14 0 0
186 | unused184 184 14 0 0
187 | unused185 185 14 0 0
188 | unused186 186 14 0 0
189 | unused187 187 14 0 0
190 | item_addskill_tab 188 1 3 6 1 11042 768 1024 10 0 3 0 16 151 14 StrSklTabItem1 StrSklTabItem1 0
191 | unused189 189 1024 10 0 0
192 | unused190 190 1024 10 0 0
193 | unused191 191 1024 10 0 0
194 | unused192 192 1024 10 0 0
195 | unused193 193 1024 10 0 0
196 | item_numsockets 194 1 4 38 170 1024 4 0 4 0 1 0
197 | item_skillonattack 195 1 7 16 1 2 190 256 1024 21 0 7 0 16 1 domeleeattack 20 domissileattack 20 160 15 ItemExpansiveChancX ItemExpansiveChancX 0
198 | item_skillonkill 196 1 7 16 1 2 85 19 1024 21 0 7 0 16 1 kill 20 160 15 ModitemskonKill ModitemskonKill 0
199 | item_skillondeath 197 1 7 16 1 2 11 9 1024 21 0 7 0 16 killed 30 160 15 Moditemskondeath Moditemskondeath 0
200 | item_skillonhit 198 1 7 16 1 2 190 256 1024 21 0 7 0 16 1 domeleedamage 20 domissiledamage 20 160 15 ItemExpansiveChanc1 ItemExpansiveChanc1 0
201 | item_skillonlevelup 199 1 7 16 1 2 7 6 1024 21 0 7 0 16 levelup 30 160 15 ModitemskonLevel ModitemskonLevel 0
202 | unused200 200 1024 21 0 0
203 | item_skillongethit 201 1 7 16 1 2 190 256 1024 21 0 7 0 16 damagedinmelee 21 damagedbymissile 21 160 15 ItemExpansiveChanc2 ItemExpansiveChanc2 0
204 | unused202 202 1024 21 0 0
205 | unused203 203 1024 21 0 0
206 | item_charged_skill 204 1 30 1 3 401 256 1024 30 0 16 0 16 1 24 ModStre10d ModStre10d 0
207 | unused204 205 1 30 3 401 256 1024 30 0 0
208 | unused205 206 1 30 3 401 256 1024 30 0 0
209 | unused206 207 1 30 3 401 256 1024 30 0 0
210 | unused207 208 1 30 3 401 256 1024 30 0 0
211 | unused208 209 1 30 3 401 256 1024 30 0 0
212 | unused209 210 1 30 3 401 256 1024 30 0 0
213 | unused210 211 1 30 3 401 256 1024 30 0 0
214 | unused211 212 1 30 3 401 256 1024 30 0 0
215 | unused212 213 1 30 3 401 256 1024 30 0 0
216 | item_armor_perlevel 214 1 6 43 42 1024 6 0 6 0 4 3 level armorclass 72 6 1 ModStr1i ModStr1i increaseswithplaylevelX 0
217 | item_armorpercent_perlevel 215 1 6 87 100 1024 6 0 6 0 5 3 level armorclass 73 8 1 Modstr2v Modstr2v increaseswithplaylevelX 0
218 | item_hp_perlevel 216 1 6 92 64 1024 8 6 0 6 0 2 3 level maxhp 57 6 1 ModStr1u ModStr1u increaseswithplaylevelX 0
219 | item_mana_perlevel 217 1 6 90 128 1024 8 6 0 6 0 2 3 level maxmana 53 6 1 ModStr1e ModStr1e increaseswithplaylevelX 0
220 | item_maxdamage_perlevel 218 1 6 54 204 1024 6 0 6 0 4 3 level maxdamage secondary_maxdamage item_throw_maxdamage 1 125 6 1 ModStr1f ModStr1f increaseswithplaylevelX 0
221 | item_maxdamage_percent_perlevel 219 1 6 86 100 1024 6 0 6 0 5 3 level maxdamage secondary_maxdamage item_throw_maxdamage 1 128 8 1 ModStr2j ModStr2j increaseswithplaylevelX 0
222 | item_strength_perlevel 220 1 6 132 128 1024 6 0 6 0 2 3 level strength 66 6 1 ModStr1a ModStr1a increaseswithplaylevelX 0
223 | item_dexterity_perlevel 221 1 6 132 128 1024 6 0 6 0 2 3 level dexterity 64 6 1 ModStr1b ModStr1b increaseswithplaylevelX 0
224 | item_energy_perlevel 222 1 6 105 128 1024 6 0 6 0 2 3 level energy 60 6 1 ModStr1d ModStr1d increaseswithplaylevelX 0
225 | item_vitality_perlevel 223 1 6 105 128 1024 6 0 6 0 2 3 level vitality 62 6 1 ModStr1c ModStr1c increaseswithplaylevelX 0
226 | item_tohit_perlevel 224 1 6 53 20 1024 6 0 6 0 2 1 level tohit 1 114 6 1 ModStr1h ModStr1h increaseswithplaylevelX 0
227 | item_tohitpercent_perlevel 225 1 6 10 256 1024 6 0 6 0 2 1 level item_tohit_percent 1 116 7 1 ModStr4c ModStr4c increaseswithplaylevelX 0
228 | item_cold_damagemax_perlevel 226 1 6 1058 340 1024 6 0 6 0 2 3 level coldmaxdam 1 94 6 1 ModStr1s ModStr1s increaseswithplaylevelX 0
229 | item_fire_damagemax_perlevel 227 1 6 49 128 1024 6 0 6 0 2 3 level firemaxdam 1 100 6 1 ModStr1o ModStr1o increaseswithplaylevelX 0
230 | item_ltng_damagemax_perlevel 228 1 6 49 128 1024 6 0 6 0 2 3 level lightmaxdam 1 97 6 1 ModStr1q ModStr1q increaseswithplaylevelX 0
231 | item_pois_damagemax_perlevel 229 1 6 49 128 1024 6 0 6 0 2 3 level poisonmaxdam 1 90 6 1 ModStr4h ModStr4h increaseswithplaylevelX 0
232 | item_resist_cold_perlevel 230 1 6 101 128 1024 6 0 6 0 2 3 level coldresist 39 7 2 ModStr1k ModStr1k increaseswithplaylevelX 0
233 | item_resist_fire_perlevel 231 1 6 101 128 1024 6 0 6 0 2 3 level fireresist 35 7 2 ModStr1j ModStr1j increaseswithplaylevelX 0
234 | item_resist_ltng_perlevel 232 1 6 101 128 1024 6 0 6 0 2 3 level lightresist 37 7 2 ModStr1l ModStr1l increaseswithplaylevelX 0
235 | item_resist_pois_perlevel 233 1 6 101 128 1024 6 0 6 0 2 3 level poisonresist 33 7 2 ModStr1n ModStr1n increaseswithplaylevelX 0
236 | item_absorb_cold_perlevel 234 1 6 207 340 1024 6 0 6 0 2 3 level item_absorbcold 32 6 1 ModStre9p ModStre9p increaseswithplaylevelX 0
237 | item_absorb_fire_perlevel 235 1 6 207 340 1024 6 0 6 0 2 3 level item_absorbfire 28 6 1 ModStre9o ModStre9o increaseswithplaylevelX 0
238 | item_absorb_ltng_perlevel 236 1 6 207 340 1024 6 0 6 0 2 3 level item_absorblight 30 6 1 ModStre9q ModStre9q increaseswithplaylevelX 0
239 | item_absorb_pois_perlevel 237 1 6 207 340 1024 6 0 6 0 2 3 level item_absorbmagic 0
240 | item_thorns_perlevel 238 1 6 55 256 1024 6 0 5 0 2 3 level item_attackertakesdamage 12 9 2 ModStr1v ModStr1v increaseswithplaylevelX 0
241 | item_find_gold_perlevel 239 1 6 42 256 1024 6 0 6 0 2 3 level item_goldbonus 9 7 1 ModStr1w ModStr1w increaseswithplaylevelX 0
242 | item_find_magic_perlevel 240 1 6 814 1024 1024 6 0 6 0 2 3 level item_magicbonus 7 7 1 ModStr1x ModStr1x increaseswithplaylevelX 0
243 | item_regenstamina_perlevel 241 1 6 79 256 1024 6 0 6 0 2 3 level staminarecoverybonus 47 8 2 ModStr3v ModStr3v increaseswithplaylevelX 0
244 | item_stamina_perlevel 242 1 6 104 64 1024 6 0 6 0 2 3 level maxstamina 50 6 1 ModStr5d ModStr5d increaseswithplaylevelX 0
245 | item_damage_demon_perlevel 243 1 6 56 10 1024 6 0 6 0 2 3 level item_demondamage_percent 1 111 8 1 ModStr4e ModStr4e increaseswithplaylevelX 0
246 | item_damage_undead_perlevel 244 1 6 91 10 1024 6 0 6 0 2 3 level item_undeaddamage_percent 1 107 8 1 ModStr4f ModStr4f increaseswithplaylevelX 0
247 | item_tohit_demon_perlevel 245 1 6 55 10 1024 6 0 6 0 2 1 level item_demon_tohit 1 109 6 1 ModStr4j ModStr4j increaseswithplaylevelX 0
248 | item_tohit_undead_perlevel 246 1 6 12 10 1024 6 0 6 0 2 1 level item_undead_tohit 1 105 6 1 ModStr4k ModStr4k increaseswithplaylevelX 0
249 | item_crushingblow_perlevel 247 1 6 213 1024 1024 6 0 6 0 2 3 level item_crushingblow 1 86 7 1 ModStr5c ModStr5c increaseswithplaylevelX 0
250 | item_openwounds_perlevel 248 1 6 181 128 1024 6 0 6 0 2 3 level item_openwounds 1 82 7 1 ModStr3m ModStr3m increaseswithplaylevelX 0
251 | item_kick_damage_perlevel 249 1 6 104 128 1024 6 0 6 0 2 3 level item_kickdamage 1 120 6 1 ModStr5e ModStr5e increaseswithplaylevelX 0
252 | item_deadlystrike_perlevel 250 1 6 118 512 1024 6 0 6 0 2 3 level item_deadlystrike 1 84 7 1 ModStr5q ModStr5q increaseswithplaylevelX 0
253 | item_find_gems_perlevel 251 1 1024 0
254 | item_replenish_durability 252 1 5 106 256 1024 5 0 6 0 1 11 0 ModStre9t ModStre9t 0
255 | item_replenish_quantity 253 1 5 106 256 1024 5 0 6 0 2 3 0 ModStre9v ModStre9v 0
256 | item_extra_stack 254 1 99 10 1024 8 0 8 0 4 3 0 ModStre9i ModStre9i 0
257 | item_find_item 255 1 1024 0
258 | item_slash_damage 256 1 1024 1 0
259 | item_slash_damage_percent 257 1 1024 1 0
260 | item_crush_damage 258 1 1024 1 0
261 | item_crush_damage_percent 259 1 1024 1 0
262 | item_thrust_damage 260 1 1024 1 0
263 | item_thrust_damage_percent 261 1 1024 1 0
264 | item_absorb_slash 262 1 1024 0
265 | item_absorb_crush 263 1 1024 0
266 | item_absorb_thrust 264 1 1024 0
267 | item_absorb_slash_percent 265 1 1024 0
268 | item_absorb_crush_percent 266 1 1024 0
269 | item_absorb_thrust_percent 267 1 1024 0
270 | item_armor_bytime 268 1 22 4 0 1024 22 0 22 0 6 armorclass 180 17 1 ModStr1i ModStr1i 0
271 | item_armorpercent_bytime 269 1 22 4 0 1024 22 0 22 0 7 armorclass 180 18 1 Modstr2v Modstr2v 0
272 | item_hp_bytime 270 1 22 4 0 1024 22 0 22 0 6 maxhp 180 17 1 ModStr1u ModStr1u 0
273 | item_mana_bytime 271 1 22 4 0 1024 22 0 22 0 6 maxmana 180 17 1 ModStr1e ModStr1e 0
274 | item_maxdamage_bytime 272 1 22 4 0 1024 22 0 22 0 6 maxdamage secondary_maxdamage item_throw_maxdamage 1 180 17 1 ModStr1f ModStr1f 0
275 | item_maxdamage_percent_bytime 273 1 22 4 0 1024 22 0 22 0 7 maxdamage secondary_mindamage item_throw_mindamage 1 180 18 1 ModStr2j ModStr2j 0
276 | item_strength_bytime 274 1 22 4 0 1024 22 0 22 0 6 strength 180 17 1 ModStr1a ModStr1a 0
277 | item_dexterity_bytime 275 1 22 4 0 1024 22 0 22 0 6 dexterity 180 17 1 ModStr1b ModStr1b 0
278 | item_energy_bytime 276 1 22 4 0 1024 22 0 22 0 6 energy 180 17 1 ModStr1d ModStr1d 0
279 | item_vitality_bytime 277 1 22 4 0 1024 22 0 22 0 6 vitality 180 17 1 ModStr1c ModStr1c 0
280 | item_tohit_bytime 278 1 22 4 0 1024 22 0 22 0 6 tohit 1 180 17 1 ModStr1h ModStr1h 0
281 | item_tohitpercent_bytime 279 1 22 4 0 1024 22 0 22 0 6 item_tohit_percent 1 180 18 1 ModStr4c ModStr4c 0
282 | item_cold_damagemax_bytime 280 1 22 4 0 1024 22 0 22 0 6 coldmaxdam 1 180 17 1 ModStr1s ModStr1s 0
283 | item_fire_damagemax_bytime 281 1 22 4 0 1024 22 0 22 0 6 firemaxdam 1 180 17 1 ModStr1o ModStr1o 0
284 | item_ltng_damagemax_bytime 282 1 22 4 0 1024 22 0 22 0 6 lightmaxdam 1 180 17 1 ModStr1q ModStr1q 0
285 | item_pois_damagemax_bytime 283 1 22 4 0 1024 22 0 22 0 6 poisonmaxdam 1 180 17 1 ModStr4h ModStr4h 0
286 | item_resist_cold_bytime 284 1 22 4 0 1024 22 0 22 0 6 coldresist 180 18 2 ModStr1k ModStr1k 0
287 | item_resist_fire_bytime 285 1 22 4 0 1024 22 0 22 0 6 fireresist 180 18 2 ModStr1j ModStr1j 0
288 | item_resist_ltng_bytime 286 1 22 4 0 1024 22 0 22 0 6 lightresist 180 18 2 ModStr1l ModStr1l 0
289 | item_resist_pois_bytime 287 1 22 4 0 1024 22 0 22 0 6 poisonresist 180 18 2 ModStr1n ModStr1n 0
290 | item_absorb_cold_bytime 288 1 22 4 0 1024 22 0 22 0 6 item_absorbcold 180 18 1 ModStre9p ModStre9p 0
291 | item_absorb_fire_bytime 289 1 22 4 0 1024 22 0 22 0 6 item_absorbfire 180 18 1 ModStre9o ModStre9o 0
292 | item_absorb_ltng_bytime 290 1 22 4 0 1024 22 0 22 0 6 item_absorblight 180 18 1 ModStre9q ModStre9q 0
293 | item_absorb_pois_bytime 291 1 22 4 0 1024 22 0 22 0 6 item_absorbmagic 0
294 | item_find_gold_bytime 292 1 22 4 0 1024 22 0 22 0 6 item_goldbonus 180 18 2 ModStr1w ModStr1w 0
295 | item_find_magic_bytime 293 1 22 4 0 1024 22 0 22 0 6 item_magicbonus 180 18 1 ModStr1x ModStr1x 0
296 | item_regenstamina_bytime 294 1 22 4 0 1024 22 0 22 0 6 staminarecoverybonus 180 18 2 ModStr3v ModStr3v 0
297 | item_stamina_bytime 295 1 22 4 0 1024 22 0 22 0 6 maxstamina 180 17 1 ModStr5d ModStr5d 0
298 | item_damage_demon_bytime 296 1 22 4 0 1024 22 0 22 0 6 item_demondamage_percent 1 180 18 1 ModStr4e ModStr4e 0
299 | item_damage_undead_bytime 297 1 22 4 0 1024 22 0 22 0 6 item_undeaddamage_percent 1 180 18 1 ModStr4f ModStr4f 0
300 | item_tohit_demon_bytime 298 1 22 4 0 1024 22 0 22 0 6 item_demon_tohit 1 180 17 1 ModStr4j ModStr4j 0
301 | item_tohit_undead_bytime 299 1 22 4 0 1024 22 0 22 0 6 item_undead_tohit 1 180 17 1 ModStr4k ModStr4k 0
302 | item_crushingblow_bytime 300 1 22 4 0 1024 22 0 22 0 6 item_crushingblow 1 180 18 1 ModStr5c ModStr5c 0
303 | item_openwounds_bytime 301 1 22 4 0 1024 22 0 22 0 6 item_openwounds 1 180 18 1 ModStr3m ModStr3m 0
304 | item_kick_damage_bytime 302 1 22 4 0 1024 22 0 22 0 6 item_kickdamage 1 180 17 1 ModStr5e ModStr5e 0
305 | item_deadlystrike_bytime 303 1 22 4 0 1024 22 0 22 0 6 item_deadlystrike 1 180 18 1 ModStr5q ModStr5q 0
306 | item_find_gems_bytime 304 1 4 0 1024 0
307 | item_pierce_cold 305 1 9 1432 513 1024 8 50 88 20 1 Moditemenrescoldsk Moditemenrescoldsk 0
308 | item_pierce_fire 306 1 9 1240 497 1024 8 50 88 20 1 Moditemenresfiresk Moditemenresfiresk 0
309 | item_pierce_ltng 307 1 9 1187 481 1024 8 50 88 20 1 Moditemenresltngsk Moditemenresltngsk 0
310 | item_pierce_pois 308 1 9 1322 506 1024 8 50 88 20 1 Moditemenrespoissk Moditemenrespoissk 0
311 | item_damage_vs_monster 309 1 1024 1 0
312 | item_damage_percent_vs_monster 310 1 1024 1 0
313 | item_tohit_vs_monster 311 1 1024 1 0
314 | item_tohit_percent_vs_monster 312 1 1024 1 0
315 | item_ac_vs_monster 313 1 1024 0
316 | item_ac_percent_vs_monster 314 1 1024 0
317 | firelength 315 1 16 1024 0
318 | burningmin 316 1 16 1024 0
319 | burningmax 317 1 16 1024 0
320 | progressive_damage 318 1 3 1024 0
321 | progressive_steal 319 1 3 1024 0
322 | progressive_other 320 1 3 1024 0
323 | progressive_fire 321 1 3 1024 0
324 | progressive_cold 322 1 3 1024 0
325 | progressive_lightning 323 1 3 1024 0
326 | item_extra_charges 324 1 6 1024 6 0 6 0 1 1 0
327 | progressive_tohit 325 1 16 1024 0
328 | poison_count 326 1 5 1024 1 0
329 | damage_framerate 327 1 8 1024 0
330 | pierce_idx 328 1 6 1024 0
331 | passive_fire_mastery 329 1 12 1117 415 1024 8 0 9 50 88 4 1 ModitemdamFiresk ModitemdamFiresk 0
332 | passive_ltng_mastery 330 1 12 1054 408 1024 8 0 9 50 88 4 1 ModitemdamLtngsk ModitemdamLtngsk 0
333 | passive_cold_mastery 331 1 12 1295 379 1024 8 0 9 50 88 4 1 ModitemdamColdsk ModitemdamColdsk 0
334 | passive_pois_mastery 332 1 12 978 394 1024 8 0 9 50 88 4 1 ModitemdamPoissk ModitemdamPoissk 0
335 | passive_fire_pierce 333 1 9 2578 1024 8 0 8 0 88 20 1 Moditemenresfiresk Moditemenresfiresk 0
336 | passive_ltng_pierce 334 1 9 2493 1024 8 0 8 0 88 20 1 Moditemenresltngsk Moditemenresltngsk 0
337 | passive_cold_pierce 335 1 9 1984 1024 8 0 8 0 88 20 1 Moditemenrescoldsk Moditemenrescoldsk 0
338 | passive_pois_pierce 336 1 9 2345 1024 8 0 8 0 88 20 1 Moditemenrespoissk Moditemenrespoissk 0
339 | passive_critical_strike 337 1 9 1024 8 0 8 0 0
340 | passive_dodge 338 1 9 1024 7 0 7 0 0
341 | passive_avoid 339 1 9 1024 7 0 7 0 0
342 | passive_evade 340 1 9 1024 7 0 7 0 0
343 | passive_warmth 341 1 9 1024 8 0 8 0 0
344 | passive_mastery_melee_th 342 1 11 8 1024 8 0 8 0 0
345 | passive_mastery_melee_dmg 343 1 11 8 1024 8 0 8 0 0
346 | passive_mastery_melee_crit 344 1 9 8 1024 8 0 8 0 0
347 | passive_mastery_throw_th 345 1 11 8 1024 8 0 8 0 0
348 | passive_mastery_throw_dmg 346 1 11 8 1024 8 0 8 0 0
349 | passive_mastery_throw_crit 347 1 9 8 1024 8 0 8 0 0
350 | passive_weaponblock 348 1 9 8 1024 8 0 8 0 0
351 | passive_summon_resist 349 1 9 1024 8 0 8 0 0
352 | modifierlist_skill 350 9 1024 0
353 | modifierlist_level 351 8 1024 0
354 | last_sent_hp_pct 352 1 8 1024 0
355 | source_unit_type 353 5 1024 0
356 | source_unit_id 354 32 1024 0
357 | shortparam1 355 16 1024 0
358 | questitemdifficulty 356 1024 2 0 0
359 | passive_mag_mastery 357 1 12 1211 431 1024 8 0 9 50 0
360 | passive_mag_pierce 358 1 9 2812 1024 8 0 8 0 0
361 |
--------------------------------------------------------------------------------
/tools/esCharView/CharacterEditor/Item.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.ComponentModel;
4 | using System.Linq;
5 | using System.Text;
6 | using BKSystem.IO;
7 |
8 | namespace CharacterEditor
9 | {
10 | public class Item : INotifyPropertyChanged, ICloneable
11 | {
12 | public enum ItemQuality
13 | {
14 | Unknown, // Shouldn't happen
15 | Inferior,
16 | Normal,
17 | Superior,
18 | Magic,
19 | Set,
20 | Rare,
21 | Unique,
22 | Craft
23 | }
24 |
25 | public enum EquipmentLocation
26 | {
27 | None, // Not equipped
28 | Head,
29 | Amulet,
30 | Body,
31 | RightPrimary,
32 | LeftPrimary,
33 | RightRing,
34 | LeftRing,
35 | Belt,
36 | Feet,
37 | Gloves,
38 | RightSecondary,
39 | LeftSecondary
40 | }
41 |
42 | public enum ItemLocation
43 | {
44 | Stored,
45 | Equipped,
46 | Belt,
47 | Ground,
48 | Tohand,
49 | Dropping,
50 | Socketed
51 | }
52 |
53 | public enum StorageType
54 | {
55 | Unknown,
56 | Inventory,
57 | UnknownB,
58 | UnknownC,
59 | Cube,
60 | Stash,
61 | }
62 |
63 | private class ItemData
64 | {
65 | public ItemData()
66 | {
67 |
68 | }
69 |
70 | public ItemData(string name, uint value, int bitCount, int index)
71 | {
72 | this.Index = index;
73 | this.Name = name;
74 | this.Value = value;
75 | this.BitCount = bitCount;
76 | }
77 |
78 | public int Index { get; set; }
79 | public string Name { get; set; }
80 | public object Value { get; set; }
81 | public int BitCount { get; set; }
82 |
83 | public override string ToString()
84 | {
85 | return Value.ToString();
86 | }
87 | }
88 |
89 | public class PropertyInfo : INotifyPropertyChanged
90 | {
91 | private int id;
92 |
93 | public int ID
94 | {
95 | get { return id; }
96 | set
97 | {
98 | id = value;
99 | OnPropertyChange("ID");
100 | OnPropertyChange("PropertyName");
101 | }
102 | }
103 |
104 | public string PropertyName
105 | {
106 | get
107 | {
108 | return ItemDefs.GetPropertyName(ID);
109 | }
110 | }
111 |
112 | public int Value { get; set; }
113 | public int ParamValue { get; set; }
114 | public bool IsAdditionalProperty { get; set; }
115 |
116 | public override string ToString()
117 | {
118 | return string.Format("[{0}] {1} -> {2} [{3}]", ID, PropertyName, Value, ParamValue);
119 | }
120 |
121 | #region INotifyPropertyChanged Members
122 |
123 | public event PropertyChangedEventHandler PropertyChanged;
124 |
125 | private void OnPropertyChange(string propertyName)
126 | {
127 | if (PropertyChanged != null)
128 | {
129 | PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
130 | }
131 | }
132 |
133 | #endregion
134 | }
135 |
136 | private List properties = new List();
137 | private List propertiesSet = new List();
138 | private List propertiesRuneword = new List();
139 | private List
- sockets = new List
- ();
140 | private static Dictionary dataIndicies = new Dictionary();
141 | private Dictionary dataEntries = new Dictionary();
142 | private BitStream bs;
143 | private byte[] remainingBytes;
144 |
145 | ///
146 | /// List of items stored in item's sockets
147 | ///
148 | public List
- Sockets
149 | {
150 | get { return sockets; }
151 | }
152 | ///
153 | /// Item properties
154 | ///
155 | public List Properties
156 | {
157 | get { return properties; }
158 | }
159 | ///
160 | /// Set bonuses for wearing multiple parts
161 | ///
162 | public List PropertiesSet
163 | {
164 | get { return propertiesSet; }
165 | }
166 | ///
167 | /// Runeword properties
168 | ///
169 | public List PropertiesRuneword
170 | {
171 | get { return propertiesRuneword; }
172 | }
173 |
174 | #region SimpleProperties
175 |
176 | // All items must contain these properties, if they don't it's an invalid item and should be caught
177 | public bool IsEquipped
178 | {
179 | get { return GetDataBoolean("IsEquipped"); }
180 | set { SetData("IsEquipped", value); }
181 | }
182 | public bool IsInSocket
183 | {
184 | get { return GetDataBoolean("IsInSocket"); }
185 | set { SetData("IsInSocket", value); }
186 | }
187 | public bool IsIdentified
188 | {
189 | get { return GetDataBoolean("IsIdentified"); }
190 | set { SetData("IsIdentified", value); }
191 | }
192 | public bool IsSwitchIn
193 | {
194 | get { return GetDataBoolean("IsSwitchIn"); }
195 | set { SetData("IsSwitchIn", value); }
196 | }
197 | public bool IsSwitchOut
198 | {
199 | get { return GetDataBoolean("IsSwitchOut"); }
200 | set { SetData("IsSwitchOut", value); }
201 | }
202 | public bool IsBroken
203 | {
204 | get { return GetDataBoolean("IsBroken"); }
205 | set { SetData("IsBroken", value); }
206 | }
207 | public bool IsSocketed
208 | {
209 | get { return GetDataBoolean("IsSocketed"); }
210 | set { SetData("IsSocketed", value); }
211 | }
212 | public bool IsPotion
213 | {
214 | get { return GetDataBoolean("IsPotion"); }
215 | set { SetData("IsPotion", value); }
216 | }
217 | public bool IsStoreItem
218 | {
219 | get { return GetDataBoolean("IsStoreItem"); }
220 | set { SetData("IsStoreItem", value); }
221 | }
222 | public bool IsNotInSocket
223 | {
224 | get { return GetDataBoolean("IsNotInSocket"); }
225 | set { SetData("IsNotInSocket", value); }
226 | }
227 | public bool IsEar
228 | {
229 | get { return GetDataBoolean("IsEar"); }
230 | set { SetData("IsEar", value); }
231 | }
232 | public bool IsStarterItem
233 | {
234 | get { return GetDataBoolean("IsStarterItem"); }
235 | set { SetData("IsStarterItem", value); }
236 | }
237 | public bool IsSimpleItem
238 | {
239 | get { return GetDataBoolean("IsSimpleItem"); }
240 | set { SetData("IsSimpleItem", value); }
241 | }
242 | public bool IsEthereal
243 | {
244 | get { return GetDataBoolean("IsEthereal"); }
245 | set { SetData("IsEthereal", value); }
246 | }
247 | public bool IsPersonalized
248 | {
249 | get { return GetDataBoolean("IsPersonalized"); }
250 | set { SetData("IsPersonalized", value); }
251 | }
252 | public bool IsGamble
253 | {
254 | get { return GetDataBoolean("IsGamble"); }
255 | set { SetData("IsGamble", value); }
256 | }
257 | public bool IsRuneword
258 | {
259 | get { return GetDataBoolean("IsRuneword"); }
260 | set { SetData("IsRuneword", value); }
261 | }
262 | ///
263 | /// ItemLocation enum
264 | ///
265 | public uint Location
266 | {
267 | get { return GetDataValue("Location"); }
268 | set { SetData("Location", value); }
269 | }
270 | ///
271 | /// EquipmentLocation enum
272 | ///
273 | public uint PositionOnBody
274 | {
275 | get { return GetDataValue("PositionOnBody"); }
276 | set { SetData("PositionOnBody", value); }
277 | }
278 | public uint PositionX
279 | {
280 | get { return GetDataValue("PositionX"); }
281 | set { SetData("PositionX", value); }
282 | }
283 | public uint PositionY
284 | {
285 | get { return GetDataValue("PositionY"); }
286 | set { SetData("PositionY", value); }
287 | }
288 | ///
289 | /// StorageType enum
290 | ///
291 | public uint StorageId
292 | {
293 | get { return GetDataValue("StorageId"); }
294 | set { SetData("StorageId", value); }
295 | }
296 | #endregion
297 |
298 | #region ExtendedProperties
299 |
300 | public string ItemCode
301 | {
302 | get
303 | {
304 | if (IsEar)
305 | {
306 | return "ear";
307 | }
308 |
309 | return GetDataObject("ItemCode") as string;
310 | //return dataEntries["ItemCode"].Value as string;
311 | }
312 | set
313 | {
314 | if (value.Length < 3)
315 | {
316 | return;
317 | }
318 | SetData("ItemCode", value.Substring(0, 3));
319 | }
320 | }
321 |
322 | public uint GoldAmountSmall
323 | {
324 | get { return GetDataValue("GoldAmountSmall"); }
325 | set { SetData("GoldAmountSmall", value); }
326 | }
327 | public uint GoldAmountLarge
328 | {
329 | get { return GetDataValue("GoldAmountLarge"); }
330 | set { SetData("GoldAmountLarge", value); }
331 | }
332 | public uint SocketsFilled
333 | {
334 | get { return GetDataValue("SocketsFilled"); }
335 | set { SetData("SocketsFilled", value); }
336 | }
337 | public uint Id
338 | {
339 | get { return GetDataValue("Id"); }
340 | set { SetData("Id", value); }
341 | }
342 | public uint Level
343 | {
344 | get
345 | {
346 | if (IsEar)
347 | {
348 | return EarLevel;
349 | }
350 |
351 | return GetDataValue("Level");
352 | }
353 | set
354 | {
355 | SetData("Level", value);
356 | }
357 | }
358 | ///
359 | /// ItemQuality enum
360 | ///
361 | public uint Quality
362 | {
363 | get { return GetDataValue("Quality"); }
364 | set { SetData("Quality", value); }
365 | }
366 | public bool HasGraphic
367 | {
368 | get { return GetDataBoolean("HasGraphic"); }
369 | set { SetData("HasGraphic", value); }
370 | }
371 | public uint Graphic
372 | {
373 | get { return GetDataValue("Graphic"); }
374 | set { SetData("Graphic", value); }
375 | }
376 | public uint UniqueSetId
377 | {
378 | get { return GetDataValue("UniqueSetId"); }
379 | set { SetData("UniqueSetId", value); }
380 | }
381 | public uint Defense
382 | {
383 | get { return GetDataValue("Defense"); }
384 | set { SetData("Defense", value); }
385 | }
386 | public uint MaxDurability
387 | {
388 | get { return GetDataValue("MaxDurability"); }
389 | set { SetData("MaxDurability", value); }
390 | }
391 | public uint Durability
392 | {
393 | get { return GetDataValue("Durability"); }
394 | set { SetData("Durability", value); }
395 | }
396 | public bool IsIndestructable
397 | {
398 | get { return GetDataBoolean("IsIndestructable"); }
399 | set { SetData("IsIndestructable", value); }
400 | }
401 | public uint SocketCount
402 | {
403 | get { return GetDataValue("SocketCount"); }
404 | set { SetData("SocketCount", value); }
405 | }
406 | public uint Quantity
407 | {
408 | get { return GetDataValue("Quantity"); }
409 | set { SetData("Quantity", value); }
410 | }
411 | public bool RandomFlag
412 | {
413 | get { return GetDataBoolean("RandomFlag"); }
414 | set { SetData("RandomFlag", value); }
415 | }
416 | public bool UnknownGoldFlag
417 | {
418 | get { return GetDataBoolean("UnknownGoldFlag"); }
419 | set { SetData("UnknownGoldFlag", value); }
420 | }
421 | public bool ClassFlag
422 | {
423 | get { return GetDataBoolean("ClassFlag"); }
424 | set { SetData("ClassFlag", value); }
425 | }
426 | public uint ClassInfo
427 | {
428 | get { return GetDataValue("ClassInfo"); }
429 | set { SetData("ClassInfo", value); }
430 | }
431 | public uint InferiorQualityType
432 | {
433 | get { return GetDataValue("InferiorQualityType"); }
434 | set { SetData("InferiorQualityType", value); }
435 | }
436 | public uint SuperiorQualityType
437 | {
438 | get { return GetDataValue("SuperiorQualityType"); }
439 | set { SetData("SuperiorQualityType", value); }
440 | }
441 | public uint CharmData
442 | {
443 | get { return GetDataValue("CharmData"); }
444 | set { SetData("CharmData", value); }
445 | }
446 | public uint SpellId
447 | {
448 | get { return GetDataValue("SpellId"); }
449 | set { SetData("SpellId", value); }
450 | }
451 | public uint MonsterId
452 | {
453 | get { return GetDataValue("MonsterId"); }
454 | set { SetData("MonsterId", value); }
455 | }
456 | public uint EarClass
457 | {
458 | get { return GetDataValue("EarClass"); }
459 | set { SetData("EarClass", value); }
460 | }
461 | public uint EarLevel
462 | {
463 | get { return GetDataValue("EarLevel"); }
464 | set { SetData("EarLevel", value); }
465 | }
466 | public string EarName
467 | {
468 | get { return (string)GetDataObject("EarName"); }
469 | protected set { SetData("EarName", value.Length > 17 ? value.Substring(0, 17) : value); }
470 | }
471 | public string PersonalizedName
472 | {
473 | get { return (string)GetDataObject("PersonalizedName"); }
474 | protected set { SetData("PersonalizedName", value.Length > 17 ? value.Substring(0, 17) : value); }
475 | }
476 | public uint RunewordId
477 | {
478 | get { return GetDataValue("RunewordId"); }
479 | set { SetData("RunewordId", value); }
480 | }
481 |
482 | #endregion
483 |
484 | #region Affix
485 |
486 | public uint PrefixNameId
487 | {
488 | get { return GetDataValue("PrefixNameId"); }
489 | set { SetData("PrefixNameId", value); }
490 | }
491 | public uint SuffixNameId
492 | {
493 | get { return GetDataValue("SuffixNameId"); }
494 | set { SetData("SuffixNameId", value); }
495 | }
496 | public bool PrefixFlag0
497 | {
498 | get { return GetDataBoolean("PrefixFlag0"); }
499 | set { SetData("PrefixFlag0", value); }
500 | }
501 | public bool PrefixFlag1
502 | {
503 | get { return GetDataBoolean("PrefixFlag1"); }
504 | set { SetData("PrefixFlag1", value); }
505 | }
506 | public bool PrefixFlag2
507 | {
508 | get { return GetDataBoolean("PrefixFlag2"); }
509 | set { SetData("PrefixFlag2", value); }
510 | }
511 | public bool SuffixFlag0
512 | {
513 | get { return GetDataBoolean("SuffixFlag0"); }
514 | set { SetData("SuffixFlag0", value); }
515 | }
516 | public bool SuffixFlag1
517 | {
518 | get { return GetDataBoolean("SuffixFlag1"); }
519 | set { SetData("SuffixFlag1", value); }
520 | }
521 | public bool SuffixFlag2
522 | {
523 | get { return GetDataBoolean("SuffixFlag2"); }
524 | set { SetData("SuffixFlag2", value); }
525 | }
526 | public uint MagicPrefix
527 | {
528 | get { return GetDataValue("MagicPrefix"); }
529 | set { SetData("MagicPrefix", value); }
530 | }
531 | public uint MagicSuffix
532 | {
533 | get { return GetDataValue("MagicSuffix"); }
534 | set { SetData("MagicSuffix", value); }
535 | }
536 | public uint Prefix0
537 | {
538 | get { return GetDataValue("Prefix0"); }
539 | set { SetData("Prefix0", value); }
540 | }
541 | public uint Prefix1
542 | {
543 | get { return GetDataValue("Prefix1"); }
544 | set { SetData("Prefix1", value); }
545 | }
546 | public uint Prefix2
547 | {
548 | get { return GetDataValue("Prefix2"); }
549 | set { SetData("Prefix2", value); }
550 | }
551 | public uint Suffix0
552 | {
553 | get { return GetDataValue("Suffix0"); }
554 | set { SetData("Suffix0", value); }
555 | }
556 | public uint Suffix1
557 | {
558 | get { return GetDataValue("Suffix1"); }
559 | set { SetData("Suffix1", value); }
560 | }
561 | public uint Suffix2
562 | {
563 | get { return GetDataValue("Suffix2"); }
564 | set { SetData("Suffix2", value); }
565 | }
566 | #endregion
567 |
568 |
569 | static Item()
570 | {
571 | CreateDataIndicies();
572 | }
573 |
574 | ///
575 | ///
576 | ///
577 | ///
578 | /// must be true only if new Item is created from byte[] array
579 | public Item(byte[] itemData, bool forceReadSockets)
580 | {
581 | if (itemData[0] != 'J' || itemData[1] != 'M')
582 | {
583 | throw new Exception("Item data missing JM header");
584 | }
585 |
586 | bs = new BitStream(itemData);
587 |
588 | ReadItemData();
589 | ReadRemainingBits();
590 |
591 | if (forceReadSockets)
592 | ReadSockets(itemData);
593 | }
594 |
595 |
596 | ///
597 | /// Decodes raw item data
598 | ///
599 | private void ReadItemData()
600 | {
601 | ReadItemDataSimple();
602 |
603 | if (IsEar)
604 | {
605 | ReadItemDataEar();
606 | return;
607 | }
608 |
609 | ReadString("ItemCode", 3, 8, true);
610 |
611 | // Read gold data if it's gold
612 | if (ItemCode.ToLower() == "gld")
613 | {
614 | ReadItemDataGold();
615 | return;
616 | }
617 |
618 | if (IsSimpleItem)
619 | {
620 | return;
621 | }
622 |
623 | ReadItemDataExtended();
624 |
625 | // TODO: Not sure what this bit is, I can't find any items with it set
626 | // Extend.txt says it's some sort of random flag followed by 40 bits
627 | ReadData("RandomFlag", 1);
628 | if (RandomFlag)
629 | {
630 | ReadData("Unknown8", 8);
631 | ReadData("Unknown9", 32);
632 | }
633 |
634 | // Type specific extended data
635 | ReadItemDataExtendedSpecific();
636 | }
637 |
638 | ///
639 | /// Decodes basic item data. All items have basic data
640 | ///
641 | private void ReadItemDataSimple()
642 | {
643 | bs.SkipBits(16); // "JM" header
644 |
645 | ReadData("IsEquipped", 1);
646 | ReadData("Unknown0", 2);
647 | ReadData("IsInSocket", 1);
648 | ReadData("IsIdentified", 1);
649 | ReadData("Unknown1", 1);
650 | ReadData("IsSwitchIn", 1);
651 | ReadData("IsSwitchOut", 1);
652 | ReadData("IsBroken", 1);
653 | ReadData("Unknown2", 1);
654 | ReadData("IsPotion", 1);
655 | ReadData("IsSocketed", 1);
656 | ReadData("Unknown3", 1);
657 | ReadData("IsStoreItem", 1);
658 | ReadData("IsNotInSocket", 1);
659 | ReadData("Unknown4", 1);
660 | ReadData("IsEar", 1);
661 | ReadData("IsStarterItem", 1);
662 | ReadData("Unknown5", 3);
663 | ReadData("IsSimpleItem", 1);
664 | ReadData("IsEthereal", 1);
665 | ReadData("Unknown6", 1);
666 | ReadData("IsPersonalized", 1);
667 | ReadData("IsGamble", 1);
668 | ReadData("IsRuneword", 1);
669 | ReadData("Unknown7", 15);
670 | ReadData("Location", 3);
671 | ReadData("PositionOnBody", 4);
672 | ReadData("PositionX", 4);
673 | ReadData("PositionY", 4);
674 | ReadData("StorageId", 3);
675 | }
676 |
677 | ///
678 | /// Decodes ear data
679 | ///
680 | private void ReadItemDataEar()
681 | {
682 | ReadData("EarClass", 3);
683 | ReadData("EarLevel", 7);
684 | ReadString("EarName", 7);
685 |
686 | if (EarName.Trim().Length == 0)
687 | {
688 | throw new Exception("Invalid Ear: Blank ear name");
689 | }
690 |
691 | foreach (char ch in EarName)
692 | {
693 | if (!Char.IsLetterOrDigit(ch) && ch != '-' && ch != '_')
694 | {
695 | throw new Exception("Invalid Ear: Ear name contains invalid characters");
696 | }
697 | }
698 |
699 | return;
700 | }
701 |
702 | ///
703 | /// Decodes gold data
704 | ///
705 | private void ReadItemDataGold()
706 | {
707 | ReadData("UnknownGoldFlag", 1);
708 |
709 | // Not sure if this is correct
710 | if (UnknownGoldFlag)
711 | ReadData("GoldAmountLarge", 32);
712 | else
713 | ReadData("GoldAmountSmall", 12);
714 |
715 | return;
716 | }
717 |
718 | ///
719 | /// Decodes extended item data
720 | ///
721 | private void ReadItemDataExtended()
722 | {
723 | ReadData("SocketsFilled", 3);
724 | ReadData("Id", 32);
725 | ReadData("Level", 7);
726 | ReadData("Quality", 4);
727 | ReadData("HasGraphic", 1);
728 | if (HasGraphic)
729 | {
730 | ReadData("Graphic", 3);
731 | }
732 |
733 | // No idea what this flag is. Some say Class data others say Color data
734 | ReadData("ClassFlag", 1);
735 | if (ClassFlag)
736 | {
737 | ReadData("ClassInfo", 11);
738 | }
739 |
740 | switch ((ItemQuality)Quality)
741 | {
742 | case ItemQuality.Inferior:
743 | ReadData("InferiorQualityType", 3);
744 | break;
745 | case ItemQuality.Superior:
746 | ReadData("SuperiorQualityType", 3);
747 | break;
748 |
749 | case ItemQuality.Normal:
750 | if (ItemDefs.IsCharm(ItemCode))
751 | {
752 | ReadData("CharmData", 12);
753 | }
754 | if (ItemDefs.IsScrollOrTome(ItemCode))
755 | {
756 | ReadData("SpellId", 5);
757 | }
758 | else if (ItemDefs.IsMonsterPart(ItemCode))
759 | {
760 | ReadData("MonsterId", 10);
761 | }
762 | break;
763 |
764 | case ItemQuality.Magic:
765 | ReadData("MagicPrefix", 11);
766 | ReadData("MagicSuffix", 11);
767 | break;
768 |
769 | case ItemQuality.Rare:
770 | case ItemQuality.Craft:
771 | ReadData("PrefixNameId", 8);
772 | ReadData("SuffixNameId", 8);
773 |
774 | for (int i = 0; i < 3; i++)
775 | {
776 | string prefixIndex = string.Format("PrefixFlag{0}", i);
777 |
778 | ReadData(prefixIndex, 1);
779 | if (GetDataBoolean(prefixIndex))
780 | {
781 | ReadData(string.Format("Prefix{0}", i), 11);
782 | }
783 |
784 | string suffixIndex = string.Format("SuffixFlag{0}", i);
785 |
786 | ReadData(suffixIndex, 1);
787 | if (GetDataBoolean(suffixIndex))
788 | {
789 | ReadData(string.Format("Suffix{0}", i), 11);
790 | }
791 | }
792 | break;
793 |
794 | case ItemQuality.Unique:
795 | case ItemQuality.Set:
796 | ReadData("UniqueSetId", 12);
797 | break;
798 |
799 | default:
800 | break;
801 | }
802 |
803 | if (IsRuneword)
804 | {
805 | ReadData("RunewordId", 16);
806 | }
807 | if (IsPersonalized)
808 | {
809 | ReadString("PersonalizedName", 7); //TODO: 15 in ROT?
810 | }
811 | }
812 |
813 | ///
814 | /// Decodes item specific data
815 | ///
816 | private void ReadItemDataExtendedSpecific()
817 | {
818 | if (ItemDefs.IsArmor(ItemCode))
819 | {
820 | ReadData("Defense", ItemDefs.ItemStatCostsByName["armorclass"].SaveBits);
821 | Defense -= (uint)ItemDefs.ItemStatCostsByName["armorclass"].SaveAdd;
822 | }
823 |
824 | if (ItemDefs.IsWeapon(ItemCode) || ItemDefs.IsArmor(ItemCode))
825 | {
826 | ReadData("MaxDurability", ItemDefs.ItemStatCostsByName["maxdurability"].SaveBits);
827 | MaxDurability -= (uint)ItemDefs.ItemStatCostsByName["maxdurability"].SaveAdd;
828 |
829 | if (MaxDurability != 0)
830 | {
831 | ReadData("Durability", ItemDefs.ItemStatCostsByName["durability"].SaveBits);
832 | Durability -= (uint)ItemDefs.ItemStatCostsByName["durability"].SaveAdd;
833 | }
834 | else
835 | {
836 | IsIndestructable = true;
837 | }
838 | }
839 |
840 | // Not sure of the order of socketed+stackable. Socketed arrows seem to mess up
841 | if (ItemDefs.IsStackable(ItemCode))
842 | {
843 | ReadData("Quantity", 9);
844 | }
845 | if (IsSocketed)
846 | {
847 | ReadData("SocketCount", 4);
848 | }
849 |
850 | if ((ItemQuality)Quality == ItemQuality.Set)
851 | {
852 | ReadData("NumberOfSetProperties", 5);
853 | }
854 |
855 | ReadPropertyList(properties);
856 |
857 | if ((ItemQuality)Quality == ItemQuality.Set)
858 | {
859 | int numberOfSetProperties = (int)GetDataValue("NumberOfSetProperties");
860 |
861 | while (bs.RemainingBits > 9)
862 | {
863 | ReadPropertyList(propertiesSet);
864 | }
865 | }
866 |
867 | if (IsRuneword)
868 | {
869 | ReadPropertyList(propertiesRuneword);
870 | }
871 | }
872 |
873 | ///
874 | /// Reads a list of properties to specified property list from the BitReader
875 | ///
876 | /// List of properties to read properties into
877 | private void ReadPropertyList(List propertyList)
878 | {
879 | while (true)
880 | {
881 | int currentPropertyID = (int)bs.ReadReversed(9);
882 | if (currentPropertyID == 0x1ff)
883 | {
884 | propertyList.Add(new PropertyInfo() { ID = currentPropertyID });
885 | break;
886 | }
887 |
888 | ReadPropertyData(propertyList, currentPropertyID);
889 | }
890 | }
891 |
892 | ///
893 | /// Reads property data for a specified ID from BitReader
894 | ///
895 | /// List of properties to add data to
896 | /// ID of property to read from BitReader
897 | /// Property to read has no header. Found in damage type properties
898 | private void ReadPropertyData(List propertyList, int currentPropertyID, bool isAdditional = false)
899 | {
900 | //ItemStatCost statCost = null;
901 | //if (ItemDefs.ItemStatCostsById.ContainsKey(currentPropertyID))
902 | ItemStatCost statCost = ItemDefs.ItemStatCostsById[currentPropertyID];
903 |
904 | if (statCost == null)
905 | return;
906 |
907 | PropertyInfo currentPropertyInfo = new PropertyInfo();
908 |
909 | currentPropertyInfo.IsAdditionalProperty = isAdditional;
910 | currentPropertyInfo.ID = currentPropertyID;
911 | currentPropertyInfo.Value = (int)bs.ReadReversed(statCost.SaveBits) - statCost.SaveAdd;
912 |
913 | if (statCost.SaveParamBits > 0)
914 | {
915 | currentPropertyInfo.ParamValue = (int)bs.ReadReversed(statCost.SaveParamBits);
916 | }
917 |
918 | propertyList.Add(currentPropertyInfo);
919 |
920 | switch (statCost.Stat)
921 | {
922 | case "item_maxdamage_percent":
923 | ReadPropertyData(propertyList, ItemDefs.ItemStatCostsByName["item_mindamage_percent"].ID, true);
924 | break;
925 | case "firemindam":
926 | ReadPropertyData(propertyList, ItemDefs.ItemStatCostsByName["firemaxdam"].ID, true);
927 | break;
928 | case "lightmindam":
929 | ReadPropertyData(propertyList, ItemDefs.ItemStatCostsByName["lightmaxdam"].ID, true);
930 | break;
931 | case "magicmindam":
932 | ReadPropertyData(propertyList, ItemDefs.ItemStatCostsByName["magicmaxdam"].ID, true);
933 | break;
934 | case "coldmindam":
935 | ReadPropertyData(propertyList, ItemDefs.ItemStatCostsByName["coldmaxdam"].ID, true);
936 | ReadPropertyData(propertyList, ItemDefs.ItemStatCostsByName["coldlength"].ID, true);
937 | break;
938 | case "poisonmindam":
939 | ReadPropertyData(propertyList, ItemDefs.ItemStatCostsByName["poisonmaxdam"].ID, true);
940 | ReadPropertyData(propertyList, ItemDefs.ItemStatCostsByName["poisonlength"].ID, true);
941 | break;
942 | default:
943 | break;
944 | }
945 |
946 | }
947 |
948 | ///
949 | /// Removes a socketed item from this item and returns it for further processing
950 | ///
951 | /// Index of socket to remove
952 | /// Socketed item already modified to be stored
953 | public Item RemoveSocketedItem(int index)
954 | {
955 | if (index < 0 || index > SocketsFilled)
956 | {
957 | throw new Exception("RemoveSocketedItem: Socket index out of bounds");
958 | }
959 |
960 | if (IsRuneword)
961 | {
962 | ClearRunewordData();
963 | }
964 |
965 | Item socketedItem = Sockets[index];
966 | socketedItem.IsNotInSocket = true;
967 | socketedItem.IsInSocket = false;
968 | socketedItem.Location = (uint)Item.ItemLocation.Stored;
969 |
970 | Sockets.RemoveAt(index);
971 | SocketsFilled--;
972 |
973 | return socketedItem;
974 | }
975 |
976 | public void ClearRunewordData()
977 | {
978 | IsRuneword = false;
979 | propertiesRuneword.Clear();
980 |
981 | if (dataEntries.ContainsKey("RunewordId"))
982 | {
983 | dataEntries.Remove("RunewordId");
984 | }
985 | }
986 |
987 | ///
988 | /// Reads the remaining bits to the remainingBytes array and LAST property
989 | ///
990 | private void ReadRemainingBits()
991 | {
992 | int paddingBitCount = GetPaddingBitCount();
993 | int remainingByteCount = (int)((int)(bs.RemainingBits) - paddingBitCount) / 8;
994 |
995 | if (remainingByteCount > 0)
996 | {
997 | remainingBytes = bs.ReadReversedBytes(remainingByteCount);
998 | }
999 |
1000 | if ((bs.RemainingBits) - paddingBitCount > 0)
1001 | {
1002 | ReadData("LAST", (int)(bs.RemainingBits) - paddingBitCount);
1003 | }
1004 | }
1005 |
1006 |
1007 | // ADDED by HarpyWar
1008 | private void ReadSockets(byte[] itemBytes)
1009 | {
1010 | if (IsSocketed)
1011 | {
1012 | // set begin position (this is without sockets, so start to read sockets from here)
1013 | var begin = GetItemBytes().Length;
1014 |
1015 | uint failedSockets = 0;
1016 |
1017 | for (int i = 0; i < SocketsFilled; i++)
1018 | {
1019 | Item nextItem = GetNextSocket(itemBytes, ref begin);
1020 |
1021 | if (nextItem == null)
1022 | {
1023 | failedSockets++;
1024 | continue;
1025 | }
1026 |
1027 | Sockets.Add(nextItem);
1028 | }
1029 | }
1030 | }
1031 | private Item GetNextSocket(byte[] itemBytes, ref int begin)
1032 | {
1033 | int itemDataSize = GetNextSocketSize(itemBytes, begin);
1034 | byte[] itemData = new byte[itemDataSize];
1035 | Array.Copy(itemBytes, begin, itemData, 0, itemDataSize);
1036 |
1037 | return new Item(itemData);
1038 | }
1039 | private int GetNextSocketSize(byte[] itemBytes, int begin)
1040 | {
1041 | for (int i = begin + 2; i < itemBytes.Length - 1; i++)
1042 | {
1043 | // Header of next item record or end of inventory list reached
1044 | if (itemBytes[i] == 'J' && itemBytes[i + 1] == 'M')
1045 | {
1046 | return i - begin;
1047 | }
1048 | }
1049 |
1050 | return itemBytes.Length - begin;
1051 | }
1052 |
1053 |
1054 |
1055 | ///
1056 | /// Reads a value (up to 32 bits) from the BitReader
1057 | ///
1058 | /// Name of the property to create to store the data
1059 | /// Number of bits to read
1060 | private void ReadData(string name, int bitCount)
1061 | {
1062 | ItemData data = new ItemData();
1063 |
1064 | if (!dataIndicies.ContainsKey(name))
1065 | {
1066 | throw new Exception("ReadData: Invalid property name specified");
1067 | }
1068 |
1069 | data.Index = dataIndicies[name];
1070 | data.BitCount = bitCount;
1071 | data.Value = bs.ReadReversed(bitCount);
1072 | data.Name = name;
1073 |
1074 | dataEntries.Add(data.Name, data);
1075 | }
1076 |
1077 | ///
1078 | /// Reads a sequence of characters from the BitStream
1079 | ///
1080 | /// Name of property to store data in
1081 | /// Number of characters to read
1082 | /// Skip an additional byte after reading the characters
1083 | private void ReadString(string name, int characterCount, int bitsPerChar, bool skipFollowingByte)
1084 | {
1085 | ItemData data = new ItemData();
1086 |
1087 | if (!dataIndicies.ContainsKey(name))
1088 | {
1089 | throw new Exception("ReadString: Invalid property name specified");
1090 | }
1091 |
1092 | data.Index = dataIndicies[name];
1093 | data.Value = bs.ReadReversedString(characterCount, bitsPerChar);
1094 | data.BitCount = (data.Value as string).Length * bitsPerChar;
1095 | data.Name = name;
1096 |
1097 | if (skipFollowingByte)
1098 | {
1099 | bs.ReadReversedByte();
1100 | }
1101 |
1102 | dataEntries.Add(data.Name, data);
1103 | }
1104 |
1105 | ///
1106 | /// Reads a null terminated string from the BitStream
1107 | ///
1108 | /// Name of property to store data in
1109 | /// Number of characters to read
1110 | private void ReadString(string name, int bitsPerChar)
1111 | {
1112 | ItemData data = new ItemData();
1113 |
1114 | if (!dataIndicies.ContainsKey(name))
1115 | {
1116 | throw new Exception("ReadString: Invalid property name specified");
1117 | }
1118 |
1119 | data.Index = dataIndicies[name];
1120 | data.Value = bs.ReadReversedString(bitsPerChar);
1121 | data.BitCount = (data.Value as string).Length * bitsPerChar;
1122 | data.Name = name;
1123 |
1124 | dataEntries.Add(data.Name, data);
1125 | }
1126 |
1127 | ///
1128 | /// Gets an object item property
1129 | ///
1130 | /// Name of property to get
1131 | /// Value of property
1132 | private object GetDataObject(string name)
1133 | {
1134 | if (!dataEntries.ContainsKey(name))
1135 | {
1136 | return null;
1137 | }
1138 |
1139 | return dataEntries[name].Value;
1140 | }
1141 |
1142 | ///
1143 | /// Gets an unsigned integer item property
1144 | ///
1145 | /// Name of property to get
1146 | /// Value of property
1147 | private uint GetDataValue(string name)
1148 | {
1149 | if (!dataEntries.ContainsKey(name))
1150 | {
1151 | return 0;
1152 | }
1153 |
1154 | return (uint)dataEntries[name].Value;
1155 | }
1156 |
1157 | ///
1158 | /// Gets a boolean item property
1159 | ///
1160 | /// Name of property to get
1161 | /// Value of property
1162 | private bool GetDataBoolean(string name)
1163 | {
1164 | if (!dataEntries.ContainsKey(name))
1165 | {
1166 | return false;
1167 | }
1168 |
1169 | if (dataEntries[name].Value.GetType() == typeof(bool))
1170 | {
1171 | return (bool)dataEntries[name].Value;
1172 | }
1173 | else
1174 | {
1175 | return (uint)dataEntries[name].Value == 1;
1176 | }
1177 | }
1178 |
1179 | ///
1180 | /// Sets an item's property if it exists
1181 | ///
1182 | /// Name of property to set
1183 | /// Value to set property to
1184 | private void SetData(string name, object value)
1185 | {
1186 | if (!dataEntries.ContainsKey(name))
1187 | {
1188 | return;
1189 | }
1190 |
1191 | dataEntries[name].Value = value;
1192 | OnPropertyChange(name);
1193 | }
1194 |
1195 | ///
1196 | /// Gets the number of bits used for 0 padding to set the remaining bits in last byte to 8
1197 | ///
1198 | /// Number of bits used for padding
1199 | private int GetPaddingBitCount()
1200 | {
1201 | long brPos = bs.Position;
1202 |
1203 | if (!IsSimpleItem)
1204 | {
1205 | bs.Position -= 9;
1206 | while (bs.Position > 0)
1207 | {
1208 | if (bs.ReadReversed(9) == 0x1ff)
1209 | {
1210 | bs.Position = brPos;
1211 | return (int)(bs.RemainingBits);
1212 | }
1213 | bs.Position -= 10;
1214 | }
1215 | }
1216 |
1217 | bs.Position = brPos;
1218 | return 0;
1219 | }
1220 |
1221 | ///
1222 | /// Converts specified item into item format for save file
1223 | ///
1224 | /// Byte representation of item for save file
1225 | public byte[] GetItemBytes()
1226 | {
1227 | BitStream bs = new BitStream();
1228 |
1229 | bs.WriteReversed('J', 8);
1230 | bs.WriteReversed('M', 8);
1231 |
1232 | var ordered = dataEntries.OrderBy(n => n.Value.Index);
1233 |
1234 | foreach (var item in ordered)
1235 | {
1236 | if (item.Value.Value is string)
1237 | {
1238 | string value = item.Value.Value as string;
1239 |
1240 | if (item.Key == "ItemCode")
1241 | {
1242 | foreach (var ch in value)
1243 | {
1244 | bs.WriteReversed(ch, 8);
1245 | }
1246 | bs.WriteReversed(' ', 8);
1247 | }
1248 | else if (item.Key == "EarName" || item.Key == "PersonalizedName")
1249 | {
1250 | foreach (var ch in value)
1251 | {
1252 | bs.WriteReversed(ch, 7);
1253 | }
1254 | bs.WriteReversed(0, 7);
1255 | }
1256 | else
1257 | {
1258 | throw new Exception("Unknown string type in item data");
1259 | }
1260 | }
1261 | else if (item.Value.Value is ValueType)
1262 | {
1263 | // LAST key is the very last property added to the item data
1264 | if (item.Key == "LAST")
1265 | continue;
1266 |
1267 | TypeCode valueType = Type.GetTypeCode(item.Value.Value.GetType());
1268 |
1269 | if (valueType == TypeCode.UInt32)
1270 | {
1271 | uint value = (uint)item.Value.Value;
1272 |
1273 | if (item.Key == "Defense")
1274 | {
1275 | value += (uint)ItemDefs.ItemStatCostsByName["armorclass"].SaveAdd;
1276 | }
1277 | else if (item.Key == "MaxDurability")
1278 | {
1279 | value += (uint)ItemDefs.ItemStatCostsByName["maxdurability"].SaveAdd;
1280 | }
1281 | else if (item.Key == "Durability")
1282 | {
1283 | value += (uint)ItemDefs.ItemStatCostsByName["durability"].SaveAdd;
1284 | }
1285 |
1286 | bs.WriteReversed(value, item.Value.BitCount);
1287 | }
1288 | else if (valueType == TypeCode.Int32)
1289 | {
1290 | bs.WriteReversed((uint)((int)item.Value.Value), item.Value.BitCount);
1291 | }
1292 | else if (valueType == TypeCode.Boolean)
1293 | {
1294 | bs.Write((bool)item.Value.Value);
1295 | }
1296 | else
1297 | {
1298 | throw new Exception("Invalid ValueType!");
1299 | }
1300 | }
1301 | else
1302 | {
1303 | throw new Exception("Invalid data type in item dataEntries");
1304 | }
1305 | }
1306 |
1307 | foreach (var item in properties)
1308 | {
1309 | WriteItemProperty(bs, item);
1310 | }
1311 |
1312 | foreach (var item in propertiesSet)
1313 | {
1314 | WriteItemProperty(bs, item);
1315 | }
1316 |
1317 | foreach (var item in propertiesRuneword)
1318 | {
1319 | WriteItemProperty(bs, item);
1320 | }
1321 |
1322 | // Some simple items do have remaining data such as the soulstone
1323 | if (IsSimpleItem)
1324 | {
1325 | //TODO: Enable renaming of ear and personlized names?
1326 | if (remainingBytes != null)
1327 | {
1328 | bs.WriteReversed(remainingBytes);
1329 | }
1330 |
1331 | if (dataEntries.ContainsKey("LAST"))
1332 | {
1333 | var lastEntry = dataEntries["LAST"];
1334 | bs.WriteReversed((uint)lastEntry.Value, lastEntry.BitCount);
1335 | }
1336 | }
1337 | else
1338 | {
1339 | // Fill the last byte with 0 if it's not already full
1340 | if ((bs.Position % 8) != 0)
1341 | {
1342 | int bitsToAdd = 8 - (int)(bs.Position % 8);
1343 | if (bitsToAdd > 0)
1344 | {
1345 | bs.WriteReversed(0, bitsToAdd);
1346 | }
1347 | }
1348 | }
1349 |
1350 | var itemBytes = bs.ToReversedByteArray();
1351 | return addSocketsBytes(itemBytes);
1352 | }
1353 |
1354 | ///
1355 | /// Merge item bytes and sockets bytes
1356 | ///
1357 | ///
1358 | private byte[] addSocketsBytes(byte[] itemBytes)
1359 | {
1360 | var bytes = new List();
1361 | bytes.AddRange(itemBytes);
1362 |
1363 | foreach (var socket in Sockets)
1364 | bytes.AddRange(socket.GetItemBytes());
1365 |
1366 | return bytes.ToArray();
1367 | }
1368 |
1369 | ///
1370 | /// Writes an item property to the BitStream
1371 | ///
1372 | /// Bitstream to write property to
1373 | /// Property to write
1374 | private void WriteItemProperty(BitStream bs, PropertyInfo property)
1375 | {
1376 | if (property.ID == 0x1ff)
1377 | {
1378 | bs.WriteReversed(property.ID, 9);
1379 | return;
1380 | }
1381 |
1382 | ItemStatCost statCost = ItemDefs.ItemStatCostsById[property.ID];
1383 |
1384 | int fixedValue = property.Value + statCost.SaveAdd;
1385 |
1386 | if (!property.IsAdditionalProperty)
1387 | {
1388 | bs.WriteReversed(property.ID, 9);
1389 | }
1390 |
1391 | bs.WriteReversed(fixedValue, statCost.SaveBits);
1392 |
1393 | if (statCost.SaveParamBits > 0)
1394 | {
1395 | bs.WriteReversed(property.ParamValue, statCost.SaveParamBits);
1396 | }
1397 | }
1398 |
1399 | ///
1400 | /// Creates a list of indicies for each data entry name
1401 | ///
1402 | private static void CreateDataIndicies()
1403 | {
1404 | int index = 0;
1405 |
1406 | // Simple data
1407 | dataIndicies.Add("IsEquipped", index++);
1408 | dataIndicies.Add("Unknown0", index++);
1409 | dataIndicies.Add("IsInSocket", index++);
1410 | dataIndicies.Add("IsIdentified", index++);
1411 | dataIndicies.Add("Unknown1", index++);
1412 | dataIndicies.Add("IsSwitchIn", index++);
1413 | dataIndicies.Add("IsSwitchOut", index++);
1414 | dataIndicies.Add("IsBroken", index++);
1415 | dataIndicies.Add("Unknown2", index++);
1416 | dataIndicies.Add("IsPotion", index++);
1417 | dataIndicies.Add("IsSocketed", index++);
1418 | dataIndicies.Add("Unknown3", index++);
1419 | dataIndicies.Add("IsStoreItem", index++);
1420 | dataIndicies.Add("IsNotInSocket", index++);
1421 | dataIndicies.Add("Unknown4", index++);
1422 | dataIndicies.Add("IsEar", index++);
1423 | dataIndicies.Add("IsStarterItem", index++);
1424 | dataIndicies.Add("Unknown5", index++);
1425 | dataIndicies.Add("IsSimpleItem", index++);
1426 | dataIndicies.Add("IsEthereal", index++);
1427 | dataIndicies.Add("Unknown6", index++);
1428 | dataIndicies.Add("IsPersonalized", index++);
1429 | dataIndicies.Add("IsGamble", index++);
1430 | dataIndicies.Add("IsRuneword", index++);
1431 | dataIndicies.Add("Unknown7", index++);
1432 | dataIndicies.Add("Location", index++);
1433 | dataIndicies.Add("PositionOnBody", index++);
1434 | dataIndicies.Add("PositionX", index++);
1435 | dataIndicies.Add("PositionY", index++);
1436 | dataIndicies.Add("StorageId", index++);
1437 |
1438 | // Ear data
1439 | dataIndicies.Add("EarClass", index++);
1440 | dataIndicies.Add("EarLevel", index++);
1441 | dataIndicies.Add("EarName", index++);
1442 |
1443 | // Extended data
1444 | dataIndicies.Add("ItemCode", index++);
1445 |
1446 | // Gold Data
1447 | dataIndicies.Add("UnknownGoldFlag", index++);
1448 | dataIndicies.Add("GoldAmountLarge", index++);
1449 | dataIndicies.Add("GoldAmountSmall", index++);
1450 |
1451 | // Extended data
1452 | dataIndicies.Add("SocketsFilled", index++);
1453 | dataIndicies.Add("Id", index++);
1454 | dataIndicies.Add("Level", index++);
1455 | dataIndicies.Add("Quality", index++);
1456 | dataIndicies.Add("HasGraphic", index++);
1457 | dataIndicies.Add("Graphic", index++);
1458 | dataIndicies.Add("ClassFlag", index++);
1459 | dataIndicies.Add("ClassInfo", index++);
1460 | dataIndicies.Add("InferiorQualityType", index++);
1461 | dataIndicies.Add("SuperiorQualityType", index++);
1462 | dataIndicies.Add("CharmData", index++);
1463 | dataIndicies.Add("SpellId", index++);
1464 | dataIndicies.Add("MonsterId", index++);
1465 | dataIndicies.Add("MagicPrefix", index++);
1466 | dataIndicies.Add("MagicSuffix", index++);
1467 | dataIndicies.Add("PrefixNameId", index++);
1468 | dataIndicies.Add("SuffixNameId", index++);
1469 | dataIndicies.Add("PrefixFlag0", index++);
1470 | dataIndicies.Add("Prefix0", index++);
1471 | dataIndicies.Add("SuffixFlag0", index++);
1472 | dataIndicies.Add("Suffix0", index++);
1473 | dataIndicies.Add("PrefixFlag1", index++);
1474 | dataIndicies.Add("Prefix1", index++);
1475 | dataIndicies.Add("SuffixFlag1", index++);
1476 | dataIndicies.Add("Suffix1", index++);
1477 | dataIndicies.Add("PrefixFlag2", index++);
1478 | dataIndicies.Add("Prefix2", index++);
1479 | dataIndicies.Add("SuffixFlag2", index++);
1480 | dataIndicies.Add("Suffix2", index++);
1481 | dataIndicies.Add("UniqueSetId", index++);
1482 | dataIndicies.Add("RunewordId", index++);
1483 | dataIndicies.Add("PersonalizedName", index++);
1484 |
1485 | // Extended data
1486 | dataIndicies.Add("RandomFlag", index++);
1487 | dataIndicies.Add("Unknown8", index++);
1488 | dataIndicies.Add("Unknown9", index++);
1489 |
1490 | // Extended specific data
1491 | dataIndicies.Add("Defense", index++);
1492 | dataIndicies.Add("MaxDurability", index++);
1493 | dataIndicies.Add("Durability", index++);
1494 | dataIndicies.Add("Quantity", index++);
1495 | dataIndicies.Add("SocketCount", index++);
1496 |
1497 |
1498 |
1499 | dataIndicies.Add("NumberOfSetProperties", index++);
1500 |
1501 | // Properties are managed in lists
1502 |
1503 | // Very last data
1504 | dataIndicies.Add("LAST", int.MaxValue);
1505 | }
1506 |
1507 | public override string ToString()
1508 | {
1509 | StringBuilder sb = new StringBuilder();
1510 |
1511 | sb.Append(String.Format("{0}", ItemDefs.GetItemDescription(ItemCode)));
1512 |
1513 | if (sockets.Count > 0)
1514 | {
1515 | sb.Append(" (");
1516 | for (int i = 0; i < sockets.Count; i++)
1517 | {
1518 | sb.Append(ItemDefs.GetItemDescription(sockets[i].ItemCode));
1519 |
1520 | if (i < sockets.Count - 1)
1521 | {
1522 | sb.Append(", ");
1523 | }
1524 | }
1525 | sb.Append(")");
1526 | }
1527 |
1528 | return sb.ToString();
1529 | }
1530 |
1531 | #region INotifyPropertyChanged Members
1532 |
1533 | public event PropertyChangedEventHandler PropertyChanged;
1534 |
1535 | private void OnPropertyChange(string propertyName)
1536 | {
1537 | if (PropertyChanged != null)
1538 | {
1539 | PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
1540 | }
1541 | }
1542 |
1543 | #endregion
1544 |
1545 | public object Clone()
1546 | {
1547 | return this.MemberwiseClone();
1548 | }
1549 | }
1550 | }
1551 |
--------------------------------------------------------------------------------