├── .gitignore ├── ItemIDs.txt ├── LICENSE ├── Project ├── Icons │ ├── IconAmulet.png │ ├── IconBeak.png │ ├── IconBlock.png │ ├── IconBoots.png │ ├── IconCandle.png │ ├── IconChestArmor.png │ ├── IconCoin.png │ ├── IconConsumable.png │ ├── IconGloves.png │ ├── IconItems.png │ ├── IconLamp.png │ ├── IconLeftovers.png │ ├── IconManaCube.png │ ├── IconPainting.png │ ├── IconPet.png │ ├── IconPetFood.png │ ├── IconPlatinumCoin.png │ ├── IconQuestItem.png │ ├── IconRecipe.png │ ├── IconRing.png │ ├── IconShoulderArmor.png │ ├── IconTransportation.png │ ├── IconVase.png │ ├── IconWeapon.png │ └── ItemIcon.png ├── icon.ico ├── icon.png ├── stats.ntl3fty.txt └── x2048.png ├── README.md ├── References ├── SQLite.Interop.dll ├── System.Data.SQLite.dll ├── System.Data.SQLite.dll.NET40.2.old ├── System.Data.SQLite.dll.NET40.old ├── app.config └── zlib.net.dll ├── Source ├── Character │ ├── Character.cs │ ├── ChineseRemainder.cs │ ├── Constants.cs │ ├── ICharacterData.cs │ ├── Inventory.cs │ ├── Item.cs │ ├── ItemAttribute.cs │ ├── NameGenerator.cs │ ├── Slot.cs │ └── World.cs ├── CharacterEditor.csproj ├── CharacterEditor.sln ├── Database.cs ├── DirtyWatcher.cs ├── Forms │ ├── Editor.Character.cs │ ├── Editor.Data.cs │ ├── Editor.Designer.cs │ ├── Editor.Equipment.cs │ ├── Editor.Inventory.cs │ ├── Editor.cs │ ├── Editor.resx │ ├── ExceptionDialog.Designer.cs │ ├── ExceptionDialog.cs │ ├── ExceptionDialog.resx │ ├── FormItemStats.Designer.cs │ ├── FormItemStats.cs │ ├── FormItemStats.resx │ ├── LoadCharacterDialog.Designer.cs │ ├── LoadCharacterDialog.cs │ ├── LoadCharacterDialog.resx │ └── SafeNumericUpDown.cs ├── Program.cs ├── Properties │ ├── AssemblyInfo.cs │ ├── Resources.Designer.cs │ └── Resources.resx ├── Resources │ └── x2048.png ├── Utility.cs ├── app.config └── icon.ico ├── TODO.txt └── characterformat.txt /.gitignore: -------------------------------------------------------------------------------- 1 | # Build Folders (you can keep bin if you'd like, to store dlls and pdbs) 2 | [Bb]in/ 3 | [Oo]bj/ 4 | 5 | # mstest test results 6 | TestResults 7 | 8 | ## Ignore Visual Studio temporary files, build results, and 9 | ## files generated by popular Visual Studio add-ons. 10 | 11 | # User-specific files 12 | *.suo 13 | *.user 14 | *.sln.docstates 15 | 16 | # Build results 17 | [Dd]ebug/ 18 | [Rr]elease/ 19 | x64/ 20 | *_i.c 21 | *_p.c 22 | *.ilk 23 | *.meta 24 | *.obj 25 | *.pch 26 | *.pdb 27 | *.pgc 28 | *.pgd 29 | *.rsp 30 | *.sbr 31 | *.tlb 32 | *.tli 33 | *.tlh 34 | *.tmp 35 | *.log 36 | *.vspscc 37 | *.vssscc 38 | .builds 39 | 40 | # Visual C++ cache files 41 | ipch/ 42 | *.aps 43 | *.ncb 44 | *.opensdf 45 | *.sdf 46 | 47 | # Visual Studio profiler 48 | *.psess 49 | *.vsp 50 | *.vspx 51 | 52 | # Guidance Automation Toolkit 53 | *.gpState 54 | 55 | # ReSharper is a .NET coding add-in 56 | _ReSharper* 57 | 58 | # NCrunch 59 | *.ncrunch* 60 | .*crunch*.local.xml 61 | 62 | # Installshield output folder 63 | [Ee]xpress 64 | 65 | # DocProject is a documentation generator add-in 66 | DocProject/buildhelp/ 67 | DocProject/Help/*.HxT 68 | DocProject/Help/*.HxC 69 | DocProject/Help/*.hhc 70 | DocProject/Help/*.hhk 71 | DocProject/Help/*.hhp 72 | DocProject/Help/Html2 73 | DocProject/Help/html 74 | 75 | # Click-Once directory 76 | publish 77 | 78 | # Publish Web Output 79 | *.Publish.xml 80 | 81 | # NuGet Packages Directory 82 | packages 83 | 84 | # Windows Azure Build Output 85 | csx 86 | *.build.csdef 87 | 88 | # Windows Store app package directory 89 | AppPackages/ 90 | 91 | # Others 92 | [Bb]in 93 | [Oo]bj 94 | sql 95 | TestResults 96 | [Tt]est[Rr]esult* 97 | *.Cache 98 | ClientBin 99 | [Ss]tyle[Cc]op.* 100 | ~$* 101 | *.dbmdl 102 | Generated_Code #added for RIA/Silverlight projects 103 | 104 | # Backup & report files from converting an old project file to a newer 105 | # Visual Studio version. Backup files are not needed, because we have git ;-) 106 | _UpgradeReport_Files/ 107 | Backup*/ 108 | UpgradeLog*.XML 109 | -------------------------------------------------------------------------------- /ItemIDs.txt: -------------------------------------------------------------------------------- 1 | - Material sometimes denotes a " of *" on items - 2 | Material 3 | 00 None 4 | 01 Iron 5 | 02 Wood 6 | 03 None 7 | 04 None 8 | 05 Obsidian 9 | 06 None 10 | 07 Bone 11 | 08 None 12 | 09 None 13 | 0A Copper 14 | 0B Gold 15 | 0C Silver 16 | 0D Emerald 17 | 0E Sapphire 18 | 0F Ruby 19 | 10 Diamond 20 | 11 Sandstone 21 | 12 Saurian 22 | 13 Parrot 23 | 14 Mammoth 24 | 15 Plant 25 | 16 Ice 26 | 17 Licht 27 | 18 Glass 28 | 19 Silk 29 | 1A Linen 30 | 1B Cotton 31 | 32 | Item Flags 33 | 01 Adapted 34 | 35 | Unknown [00] 36 | Unknown 37 | 38 | Consumables [01] 39 | Modifiers 40 | 00 None 41 | 00 Cookie 42 | 01 Life Potion 43 | 02 Cactus Potion 44 | 03 Mana Potion 45 | 04 Ginseng Soup 46 | 05 Snowberry Mash 47 | 06 Mushroom Spit 48 | 07 Bomb 49 | 08 Pineapple Slice 50 | 09 Pumpkin Muffin 51 | 52 | Recipes [02] 53 | Modifiers 54 | 00 None 55 | Unknown 56 | 57 | Weapons [03] 58 | Modifiers 59 | 00 None 60 | 01 Plain 61 | 02 Battered 62 | 03 Artless 63 | 04 Unwieldy 64 | 05 Used 65 | 06 Dusty 66 | 07 Scratched 67 | 08 Worn 68 | 09 Common 69 | 0A Shabby 70 | 00 Sword 71 | 01 Axe 72 | 02 Mace 73 | 03 Dagger 74 | 04 Fist 75 | 05 Longsword 76 | 06 Bow 77 | 07 Crossbow 78 | 08 Boomarang 79 | 09 Arrow 80 | 0A Staff 81 | 0B Wand 82 | 0C Bracelet 83 | 0D Shield 84 | 0E Arrows 85 | 0F Greatsword 86 | 10 Greataxe 87 | 11 Greatmace 88 | 12 (Rake) 89 | 13 (Pickaxe) 90 | 14 Torch 91 | 92 | Chest Armor [04] 93 | Modifiers 94 | 00 None 95 | 01 Polished 96 | 02 Extraordinary 97 | 03 Exquisite 98 | 04 Superb 99 | 05 Unique 100 | 06 Handsome 101 | 07 Grand 102 | 08 Magic 103 | 09 Decorated 104 | 0A Exceptional 105 | 00 Chest 106 | 107 | Gloves [05] 108 | Modifiers 109 | 00 None 110 | 01 Polished 111 | 02 Extraordinary 112 | 03 Exquisite 113 | 04 Superb 114 | 05 Unique 115 | 06 Handsome 116 | 07 Grand 117 | 08 Magic 118 | 09 Decorated 119 | 0A Exceptional 120 | 00 Gloves 121 | 122 | Boots [06] 123 | Modifiers 124 | 00 None 125 | 01 Polished 126 | 02 Extraordinary 127 | 03 Exquisite 128 | 04 Superb 129 | 05 Unique 130 | 06 Handsome 131 | 07 Grand 132 | 08 Magic 133 | 09 Decorated 134 | 0A Exceptional 135 | 00 Boots 136 | 137 | Shoulder Armors [07] 138 | Modifiers 139 | 00 None 140 | 01 Polished 141 | 02 Extraordinary 142 | 03 Exquisite 143 | 04 Superb 144 | 05 Unique 145 | 06 Handsome 146 | 07 Grand 147 | 08 Magic 148 | 09 Decorated 149 | 0A Exceptional 150 | Materials 151 | 19 Mage 152 | 1A Ranger 153 | 1B Rogue 154 | 00 Shoulder Armor 155 | 156 | Amulets [08] 157 | Modifiers 158 | 00 None 159 | 01 Polished 160 | 02 Extraordinary 161 | 03 Exquisite 162 | 04 Superb 163 | 05 Unique 164 | 06 Handsome 165 | 07 Grand 166 | 08 Magic 167 | 09 Decorated 168 | 0A Exceptional 169 | 00 Amulet 170 | 171 | Rings [09] 172 | Modifiers 173 | 00 None 174 | 01 Polished 175 | 02 Extraordinary 176 | 03 Exquisite 177 | 04 Superb 178 | 05 Unique 179 | 06 Handsome 180 | 07 Grand 181 | 08 Magic 182 | 09 Decorated 183 | 0A Exceptional 184 | 00 Ring 185 | 186 | Blocks [0A] 187 | Modifiers 188 | 00 None 189 | 01 Polished 190 | 02 Extraordinary 191 | 03 Exquisite 192 | 04 Superb 193 | 05 Unique 194 | 06 Handsome 195 | 07 Grand 196 | 08 Magic 197 | 09 Decorated 198 | 0A Exceptional 199 | 00 Block 200 | 201 | Items [0B] 202 | Modifiers 203 | 00 None 204 | 01 Polished 205 | 02 Extraordinary 206 | 03 Exquisite 207 | 04 Superb 208 | 05 Unique 209 | 06 Handsome 210 | 07 Grand 211 | 08 Magic 212 | 09 Decorated 213 | 0A Exceptional 214 | 00 Nugget 215 | 01 Log 216 | 02 Feather 217 | 03 Horn 218 | 04 Claw 219 | 05 Fiber 220 | 06 Cobweb 221 | 07 Hair 222 | 08 Crystal 223 | 09 Yarn 224 | 0A Cube 225 | 0B Capsule 226 | 0C Flask 227 | 0D Orb 228 | 0E Spirit 229 | 0F Mushroom 230 | 10 Pumpkin 231 | 11 Pineapple 232 | 12 Radish Slice 233 | 13 Shimmer Mushroom 234 | 14 Ginseg Root 235 | 15 Onion Slice 236 | 16 Heartflower 237 | 17 Prickly Pear 238 | 18 Iceflower 239 | 19 Soulflower 240 | 1A Water Flask 241 | 1B Snowberry 242 | 243 | Coins [0C] 244 | Modifiers 245 | 00 None 246 | 01 Polished 247 | 02 Extraordinary 248 | 03 Exquisite 249 | 04 Superb 250 | 05 Unique 251 | 06 Handsome 252 | 07 Grand 253 | 08 Magic 254 | 09 Decorated 255 | 0A Exceptional 256 | 00 Coin 257 | 258 | Platinum Coin [0D] 259 | Modifiers 260 | 00 None 261 | 01 Polished 262 | 02 Extraordinary 263 | 03 Exquisite 264 | 04 Superb 265 | 05 Unique 266 | 06 Handsome 267 | 07 Grand 268 | 08 Magic 269 | 09 Decorated 270 | 0A Exceptional 271 | 00 Platinum Coin 272 | 273 | Leftovers [0E] 274 | Modifiers 275 | 00 None 276 | 00 Leftovers 277 | 278 | Beak [0F] 279 | Modifiers 280 | 00 None 281 | 01 Polished 282 | 02 Extraordinary 283 | 03 Exquisite 284 | 04 Superb 285 | 05 Unique 286 | 06 Handsome 287 | 07 Grand 288 | 08 Magic 289 | 09 Decorated 290 | 0A Exceptional 291 | 00 Beak 292 | 293 | Painting [10] 294 | Modifiers 295 | 00 None 296 | 01 Polished 297 | 02 Extraordinary 298 | 03 Exquisite 299 | 04 Superb 300 | 05 Unique 301 | 06 Handsome 302 | 07 Grand 303 | 08 Magic 304 | 09 Decorated 305 | 0A Exceptional 306 | 00 Painting 307 | 308 | Vase [11] 309 | Modifiers 310 | 00 None 311 | 01 Polished 312 | 02 Extraordinary 313 | 03 Exquisite 314 | 04 Superb 315 | 05 Unique 316 | 06 Handsome 317 | 07 Grand 318 | 08 Magic 319 | 09 Decorated 320 | 0A Exceptional 321 | 00 Vase 322 | 323 | Candle [12] 324 | Modifiers 325 | 00 None 326 | 01 Fancy 327 | 02 3 fancy 5 me 328 | 00 Candle 329 | 01 Haunted Candle 330 | 331 | Pets [13] 332 | Look elsewhere 333 | 334 | Pet Food [14] 335 | Modifiers 336 | 00 None 337 | 01 Polished 338 | 02 Extraordinary 339 | 03 Exquisite 340 | 04 Superb 341 | 05 Unique 342 | 06 Handsome 343 | 07 Grand 344 | 08 Magic 345 | 09 Decorated 346 | 0A Exceptional 347 | [ Not gonna bother mentioning all the non-existant IDs ] 348 | 13 Bubble gum 349 | 17 Chocolate cupcake 350 | 19 Cinnamon role (sic) 351 | 1A Waffle 352 | 1B Croissant 353 | 1E Candy 354 | 21 Pumpkin mash 355 | 22 Cotton candy 356 | 23 Carrot 357 | 24 Blackberry marmalade 358 | 25 Green jelly 359 | 26 Pink Jelly 360 | 27 Yellow Jelly 361 | 28 Blue jelly 362 | 32 Banana split 363 | 35 Popcorn 364 | 37 Licorice candy 365 | 38 Cereal bar 366 | 39 Salted caramel 367 | 3A Ginger tartlet 368 | 3B Mango juice 369 | 3C Fruit basket 370 | 3D Melon ice cream 371 | 3E Bloodorange juice 372 | 3F Milk chocolate bar 373 | 40 Mint chocolate bar 374 | 41 White chocolate bar 375 | 42 Caramel chocolate bar 376 | 43 Chocolate cookie 377 | 4A Sugar candy 378 | 4B Apple ring 379 | 56 Water ice 380 | 57 Chocolate donut 381 | 58 Pancakes 382 | 5A Strawberry cake 383 | 5B Chocolate cake 384 | 5C Lollipop 385 | 5D Softice 386 | 62 Candied apple 387 | 63 Date cookie 388 | 66 Bread 389 | 67 Curry 390 | 68 Lolly 391 | 69 Lemon tart 392 | 6A strawberry cocktail 393 | 394 | [ I have no clue what's wrong here ] 395 | 396 | Quest Items [15] 397 | Modifiers 398 | 00 Eric's 399 | 01 Arweya's 400 | 02 Derek's 401 | 03 Sarah's 402 | 04 Grazic's 403 | 05 Kurra's 404 | 06 Krono's 405 | 07 Chorux's 406 | 08 Zirya's 407 | 09 Torlox's 408 | 0A Mumpie's 409 | 0B Uzku's 410 | 0C Uzka's 411 | 0D Qaurik's 412 | 0E Quaria's 413 | 0F Chulu's 414 | 10 Xula's 415 | 00 Amulet (Gold) 416 | 01 Amulet (Sapphire) 417 | 02 Jewel Case 418 | 03 Key 419 | 04 Medicine 420 | 05 Antivenom 421 | 06 Band Aid 422 | 07 Crutch 423 | 08 Bandage 424 | 09 Salve 425 | 426 | Unused [16] 427 | 00 Unused 428 | 429 | Transporation [17] 430 | Modifiers 431 | 00 None 432 | 01 Polished 433 | 02 Extraordinary 434 | 03 Exquisite 435 | 04 Superb 436 | 05 Unique 437 | 06 Handsome 438 | 07 Grand 439 | 08 Magic 440 | 09 Decorated 441 | 0A Exceptional 442 | 00 Hang Glider 443 | 01 Boat 444 | 445 | Lamps [18] 446 | Modifiers 447 | 00 None 448 | 01 Polished 449 | 02 Extraordinary 450 | 03 Exquisite 451 | 04 Superb 452 | 05 Unique 453 | 06 Handsome 454 | 07 Grand 455 | 08 Magic 456 | 09 Decorated 457 | 0A Exceptional 458 | 00 Lamp 459 | 460 | Mana Cube [19] 461 | Modifiers 462 | 00 None 463 | 01 Battle-tested 464 | 02 Extraordinary 465 | 03 Exquisite 466 | 04 Superb 467 | 05 Unique 468 | 06 Handsome 469 | 07 Grand 470 | 08 Magic 471 | 09 Decorated 472 | 0A Exceptional 473 | 00 Mana Cube 474 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2013 Zachary Reedy 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in 13 | all copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 21 | THE SOFTWARE. 22 | -------------------------------------------------------------------------------- /Project/Icons/IconAmulet.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DatZach/CharacterEditor/974b2b9e9bd6756eb68b2a8ba349eac97ff67354/Project/Icons/IconAmulet.png -------------------------------------------------------------------------------- /Project/Icons/IconBeak.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DatZach/CharacterEditor/974b2b9e9bd6756eb68b2a8ba349eac97ff67354/Project/Icons/IconBeak.png -------------------------------------------------------------------------------- /Project/Icons/IconBlock.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DatZach/CharacterEditor/974b2b9e9bd6756eb68b2a8ba349eac97ff67354/Project/Icons/IconBlock.png -------------------------------------------------------------------------------- /Project/Icons/IconBoots.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DatZach/CharacterEditor/974b2b9e9bd6756eb68b2a8ba349eac97ff67354/Project/Icons/IconBoots.png -------------------------------------------------------------------------------- /Project/Icons/IconCandle.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DatZach/CharacterEditor/974b2b9e9bd6756eb68b2a8ba349eac97ff67354/Project/Icons/IconCandle.png -------------------------------------------------------------------------------- /Project/Icons/IconChestArmor.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DatZach/CharacterEditor/974b2b9e9bd6756eb68b2a8ba349eac97ff67354/Project/Icons/IconChestArmor.png -------------------------------------------------------------------------------- /Project/Icons/IconCoin.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DatZach/CharacterEditor/974b2b9e9bd6756eb68b2a8ba349eac97ff67354/Project/Icons/IconCoin.png -------------------------------------------------------------------------------- /Project/Icons/IconConsumable.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DatZach/CharacterEditor/974b2b9e9bd6756eb68b2a8ba349eac97ff67354/Project/Icons/IconConsumable.png -------------------------------------------------------------------------------- /Project/Icons/IconGloves.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DatZach/CharacterEditor/974b2b9e9bd6756eb68b2a8ba349eac97ff67354/Project/Icons/IconGloves.png -------------------------------------------------------------------------------- /Project/Icons/IconItems.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DatZach/CharacterEditor/974b2b9e9bd6756eb68b2a8ba349eac97ff67354/Project/Icons/IconItems.png -------------------------------------------------------------------------------- /Project/Icons/IconLamp.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DatZach/CharacterEditor/974b2b9e9bd6756eb68b2a8ba349eac97ff67354/Project/Icons/IconLamp.png -------------------------------------------------------------------------------- /Project/Icons/IconLeftovers.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DatZach/CharacterEditor/974b2b9e9bd6756eb68b2a8ba349eac97ff67354/Project/Icons/IconLeftovers.png -------------------------------------------------------------------------------- /Project/Icons/IconManaCube.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DatZach/CharacterEditor/974b2b9e9bd6756eb68b2a8ba349eac97ff67354/Project/Icons/IconManaCube.png -------------------------------------------------------------------------------- /Project/Icons/IconPainting.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DatZach/CharacterEditor/974b2b9e9bd6756eb68b2a8ba349eac97ff67354/Project/Icons/IconPainting.png -------------------------------------------------------------------------------- /Project/Icons/IconPet.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DatZach/CharacterEditor/974b2b9e9bd6756eb68b2a8ba349eac97ff67354/Project/Icons/IconPet.png -------------------------------------------------------------------------------- /Project/Icons/IconPetFood.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DatZach/CharacterEditor/974b2b9e9bd6756eb68b2a8ba349eac97ff67354/Project/Icons/IconPetFood.png -------------------------------------------------------------------------------- /Project/Icons/IconPlatinumCoin.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DatZach/CharacterEditor/974b2b9e9bd6756eb68b2a8ba349eac97ff67354/Project/Icons/IconPlatinumCoin.png -------------------------------------------------------------------------------- /Project/Icons/IconQuestItem.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DatZach/CharacterEditor/974b2b9e9bd6756eb68b2a8ba349eac97ff67354/Project/Icons/IconQuestItem.png -------------------------------------------------------------------------------- /Project/Icons/IconRecipe.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DatZach/CharacterEditor/974b2b9e9bd6756eb68b2a8ba349eac97ff67354/Project/Icons/IconRecipe.png -------------------------------------------------------------------------------- /Project/Icons/IconRing.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DatZach/CharacterEditor/974b2b9e9bd6756eb68b2a8ba349eac97ff67354/Project/Icons/IconRing.png -------------------------------------------------------------------------------- /Project/Icons/IconShoulderArmor.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DatZach/CharacterEditor/974b2b9e9bd6756eb68b2a8ba349eac97ff67354/Project/Icons/IconShoulderArmor.png -------------------------------------------------------------------------------- /Project/Icons/IconTransportation.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DatZach/CharacterEditor/974b2b9e9bd6756eb68b2a8ba349eac97ff67354/Project/Icons/IconTransportation.png -------------------------------------------------------------------------------- /Project/Icons/IconVase.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DatZach/CharacterEditor/974b2b9e9bd6756eb68b2a8ba349eac97ff67354/Project/Icons/IconVase.png -------------------------------------------------------------------------------- /Project/Icons/IconWeapon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DatZach/CharacterEditor/974b2b9e9bd6756eb68b2a8ba349eac97ff67354/Project/Icons/IconWeapon.png -------------------------------------------------------------------------------- /Project/Icons/ItemIcon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DatZach/CharacterEditor/974b2b9e9bd6756eb68b2a8ba349eac97ff67354/Project/Icons/ItemIcon.png -------------------------------------------------------------------------------- /Project/icon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DatZach/CharacterEditor/974b2b9e9bd6756eb68b2a8ba349eac97ff67354/Project/icon.ico -------------------------------------------------------------------------------- /Project/icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DatZach/CharacterEditor/974b2b9e9bd6756eb68b2a8ba349eac97ff67354/Project/icon.png -------------------------------------------------------------------------------- /Project/stats.ntl3fty.txt: -------------------------------------------------------------------------------- 1 | public double Armor 2 | { 3 | get 4 | { 5 | if (!(Type == ItemType.Armor || Type == ItemType.Shoulder || Type == ItemType.Hand || Type == ItemType.Feet)) 6 | return 0; 7 | 8 | double typeBonus = Type == ItemType.Armor ? 1.0 : 0.5; 9 | 10 | double materialBonus = 0; 11 | switch (Material) 12 | { 13 | case 23: 14 | case 25: 15 | materialBonus = 0.075; 16 | break; 17 | case 19: 18 | case 26: 19 | case 27: 20 | materialBonus = 0.85; // might need to expand the precision here 21 | break; 22 | case 18: 23 | materialBonus = 0.80; // might need to expand the precision here 24 | break; 25 | } 26 | 27 | double effect = CalculateLevelEffectValue(Level + UpgradeList.Used / 10.0, Rarity); 28 | return effect * typeBonus * materialBonus; 29 | } 30 | } 31 | 32 | public double Critical 33 | { 34 | get 35 | { 36 | if (!(Type == ItemType.Amulet || Type == ItemType.Ring || Type == ItemType.Weapon || 37 | Type == ItemType.Armor || Type == ItemType.Shoulder || Type == ItemType.Hand || 38 | Type == ItemType.Feet)) 39 | { 40 | return 0; 41 | } 42 | 43 | double typeBonus = 0.05; 44 | if (Type == ItemType.Weapon && (Subtype == 15 || Subtype == 16 || Subtype == 17 || 45 | Subtype == 5 || Subtype == 10 || Subtype == 11 || 46 | Subtype == 18 || Subtype == 8 || Subtype == 6 || Subtype == 7) 47 | || Type == ItemType.Armor) 48 | { 49 | typeBonus = 0.1; 50 | } 51 | 52 | double modifierBonus = 1.0 - ((Modifier % 21) / 20.0); 53 | if (Material == 11) 54 | { 55 | modifierBonus += 1.0; 56 | } 57 | 58 | double effect = CalculateLevelEffectPercent(Level, Rarity); 59 | double result = effect * typeBonus * modifierBonus; 60 | 61 | return Math.Abs(result) < 0.001 ? 0 : result; 62 | } 63 | } 64 | 65 | public double Life 66 | { 67 | get 68 | { 69 | if (!(Type == ItemType.Weapon || Type == ItemType.Armor || 70 | Type == ItemType.Shoulder || Type == ItemType.Hand || Type == ItemType.Feet)) 71 | { 72 | return 0; 73 | } 74 | 75 | double typeBonus = Type == ItemType.Armor ? 1.0 : 0.5; 76 | double modifierBonus = (1.0 - ((Modifier % 21) / 20.0)) + 1.0; 77 | 78 | switch (Material) 79 | { 80 | case 1: 81 | modifierBonus += 1.0; 82 | break; 83 | case 26: 84 | modifierBonus += 0.5; 85 | break; 86 | case 27: 87 | modifierBonus += 0.75; 88 | break; 89 | } 90 | 91 | double effect = CalculateLevelEffectValue(Level + UpgradeList.Used / 10.0, Rarity); 92 | return effect * 5.0 * typeBonus * modifierBonus; 93 | } 94 | } 95 | 96 | public double Regeneration 97 | { 98 | get 99 | { 100 | if (!(Type == ItemType.Weapon || Type == ItemType.Armor || 101 | Type == ItemType.Shoulder || Type == ItemType.Hand || Type == ItemType.Feet)) 102 | { 103 | return 0; 104 | } 105 | 106 | double typeBonus = Type == ItemType.Armor ? 0.2 : 0.1; 107 | double modifierBonus = (Modifier % 21) / 20.0; 108 | 109 | switch (Material) 110 | { 111 | case 26: 112 | modifierBonus += 0.5; 113 | break; 114 | case 27: 115 | modifierBonus += 1.0; 116 | break; 117 | } 118 | 119 | double effect = CalculateLevelEffectValue(Level + UpgradeList.Used / 10.0, Rarity); 120 | return effect * typeBonus * modifierBonus; 121 | } 122 | } 123 | 124 | public double Resistance 125 | { 126 | get 127 | { 128 | if (!(Type == ItemType.Armor || Type == ItemType.Shoulder || Type == ItemType.Hand || Type == ItemType.Feet)) 129 | return 0; 130 | 131 | double typeBonus = Type == ItemType.Armor ? 1.0 : 0.5; 132 | 133 | double materialBonus = 0; 134 | switch (Material) 135 | { 136 | case 1: 137 | case 19: 138 | materialBonus = 0.85; 139 | break; 140 | case 26: 141 | case 27: 142 | materialBonus = 0.75; 143 | break; 144 | } 145 | 146 | double effect = CalculateLevelEffectValue(Level + UpgradeList.Used / 10.0, Rarity); 147 | return effect * typeBonus * materialBonus; 148 | } 149 | } 150 | 151 | public double Tempo 152 | { 153 | get 154 | { 155 | if (!(Type == ItemType.Amulet || Type == ItemType.Ring || Type == ItemType.Weapon || 156 | Type == ItemType.Armor || Type == ItemType.Shoulder || Type == ItemType.Hand || 157 | Type == ItemType.Feet)) 158 | { 159 | return 0; 160 | } 161 | 162 | double typeBonus = 0.1; 163 | if (Type == ItemType.Weapon && (Subtype == 15 || Subtype == 16 || Subtype == 17 || 164 | Subtype == 5 || Subtype == 10 || Subtype == 11 || 165 | Subtype == 18 || Subtype == 8 || Subtype == 6 || Subtype == 7) 166 | || Type == ItemType.Armor) 167 | { 168 | typeBonus = 0.2; 169 | } 170 | 171 | double modifierBonus = (Modifier % 21) / 20.0; 172 | if (Material == 12) 173 | { 174 | modifierBonus += 1.0; 175 | } 176 | 177 | double effect = CalculateLevelEffectPercent(Level, Rarity); 178 | double result = effect * typeBonus * modifierBonus; 179 | 180 | return Math.Abs(result) < 0.001 ? 0 : result; 181 | 182 | } 183 | } 184 | 185 | public double Damage 186 | { 187 | get 188 | { 189 | if (Type != ItemType.Weapon) 190 | return 0; 191 | 192 | double damageBonus = 4.0; 193 | switch (Subtype) 194 | { 195 | case 3: 196 | case 4: 197 | damageBonus = 2.0; 198 | break; 199 | case 5: 200 | damageBonus = 4.0; 201 | break; 202 | case 13: 203 | damageBonus = 2.0; 204 | break; 205 | case 15: 206 | case 16: 207 | case 17: 208 | case 10: 209 | case 11: 210 | case 18: 211 | case 8: 212 | case 6: 213 | case 7: 214 | damageBonus = 8.0; 215 | break; 216 | } 217 | 218 | double effect = CalculateLevelEffectValue(Level + UpgradeList.Used / 10.0, Rarity); 219 | return effect * damageBonus; 220 | } 221 | } 222 | 223 | private static double CalculateLevelEffectValue(double level, int rarity) 224 | { 225 | double a = 3.0 * (1.0 - (1.0 / (1.0 + ((level - 1.0) / 20.0)))); 226 | double b = rarity / 4.0; 227 | double result = Math.Pow(2, a) * Math.Pow(2, b); 228 | 229 | return result; 230 | } 231 | 232 | private static double CalculateLevelEffectPercent(double level, int rarity) 233 | { 234 | double a = 3.0 * (1.0 - (1.0 / (1.0 + ((level - 1.0) / 20.0)))); 235 | double b = rarity / 4.0; 236 | double c = 3.0; 237 | double result = Math.Pow(2, a) * Math.Pow(2, b) / Math.Pow(2, c); 238 | 239 | return result; 240 | } -------------------------------------------------------------------------------- /Project/x2048.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DatZach/CharacterEditor/974b2b9e9bd6756eb68b2a8ba349eac97ff67354/Project/x2048.png -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | CharacterEditor 2 | =============== 3 | 4 | Cube World Character Editor -------------------------------------------------------------------------------- /References/SQLite.Interop.dll: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DatZach/CharacterEditor/974b2b9e9bd6756eb68b2a8ba349eac97ff67354/References/SQLite.Interop.dll -------------------------------------------------------------------------------- /References/System.Data.SQLite.dll: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DatZach/CharacterEditor/974b2b9e9bd6756eb68b2a8ba349eac97ff67354/References/System.Data.SQLite.dll -------------------------------------------------------------------------------- /References/System.Data.SQLite.dll.NET40.2.old: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DatZach/CharacterEditor/974b2b9e9bd6756eb68b2a8ba349eac97ff67354/References/System.Data.SQLite.dll.NET40.2.old -------------------------------------------------------------------------------- /References/System.Data.SQLite.dll.NET40.old: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DatZach/CharacterEditor/974b2b9e9bd6756eb68b2a8ba349eac97ff67354/References/System.Data.SQLite.dll.NET40.old -------------------------------------------------------------------------------- /References/app.config: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /References/zlib.net.dll: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DatZach/CharacterEditor/974b2b9e9bd6756eb68b2a8ba349eac97ff67354/References/zlib.net.dll -------------------------------------------------------------------------------- /Source/Character/Character.cs: -------------------------------------------------------------------------------- 1 | using System.Collections.Generic; 2 | using System.Drawing; 3 | using System.IO; 4 | using System.Linq; 5 | 6 | namespace CharacterEditor.Character 7 | { 8 | public class Character 9 | { 10 | public const int EquipmentCount = 13; 11 | public const int InventoryCount = 4; 12 | public const int SkillCount = 11; 13 | 14 | public enum ClassType : byte 15 | { 16 | None, 17 | Warrior, 18 | Ranger, 19 | Mage, 20 | Rogue 21 | } 22 | 23 | public int DatabaseIndex { get; private set; } 24 | public int EntityId { get; private set; } 25 | public long PositionX { get; private set; } 26 | public long PositionY { get; private set; } 27 | public long PositionZ { get; private set; } 28 | public float Pitch { get; private set; } 29 | public float Roll { get; private set; } 30 | public float Yaw { get; private set; } 31 | 32 | public float Health; 33 | public int Experience; 34 | public int Level; 35 | public ClassType Class; 36 | public byte Specialization; 37 | 38 | private uint unknown1; 39 | private uint unknown2; 40 | 41 | public List Equipment; 42 | 43 | public string Name; 44 | public int Race; 45 | public byte Gender; 46 | public int Face; 47 | public int Hair; 48 | public Color HairColor; 49 | 50 | public List Inventories; 51 | 52 | public int Coins; 53 | public int PlatinumCoins; 54 | 55 | public List CraftingRecipes; 56 | public List Worlds; 57 | public World LastWorld; 58 | 59 | public int ManaCubes; 60 | public int PetMasterSkillLevel; 61 | public int PetRidingSkillLevel; 62 | public int ClimbingSkillLevel; 63 | public int HangGlidingSkillLevel; 64 | public int SwimmingSkillLevel; 65 | public int SailingSkillLevel; 66 | public int TierOneSkillLevel; 67 | public int TierTwoSkillLevel; 68 | public int TierThreeSkillLevel; 69 | private int unknown4; 70 | private int unknown5; 71 | 72 | public Character(int index) 73 | { 74 | DatabaseIndex = index; 75 | 76 | Equipment = new List(); 77 | Inventories = new List(); 78 | CraftingRecipes = new List(); 79 | Worlds = new List(); 80 | } 81 | 82 | public void Load(Database database) 83 | { 84 | byte[] characterData = database.ReadCharacterBlob(DatabaseIndex); 85 | 86 | using (BinaryReader reader = new BinaryReader(new MemoryStream(characterData))) 87 | Read(reader); 88 | } 89 | 90 | public bool Save(Database database) 91 | { 92 | MemoryStream saveDataStream = new MemoryStream(); 93 | 94 | using (BinaryWriter writer = new BinaryWriter(saveDataStream)) 95 | Write(writer); 96 | 97 | return database.WriteCharacterBlob(DatabaseIndex, saveDataStream.ToArray()); 98 | } 99 | 100 | public void Read(BinaryReader reader) 101 | { 102 | EntityId = reader.ReadInt32(); 103 | PositionX = reader.ReadInt64(); 104 | PositionY = reader.ReadInt64(); 105 | PositionZ = reader.ReadInt64(); 106 | Pitch = reader.ReadSingle(); 107 | Roll = reader.ReadSingle(); 108 | Yaw = reader.ReadSingle(); 109 | 110 | Health = reader.ReadSingle(); 111 | Experience = reader.ReadInt32(); 112 | Level = reader.ReadInt32(); 113 | Class = (ClassType)reader.ReadByte(); 114 | Specialization = reader.ReadByte(); 115 | unknown1 = reader.ReadUInt32(); 116 | unknown2 = reader.ReadUInt32(); 117 | 118 | for (int i = 0; i < EquipmentCount; ++i) 119 | { 120 | Item item = new Item(); 121 | item.Read(reader); 122 | 123 | Equipment.Add(item); 124 | } 125 | 126 | Name = reader.ReadLongString(); 127 | Race = reader.ReadInt32(); 128 | Gender = reader.ReadByte(); 129 | reader.Skip(3); 130 | Face = reader.ReadInt32(); 131 | Hair = reader.ReadInt32(); 132 | HairColor = Utility.FromAbgr(reader.ReadInt32()); 133 | 134 | int inventoryCount = reader.ReadInt32(); 135 | for (int i = 0; i < inventoryCount; ++i) 136 | { 137 | Inventory inventory = new Inventory(); 138 | inventory.Read(reader); 139 | 140 | Inventories.Add(inventory); 141 | } 142 | 143 | Coins = reader.ReadInt32(); 144 | PlatinumCoins = reader.ReadInt32(); 145 | 146 | int craftingRecipeCount = reader.ReadInt32(); 147 | for (int i = 0; i < craftingRecipeCount; ++i) 148 | { 149 | Item item = new Item(); 150 | item.Read(reader); 151 | 152 | CraftingRecipes.Add(item); 153 | } 154 | 155 | int worldCount = reader.ReadInt32(); 156 | for (int i = 0; i < worldCount; ++i) 157 | { 158 | World world = new World(); 159 | world.Read(reader); 160 | 161 | Worlds.Add(world); 162 | } 163 | 164 | int lastWorldSeed = reader.ReadInt32(); 165 | string lastWorldName = reader.ReadLongString(); 166 | 167 | LastWorld = Worlds.FirstOrDefault(w => w.Seed == lastWorldSeed && w.Name == lastWorldName) ?? new World { Name = lastWorldName, Seed = lastWorldSeed }; 168 | 169 | ManaCubes = reader.ReadInt32(); 170 | reader.Skip(4); 171 | PetMasterSkillLevel = reader.ReadInt32(); 172 | PetRidingSkillLevel = reader.ReadInt32(); 173 | ClimbingSkillLevel = reader.ReadInt32(); 174 | HangGlidingSkillLevel = reader.ReadInt32(); 175 | SwimmingSkillLevel = reader.ReadInt32(); 176 | SailingSkillLevel = reader.ReadInt32(); 177 | TierOneSkillLevel = reader.ReadInt32(); 178 | TierTwoSkillLevel = reader.ReadInt32(); 179 | TierThreeSkillLevel = reader.ReadInt32(); 180 | unknown4 = reader.ReadInt32(); 181 | unknown5 = reader.ReadInt32(); 182 | } 183 | 184 | public void Write(BinaryWriter writer) 185 | { 186 | writer.Write(EntityId); 187 | writer.Write(PositionX); 188 | writer.Write(PositionY); 189 | writer.Write(PositionZ); 190 | writer.Write(Pitch); 191 | writer.Write(Roll); 192 | writer.Write(Yaw); 193 | 194 | writer.Write(Health); 195 | writer.Write(Experience); 196 | writer.Write(Level); 197 | writer.Write((byte)Class); 198 | writer.Write(Specialization); 199 | writer.Write(unknown1); 200 | writer.Write(unknown2); 201 | 202 | foreach (Item equipment in Equipment) 203 | equipment.Write(writer); 204 | 205 | writer.WriteLongString(Name); 206 | writer.Write(Race); 207 | writer.Write(Gender); 208 | writer.Skip(3); 209 | writer.Write(Face); 210 | writer.Write(Hair); 211 | writer.Write(Utility.ToAbgr(HairColor)); 212 | 213 | writer.Write(InventoryCount); 214 | foreach (Inventory inventory in Inventories) 215 | inventory.Write(writer); 216 | 217 | writer.Write(Coins); 218 | writer.Write(PlatinumCoins); 219 | 220 | writer.Write(CraftingRecipes.Count); 221 | foreach (Item recipe in CraftingRecipes) 222 | recipe.Write(writer); 223 | 224 | writer.Write(Worlds.Count); 225 | foreach (World world in Worlds) 226 | world.Write(writer); 227 | 228 | writer.Write(LastWorld.Seed); 229 | writer.WriteLongString(LastWorld.Name); 230 | 231 | writer.Write(ManaCubes); 232 | writer.Write(SkillCount); 233 | writer.Write(PetMasterSkillLevel); 234 | writer.Write(PetRidingSkillLevel); 235 | writer.Write(ClimbingSkillLevel); 236 | writer.Write(HangGlidingSkillLevel); 237 | writer.Write(SwimmingSkillLevel); 238 | writer.Write(SailingSkillLevel); 239 | writer.Write(TierOneSkillLevel); 240 | writer.Write(TierTwoSkillLevel); 241 | writer.Write(TierThreeSkillLevel); 242 | writer.Write(unknown4); 243 | writer.Write(unknown5); 244 | } 245 | } 246 | } 247 | -------------------------------------------------------------------------------- /Source/Character/ChineseRemainder.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Data; 3 | 4 | namespace CharacterEditor.Character 5 | { 6 | /// 7 | /// Solve Chinese Remainder Problem 8 | /// Original source: http://www.codeproject.com/Articles/29610/Chinese-Remainder-Problem 9 | /// 10 | class ChineseRemainder 11 | { 12 | /// 13 | /// Get Greatest Common Divisor 14 | /// 15 | public static int Gcd(int a, int b) 16 | { 17 | if (a > b) 18 | { 19 | int t = b; 20 | b = a; 21 | a = t; 22 | } 23 | 24 | int r = b % a; 25 | while (r != 0) 26 | { 27 | b = a; 28 | a = r; 29 | r = b % a; 30 | } 31 | 32 | return a; 33 | } 34 | 35 | /// 36 | /// Get Least Common Multiple 37 | /// 38 | public static int Lcm(int a, int b) 39 | { 40 | int gcd = Gcd(a, b); 41 | return a * b / gcd; 42 | } 43 | 44 | /// 45 | /// Solve ax=by+1 46 | /// 47 | public static void Solve(int a, int b, out int x, out int y) 48 | { 49 | if (b == 1) 50 | { 51 | x = 1; 52 | y = a - 1; 53 | } 54 | else if (a == 1) 55 | { 56 | y = 1; 57 | x = b + 1; 58 | } 59 | else if (b > a) 60 | { 61 | int subx; 62 | Solve(a, b - a, out subx, out y); 63 | x = y + subx; 64 | } 65 | else if (a > b) 66 | { 67 | int suby; 68 | Solve(a - b, b, out x, out suby); 69 | y = x + suby; 70 | } 71 | else 72 | throw new DataException(String.Format("The equation {0}x={1}y+1 has no integer solution.", a, b)); 73 | } 74 | 75 | /// 76 | /// Solve ax = by + c 77 | /// 78 | public static void Solve(int a, int b, int c, out int x1, out int y1) 79 | { 80 | /* if 81 | a * x0 = b * y0 + 1 82 | then 83 | x = b * t + c * x0 84 | y = a * t + c * y0 85 | satisfies 86 | a * x = b * y + c 87 | so 88 | x1 = (c * x0) mod b 89 | y1 = (c * y0) mod a 90 | */ 91 | int d = Gcd(a, b); 92 | if (d > 1) 93 | { 94 | if (c % d != 0) 95 | throw new DataException(String.Format("The equation {0}x={1}y+{2} has no integer solution.", a, b, c)); 96 | 97 | a = a / d; 98 | b = b / d; 99 | c = c / d; 100 | } 101 | 102 | int x0, y0; 103 | Solve(a, b, out x0, out y0); 104 | x1 = (c * x0) % b; 105 | y1 = (c * y0) % a; 106 | } 107 | 108 | /// 109 | /// Solve a * x + r1 = b * y + r2 110 | /// 111 | public static void Solve(int a, int b, int r1, int r2, out int x1, out int y1) 112 | { 113 | if (r2 > r1) 114 | Solve(a, b, r2 - r1, out x1, out y1); 115 | else if (r1 > r2) 116 | Solve(b, a, r1 - r2, out y1, out x1); 117 | else 118 | { 119 | x1 = b; 120 | y1 = a; 121 | } 122 | } 123 | 124 | /// 125 | /// Solve a * x + r1 = b * y + r2 = c * z + r3 = n 126 | /// n0 = n mod t 127 | /// 128 | public static void Solve(int a, int b, int c, int r1, 129 | int r2, int r3, out int n0, out int t) 130 | { 131 | int x1, y1; 132 | 133 | Solve(a, b, r1, r2, out x1, out y1); 134 | 135 | // let r4 = a * x1 + r1 = b * y1 + r2 136 | // to satisfy n = a * x + r1 = b * y + r2 137 | // we can see n = a * b * u + r4 138 | 139 | int r4 = a * x1 + r1; 140 | int x2, y2; 141 | 142 | Solve(a * b, c, r4, r3, out x2, out y2); 143 | n0 = c * y2 + r3; 144 | t = Lcm(Lcm(a, b), c); 145 | //n0 = n % t; 146 | } 147 | } 148 | } 149 | -------------------------------------------------------------------------------- /Source/Character/Constants.cs: -------------------------------------------------------------------------------- 1 | namespace CharacterEditor.Character 2 | { 3 | public static class Constants 4 | { 5 | public enum ItemType : byte 6 | { 7 | None, 8 | Consumables, 9 | Recipes, 10 | Weapons, 11 | ChestArmor, 12 | Gloves, 13 | Boots, 14 | ShoulderArmor, 15 | Amulets, 16 | Rings, 17 | Blocks, 18 | Items, 19 | Coins, 20 | PlatinumCoins, 21 | Leftovers, 22 | Beak, 23 | Painting, 24 | Vase, 25 | Candle, 26 | Pets, 27 | PetFood, 28 | QuestItems, 29 | Unused, 30 | Transportation, 31 | Lamps, 32 | ManaCubes 33 | } 34 | 35 | public static readonly string[] ItemTypeNames = new[] 36 | { 37 | "None", // None 38 | "Consumables", 39 | "Recipes", 40 | "Weapons", 41 | "Chest Armor", 42 | "Gloves", 43 | "Boots", 44 | "Shoulder Armor", 45 | "Amulets", 46 | "Rings", 47 | "Blocks", 48 | "Items", 49 | "Coins", 50 | "Platinum Coins", 51 | "Leftovers", 52 | "Beak", 53 | "Painting", 54 | "Vase", 55 | "Candle", 56 | "Pets", 57 | "Pet Food", 58 | "Quest Items", 59 | null, 60 | "Transportation", 61 | "Lamps", 62 | "Mana Cubes" 63 | }; 64 | 65 | public static readonly string[][] ItemModifiers = new [] 66 | { 67 | new [] // Rarity 0 68 | { 69 | "Plain {0}", 70 | "Battered {0}", 71 | "Artless {0}", 72 | "Unwieldy {0}", 73 | "Used {0}", 74 | "Dusty {0}", 75 | "Scratched {0}", 76 | "Worn {0}", 77 | "Common {0}", 78 | "Shabby {0}" 79 | }, 80 | 81 | new [] // Rarity 1 82 | { 83 | "Balanced {0}", 84 | "Battle-tested {0}", 85 | "Good {0}", 86 | "Handmade {0}", 87 | "Fair {0}", 88 | "Neat {0}", 89 | "Clean {0}", 90 | "Undamaged {0}", 91 | "Flawless {0}", 92 | "Adjusted {0}" 93 | }, 94 | 95 | new [] // Rarity 2 96 | { 97 | "Polished {0}", 98 | "Extraordinary {0}", 99 | "Exquisite {0}", 100 | "Superb {0}", 101 | "Unique {0}", 102 | "Handsome {0}", 103 | "Grand {0}", 104 | "Magic {0}", 105 | "Decorated {0}", 106 | "Exceptional {0}" 107 | }, 108 | 109 | new[] // Rarity 3 110 | { 111 | "Polished {0} of {1}", 112 | "Extraordinary {0} of {1}", 113 | "Exquisite {0} of {1}", 114 | "{1}'s Superb {0}", 115 | "Unique {0} of {1}", 116 | "{1}'s Handsome {0}", 117 | "Grand {0} of {1}", 118 | "Magic {0} of {1}", 119 | "Decorated {0} of {1}", 120 | "{1}'s Exceptional {0}" 121 | }, 122 | 123 | new [] // Rarity 4 124 | { 125 | "Shining {0} of {1}", // 1 126 | "Magnificent {0} von {1}", 127 | "Sublime {0} of {1}", 128 | "{1}'s Pompous {0}", 129 | "Glorious {0} of {1}", 130 | "{1}'s Splendid {0}", 131 | "Famous {0} of {1}", 132 | "Legendary {0} of {1}", 133 | "Fabulous {0} of {1}", 134 | "{1}'s Brilliant {0}" 135 | } 136 | }; 137 | 138 | public static readonly string[] ItemMaterialNames = new[] 139 | { 140 | "None", // Might be a problem? 141 | "Iron", 142 | "Wood", 143 | null, 144 | null, 145 | "Obsidian", 146 | null, 147 | "Bone", 148 | null, 149 | null, 150 | "Copper", 151 | "Gold", 152 | "Silver", 153 | "Emerald", 154 | "Sapphire", 155 | "Ruby", 156 | "Diamond", 157 | "Sandstone", 158 | "Saurian", 159 | "Parrot", 160 | "Mammoth", 161 | "Plant", 162 | "Ice", 163 | "Licht (Light)", 164 | "Glass", 165 | "Silk", 166 | "Linen", 167 | "Cotton", 168 | null, 169 | null, 170 | null, 171 | null, 172 | null, 173 | null, 174 | null, 175 | null, 176 | null, 177 | null, 178 | null, 179 | null, 180 | null, 181 | null, 182 | null, 183 | null, 184 | null, 185 | null, 186 | null, 187 | null, 188 | null, 189 | null, 190 | null, 191 | null, 192 | null, 193 | null, 194 | null, 195 | null, 196 | null, 197 | null, 198 | null, 199 | null, 200 | null, 201 | null, 202 | null, 203 | null, 204 | null, 205 | null, 206 | null, 207 | null, 208 | null, 209 | null, 210 | null, 211 | null, 212 | null, 213 | null, 214 | null, 215 | null, 216 | null, 217 | null, 218 | null, 219 | null, 220 | null, 221 | null, 222 | null, 223 | null, 224 | null, 225 | null, 226 | null, 227 | null, 228 | null, 229 | null, 230 | null, 231 | null, 232 | null, 233 | null, 234 | null, 235 | null, 236 | null, 237 | null, 238 | null, 239 | null, 240 | null, 241 | null, 242 | null, 243 | null, 244 | null, 245 | null, 246 | null, 247 | null, 248 | null, 249 | null, 250 | null, 251 | null, 252 | null, 253 | null, 254 | null, 255 | null, 256 | null, 257 | null, 258 | null, 259 | null, 260 | null, 261 | null, 262 | null, 263 | null, 264 | null, 265 | null, 266 | null, 267 | null, 268 | "Fire", 269 | "Unholy", 270 | "Ice", 271 | "Wind" 272 | }; 273 | 274 | // [type][subtype] 275 | public static readonly string[][] ItemSubtypes = new[] 276 | { 277 | new [] // None 278 | { 279 | "" 280 | }, 281 | 282 | new [] // Consumable 283 | { 284 | "Cookie", 285 | "Life Potion", 286 | "Cactus Potion", 287 | "Mana Potion", 288 | "Ginseng Soup", 289 | "Snowberry Mash", 290 | "Mushroom Spit", 291 | "Bomb", 292 | "Pineapple Slice", 293 | "Pumpkin Muffin" 294 | }, 295 | 296 | new [] // Recipes 297 | { 298 | "Recipe" 299 | }, 300 | 301 | new [] // Weapons 302 | { 303 | "Sword", 304 | "Axe", 305 | "Mace", 306 | "Dagger", 307 | "Fist", 308 | "Longsword", 309 | "Bow", 310 | "Crossbow", 311 | "Boomarang", 312 | "Arrow", 313 | "Staff", 314 | "Wand", 315 | "Bracelet", 316 | "Shield", 317 | "Arrows", 318 | "Greatsword", 319 | "Greataxe", 320 | "Greatmace", 321 | "Rake", 322 | "Pickaxe", 323 | "Torch" 324 | }, 325 | 326 | new [] // Chest Armor 327 | { 328 | "Chest Armor" 329 | }, 330 | 331 | new [] // Gloves 332 | { 333 | "Gloves" 334 | }, 335 | 336 | new [] // Boots 337 | { 338 | "Boots" 339 | }, 340 | 341 | new [] // Shoulder Armor 342 | { 343 | "Shoulder Armor" 344 | }, 345 | 346 | new [] // Amulets 347 | { 348 | "Amulet" 349 | }, 350 | 351 | new [] // Rings 352 | { 353 | "Ring" 354 | }, 355 | 356 | new [] // Blocks 357 | { 358 | "Block" 359 | }, 360 | 361 | new [] // Items 362 | { 363 | "Nugget", 364 | "Log", 365 | "Feather", 366 | "Horn", 367 | "Claw", 368 | "Fiber", 369 | "Cobweb", 370 | "Hair", 371 | "Crystal", 372 | "Yarn", 373 | "Cube", 374 | "Capsule", 375 | "Flask", 376 | "Orb", 377 | "Spirit", 378 | "Mushroom", 379 | "Pumpkin", 380 | "Pineapple", 381 | "Radish Slice", 382 | "Shimmer Mushroom", 383 | "Ginseng Root", 384 | "Onion Slice", 385 | "Heartflower", 386 | "Prickly Pear", 387 | "Iceflower", 388 | "Soulflower", 389 | "Water Flask", 390 | "Snowberry" 391 | }, 392 | 393 | new [] // Coins 394 | { 395 | "Coin" 396 | }, 397 | 398 | new [] // Platinum Coins 399 | { 400 | "Platinum Coin" 401 | }, 402 | 403 | new [] // Leftovers 404 | { 405 | "Leftovers" 406 | }, 407 | 408 | new [] // Beak 409 | { 410 | "Beak" 411 | }, 412 | 413 | new [] // Painting 414 | { 415 | "Painting" 416 | }, 417 | 418 | new [] // Vase 419 | { 420 | "Vase" 421 | }, 422 | 423 | new [] // Candle 424 | { 425 | "Candle", 426 | "Haunted Candle" 427 | }, 428 | 429 | new [] // Pets 430 | { 431 | "", "", "", "", "", "", "", "", 432 | "", "", "", "", "", "", "", "", 433 | "", "", "", 434 | "Collie", 435 | "Shepherd Dog", 436 | "", 437 | "Alpaca", 438 | "Alpaca (Brown)", 439 | "", 440 | "Turtle", 441 | "Terrier", 442 | "Terrier (Scottish)", 443 | "Wolf", 444 | "", 445 | "Cat", 446 | "Cat (Brown)", 447 | "Cat (White)", 448 | "Pig", 449 | "Sheep", 450 | "Bunny", 451 | "Porcupine", 452 | "Slime (Green)", 453 | "Slime (Pink)", 454 | "Slime (Yellow)", 455 | "Slime (Blue)", 456 | "", "", "", "", "", "", "", "", 457 | "", 458 | "Monkey", 459 | "", "", 460 | "Hornet", 461 | "", 462 | "Crow", 463 | "Chicken", 464 | "Seagull", 465 | "Parrot", 466 | "Bat", 467 | "Fly", 468 | "Midge", 469 | "Mosquito", 470 | "Runner (Plain)", 471 | "Runner (Leaf)", 472 | "Runner (Snow)", 473 | "Runner (Desert)", 474 | "Peacock", 475 | "Frog", 476 | "", "", "", "", 477 | "Devourer", 478 | "Duckbill", 479 | "Crocodile", 480 | "", "", "", "", "", "", "", "", "", 481 | "Imp", 482 | "Spitter", 483 | "Mole", 484 | "Biter", 485 | "Koala", 486 | "Squirrel", 487 | "Raccoon", 488 | "Owl", 489 | "Penguin", 490 | "", "", "", "", 491 | "Horse", 492 | "Camel", 493 | "", "", 494 | "Beetle (Dark)", 495 | "Beetle (Fire)", 496 | "Beetle (Snout)", 497 | "Beetle (Lemon)", 498 | "Crab", 499 | "", "", "", "", "", "", "", "", 500 | "", "", "", "", "", "", "", "", 501 | "", "", "", "", "", "", "", "", 502 | "", "", "", "", "", "", "", "", 503 | "", "", "", "", "", "", "", "", 504 | "", "", "", "", 505 | "Bumblebee" 506 | }, 507 | 508 | new [] // Pet Food 509 | { 510 | "", "", "", "", "", "", "", "", 511 | "", "", "", "", "", "", "", "", 512 | "", "", "", 513 | "Bubble Gum", 514 | "", "", 515 | "Vanilla Cupcake", 516 | "Chocolate Cupcake", 517 | "", 518 | "Cinnamon Roll", 519 | "Waffle", 520 | "Croissant", 521 | "", 522 | "", 523 | "Candy", 524 | "", 525 | "", 526 | "Pumpkin Mash", 527 | "Cotton Candy", 528 | "Carrot", 529 | "Blackberry Marmalade", 530 | "Green Jelly", 531 | "Pink Jelly", 532 | "Yellow Jelly", 533 | "Blue Jelly", 534 | "", "", "", "", "", "", "", "", "", 535 | "Banana Split", 536 | "", "", 537 | "Popcorn", 538 | "", 539 | "Licorice Candy", 540 | "Cereal Bar", 541 | "Salted Caramel", 542 | "Ginger Tartlet", 543 | "Mango Juice", 544 | "Fruit Basket", 545 | "Melon Icecream", 546 | "Bloodorange Juice", 547 | "Milk chocolate bar", 548 | "Mint chocolate bar", 549 | "White chocolate bar", 550 | "Caramel chocolate bar", 551 | "Chocolate Cookie", 552 | "", "", "", "", "", "", 553 | "Sugar Candy", 554 | "Apple Ring", 555 | "", "", "", "", "", "", "", "", "", "", 556 | "Water Ice", 557 | "Chocolate Doughnut", 558 | "Pancakes", 559 | "", 560 | "Strawberry Cake", 561 | "Chocolate Cake", 562 | "Lollipop", 563 | "Softice", 564 | "", "", "", "", 565 | "Candied Apple", 566 | "Date Cookie", 567 | "", "", 568 | "Bread", 569 | "Curry", 570 | "Lolly", 571 | "Lemon Tart", 572 | "Strawberry Cocktail", 573 | "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", 574 | "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", 575 | "", "", "", "", 576 | "Biscuit Role" 577 | }, 578 | 579 | new [] // Quest Items 580 | { 581 | "Amulet (Gold)", 582 | "Amulet (Sapphire)", 583 | "Jewel Case", 584 | "Key", 585 | "Medicine", 586 | "Antivenom", 587 | "Band Aid", 588 | "Crutch", 589 | "Bandage", 590 | "Salve" 591 | }, 592 | 593 | new [] // Unused 594 | { 595 | "" 596 | }, 597 | 598 | new [] // Transportation 599 | { 600 | "Hang Glider", 601 | "Boat" 602 | }, 603 | 604 | new [] // Lamps 605 | { 606 | "Lamp" 607 | }, 608 | 609 | new [] // Mana Cubes 610 | { 611 | "Mana Cube" 612 | } 613 | }; 614 | } 615 | } 616 | -------------------------------------------------------------------------------- /Source/Character/ICharacterData.cs: -------------------------------------------------------------------------------- 1 | using System.IO; 2 | 3 | namespace CharacterEditor.Character 4 | { 5 | public interface ICharacterData 6 | { 7 | void Read(BinaryReader reader); 8 | void Write(BinaryWriter writer); 9 | } 10 | } 11 | -------------------------------------------------------------------------------- /Source/Character/Inventory.cs: -------------------------------------------------------------------------------- 1 | using System.Collections.Generic; 2 | using System.IO; 3 | 4 | namespace CharacterEditor.Character 5 | { 6 | public class Inventory : ICharacterData 7 | { 8 | public const int DefaultItemCount = 50; 9 | 10 | public List Items; 11 | 12 | public Inventory() 13 | { 14 | Items = new List(); 15 | } 16 | 17 | public void Read(BinaryReader reader) 18 | { 19 | int inventoryCount = reader.ReadInt32(); 20 | for (int i = 0; i < inventoryCount; ++i) 21 | { 22 | Slot slot = new Slot(); 23 | slot.Read(reader); 24 | 25 | Items.Add(slot); 26 | } 27 | } 28 | 29 | public void Write(BinaryWriter writer) 30 | { 31 | writer.Write(Items.Count); 32 | 33 | foreach (Slot slot in Items) 34 | slot.Write(writer); 35 | } 36 | } 37 | } -------------------------------------------------------------------------------- /Source/Character/Item.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.IO; 4 | using System.Linq; 5 | 6 | namespace CharacterEditor.Character 7 | { 8 | public class Item : ICharacterData 9 | { 10 | public const int AttributeCount = 32; 11 | public const int PrefixDivisor = 10; 12 | public const int ModelDivisor = 11; 13 | public const int EffectDivisor = 21; 14 | 15 | public byte Type; 16 | public byte Subtype; 17 | //public short ActualModifier; // TODO Hack, should build modifier from its fragments 18 | public byte RecipeType; 19 | public byte Rarity; 20 | public byte Material; 21 | public ItemFlags Flags; 22 | public short Level; 23 | 24 | // Modifier subparts 25 | public int PrefixId; 26 | public int ModelId; 27 | public int EffectId; 28 | 29 | public List Attributes; 30 | 31 | public double Armor 32 | { 33 | get 34 | { 35 | HashSet supportedTypes = new HashSet 36 | { 37 | Constants.ItemType.ChestArmor, 38 | Constants.ItemType.ShoulderArmor, 39 | Constants.ItemType.Gloves, 40 | Constants.ItemType.Boots 41 | }; 42 | 43 | Constants.ItemType itemType = (Constants.ItemType)Type; 44 | 45 | if (!supportedTypes.Contains(itemType)) 46 | return 0.0; 47 | 48 | double typeBonus = itemType == Constants.ItemType.ChestArmor ? 1.0 : 0.5; 49 | 50 | double materialBonus = 0; 51 | switch (Material) 52 | { 53 | case 23: 54 | case 25: 55 | materialBonus = 0.075; 56 | break; 57 | 58 | case 19: 59 | case 26: 60 | case 27: 61 | materialBonus = 0.85; // might need to expand the precision here 62 | break; 63 | 64 | case 18: 65 | materialBonus = 0.80; // might need to expand the precision here 66 | break; 67 | } 68 | 69 | double effect = CalculateLevelEffectValue(Level + Attributes.Count / 10.0, Rarity); 70 | return effect * typeBonus * materialBonus; 71 | } 72 | } 73 | 74 | public double Critical 75 | { 76 | get 77 | { 78 | HashSet supportedTypes = new HashSet 79 | { 80 | Constants.ItemType.Amulets, 81 | Constants.ItemType.Rings, 82 | Constants.ItemType.Weapons, 83 | Constants.ItemType.ChestArmor, 84 | Constants.ItemType.ShoulderArmor, 85 | Constants.ItemType.Gloves, 86 | Constants.ItemType.Boots 87 | }; 88 | 89 | Constants.ItemType itemType = (Constants.ItemType)Type; 90 | 91 | if (!supportedTypes.Contains(itemType)) 92 | return 0.0; 93 | 94 | double typeBonus = 0.05; 95 | if (itemType == Constants.ItemType.Weapons && (Subtype == 15 || Subtype == 16 || Subtype == 17 || 96 | Subtype == 5 || Subtype == 10 || Subtype == 11 || 97 | Subtype == 18 || Subtype == 8 || Subtype == 6 || Subtype == 7) || 98 | itemType == Constants.ItemType.ChestArmor) 99 | typeBonus = 0.1; 100 | 101 | double modifierBonus = 1.0 - ((Modifier % 21) / 20.0); 102 | if (Material == 11) 103 | modifierBonus += 1.0; 104 | 105 | double effect = CalculateLevelEffectPercent(Level, Rarity); 106 | double result = effect * typeBonus * modifierBonus; 107 | 108 | return Math.Abs(result) < 0.001 ? 0 : result; 109 | } 110 | } 111 | 112 | public double Life 113 | { 114 | get 115 | { 116 | HashSet supportedTypes = new HashSet 117 | { 118 | Constants.ItemType.Weapons, 119 | Constants.ItemType.ChestArmor, 120 | Constants.ItemType.ShoulderArmor, 121 | Constants.ItemType.Gloves, 122 | Constants.ItemType.Boots 123 | }; 124 | 125 | Constants.ItemType itemType = (Constants.ItemType)Type; 126 | 127 | if (!supportedTypes.Contains(itemType)) 128 | return 0.0; 129 | 130 | double typeBonus = itemType == Constants.ItemType.ChestArmor ? 1.0 : 0.5; 131 | double modifierBonus = (1.0 - ((Modifier % 21) / 20.0)) + 1.0; 132 | 133 | switch (Material) 134 | { 135 | case 1: 136 | modifierBonus += 1.0; 137 | break; 138 | 139 | case 26: 140 | modifierBonus += 0.5; 141 | break; 142 | 143 | case 27: 144 | modifierBonus += 0.75; 145 | break; 146 | } 147 | 148 | double effect = CalculateLevelEffectValue(Level + Attributes.Count / 10.0, Rarity); 149 | return effect * 5.0 * typeBonus * modifierBonus; 150 | } 151 | } 152 | 153 | public double Regeneration 154 | { 155 | get 156 | { 157 | HashSet supportedTypes = new HashSet 158 | { 159 | Constants.ItemType.Weapons, 160 | Constants.ItemType.ChestArmor, 161 | Constants.ItemType.ShoulderArmor, 162 | Constants.ItemType.Gloves, 163 | Constants.ItemType.Boots 164 | }; 165 | 166 | Constants.ItemType itemType = (Constants.ItemType)Type; 167 | 168 | if (!supportedTypes.Contains(itemType)) 169 | return 0.0; 170 | 171 | double typeBonus = itemType == Constants.ItemType.ChestArmor ? 0.2 : 0.1; 172 | double modifierBonus = (Modifier % 21) / 20.0; 173 | 174 | switch (Material) 175 | { 176 | case 26: 177 | modifierBonus += 0.5; 178 | break; 179 | 180 | case 27: 181 | modifierBonus += 1.0; 182 | break; 183 | } 184 | 185 | double effect = CalculateLevelEffectValue(Level + Attributes.Count / 10.0, Rarity); 186 | return effect * typeBonus * modifierBonus; 187 | } 188 | } 189 | 190 | public double Resistance 191 | { 192 | get 193 | { 194 | HashSet supportedTypes = new HashSet 195 | { 196 | Constants.ItemType.ChestArmor, 197 | Constants.ItemType.ShoulderArmor, 198 | Constants.ItemType.Gloves, 199 | Constants.ItemType.Boots 200 | }; 201 | 202 | Constants.ItemType itemType = (Constants.ItemType)Type; 203 | 204 | if (!supportedTypes.Contains(itemType)) 205 | return 0.0; 206 | 207 | double typeBonus = itemType == Constants.ItemType.ChestArmor ? 1.0 : 0.5; 208 | 209 | double materialBonus = 0.0; 210 | switch (Material) 211 | { 212 | case 1: 213 | case 19: 214 | materialBonus = 0.85; 215 | break; 216 | 217 | case 26: 218 | case 27: 219 | materialBonus = 0.75; 220 | break; 221 | } 222 | 223 | double effect = CalculateLevelEffectValue(Level + Attributes.Count / 10.0, Rarity); 224 | return effect * typeBonus * materialBonus; 225 | } 226 | } 227 | 228 | public double Tempo 229 | { 230 | get 231 | { 232 | HashSet supportedTypes = new HashSet 233 | { 234 | Constants.ItemType.Amulets, 235 | Constants.ItemType.Rings, 236 | Constants.ItemType.Weapons, 237 | Constants.ItemType.ChestArmor, 238 | Constants.ItemType.ShoulderArmor, 239 | Constants.ItemType.Gloves, 240 | Constants.ItemType.Boots 241 | }; 242 | 243 | Constants.ItemType itemType = (Constants.ItemType)Type; 244 | 245 | if (!supportedTypes.Contains(itemType)) 246 | return 0.0; 247 | 248 | double typeBonus = 0.1; 249 | if (itemType == Constants.ItemType.Weapons && (Subtype == 15 || Subtype == 16 || Subtype == 17 || 250 | Subtype == 5 || Subtype == 10 || Subtype == 11 || 251 | Subtype == 18 || Subtype == 8 || Subtype == 6 || Subtype == 7) || 252 | itemType == Constants.ItemType.ChestArmor) 253 | typeBonus = 0.2; 254 | 255 | double modifierBonus = (Modifier % 21) / 20.0; 256 | if (Material == 12) 257 | modifierBonus += 1.0; 258 | 259 | double effect = CalculateLevelEffectPercent(Level, Rarity); 260 | double result = effect * typeBonus * modifierBonus; 261 | 262 | return Math.Abs(result) < 0.001 ? 0 : result; 263 | 264 | } 265 | } 266 | 267 | public double Damage 268 | { 269 | get 270 | { 271 | Constants.ItemType itemType = (Constants.ItemType)Type; 272 | 273 | if (itemType != Constants.ItemType.Weapons) 274 | return 0.0; 275 | 276 | double damageBonus = 4.0; 277 | switch (Subtype) 278 | { 279 | case 3: 280 | case 4: 281 | damageBonus = 2.0; 282 | break; 283 | 284 | case 5: 285 | damageBonus = 4.0; 286 | break; 287 | 288 | case 13: 289 | damageBonus = 2.0; 290 | break; 291 | 292 | case 15: 293 | case 16: 294 | case 17: 295 | case 10: 296 | case 11: 297 | case 18: 298 | case 8: 299 | case 6: 300 | case 7: 301 | damageBonus = 8.0; 302 | break; 303 | } 304 | 305 | double effect = CalculateLevelEffectValue(Level + Attributes.Count / 10.0, Rarity); 306 | return effect * damageBonus; 307 | } 308 | } 309 | 310 | public short Modifier 311 | { 312 | get 313 | { 314 | int modifier, t; 315 | ChineseRemainder.Solve(PrefixDivisor, ModelDivisor, EffectDivisor, PrefixId, ModelId, EffectId, out modifier, out t); 316 | 317 | return (short)modifier; 318 | } 319 | 320 | private set 321 | { 322 | PrefixId = value % PrefixDivisor; 323 | ModelId = value % ModelDivisor; 324 | EffectId = value % EffectDivisor; 325 | } 326 | } 327 | 328 | public string FriendlyName 329 | { 330 | get 331 | { 332 | try 333 | { 334 | // TODO Should probably clean this up 335 | string format = "{0}"; 336 | 337 | string ownerName = NameGenerator.Generate(Modifier, (Modifier * 7) % 11); 338 | string itemName = string.Empty; 339 | 340 | if (Type == (int)Constants.ItemType.Recipes) 341 | { 342 | itemName += Constants.ItemSubtypes[RecipeType][Subtype] + " "; 343 | itemName += Constants.ItemSubtypes[(int)Constants.ItemType.Recipes][Subtype]; 344 | } 345 | else 346 | itemName += Constants.ItemSubtypes[Type][Subtype]; 347 | 348 | if (Material != 0) 349 | itemName = Constants.ItemMaterialNames[Material] + " " + itemName; 350 | 351 | if (Modifier != 0) 352 | format = Constants.ItemModifiers[Rarity][(Modifier - 1) % 10]; 353 | 354 | return Rarity < 3 ? string.Format(format, itemName) : string.Format(format, itemName, ownerName); 355 | } 356 | catch (Exception) 357 | { 358 | return "ERROR"; 359 | } 360 | } 361 | } 362 | 363 | [Flags] 364 | public enum ItemFlags : byte 365 | { 366 | Adapted = 0x01 367 | } 368 | 369 | public Item() 370 | { 371 | Attributes = new List(); 372 | } 373 | 374 | public void Read(BinaryReader reader) 375 | { 376 | Type = reader.ReadByte(); 377 | Subtype = reader.ReadByte(); 378 | reader.Skip(2); 379 | Modifier = reader.ReadInt16(); 380 | reader.Skip(2); 381 | RecipeType = reader.ReadByte(); 382 | reader.Skip(3); 383 | Rarity = reader.ReadByte(); 384 | Material = reader.ReadByte(); 385 | Flags = (ItemFlags)reader.ReadByte(); 386 | reader.Skip(1); 387 | Level = reader.ReadInt16(); 388 | reader.Skip(2); 389 | 390 | for (int i = 0; i < AttributeCount; ++i) 391 | { 392 | ItemAttribute attribute = new ItemAttribute(); 393 | attribute.Read(reader); 394 | 395 | Attributes.Add(attribute); 396 | } 397 | 398 | // AttributesUsed is calculated on write 399 | reader.Skip(4); 400 | } 401 | 402 | public void Write(BinaryWriter writer) 403 | { 404 | writer.Write(Type); 405 | writer.Write(Subtype); 406 | writer.Skip(2); 407 | writer.Write(Modifier); 408 | writer.Skip(2); 409 | writer.Write(RecipeType); 410 | writer.Skip(3); 411 | writer.Write(Rarity); 412 | writer.Write(Material); 413 | writer.Write((byte)Flags); 414 | writer.Skip(1); 415 | writer.Write(Level); 416 | writer.Skip(2); 417 | 418 | foreach (ItemAttribute attribute in Attributes) 419 | attribute.Write(writer); 420 | 421 | writer.Write(Attributes.Count(attr => attr.Used)); 422 | } 423 | 424 | private static double CalculateLevelEffectValue(double level, int rarity) 425 | { 426 | double a = 3.0 * (1.0 - (1.0 / (1.0 + ((level - 1.0) / 20.0)))); 427 | double b = rarity / 4.0; 428 | double result = Math.Pow(2, a) * Math.Pow(2, b); 429 | 430 | return result; 431 | } 432 | 433 | private static double CalculateLevelEffectPercent(double level, int rarity) 434 | { 435 | double a = 3.0 * (1.0 - (1.0 / (1.0 + ((level - 1.0) / 20.0)))); 436 | double b = rarity / 4.0; 437 | double c = 3.0; 438 | double result = Math.Pow(2, a) * Math.Pow(2, b) / Math.Pow(2, c); 439 | 440 | return result; 441 | } 442 | } 443 | } -------------------------------------------------------------------------------- /Source/Character/ItemAttribute.cs: -------------------------------------------------------------------------------- 1 | using System.IO; 2 | 3 | namespace CharacterEditor.Character 4 | { 5 | public class ItemAttribute : ICharacterData 6 | { 7 | public byte OffsetX; 8 | public byte OffsetY; 9 | public byte OffsetZ; 10 | public byte Material; 11 | public short Level; 12 | 13 | public bool Used 14 | { 15 | get 16 | { 17 | return OffsetX + OffsetY + OffsetZ + Material + Level > 0; 18 | } 19 | } 20 | 21 | public void Read(BinaryReader reader) 22 | { 23 | OffsetX = reader.ReadByte(); 24 | OffsetY = reader.ReadByte(); 25 | OffsetZ = reader.ReadByte(); 26 | Material = reader.ReadByte(); 27 | Level = reader.ReadInt16(); 28 | reader.Skip(2); 29 | } 30 | 31 | public void Write(BinaryWriter writer) 32 | { 33 | writer.Write(OffsetX); 34 | writer.Write(OffsetY); 35 | writer.Write(OffsetZ); 36 | writer.Write(Material); 37 | writer.Write(Level); 38 | writer.Skip(2); 39 | } 40 | } 41 | } -------------------------------------------------------------------------------- /Source/Character/NameGenerator.cs: -------------------------------------------------------------------------------- 1 | using System.Collections.Generic; 2 | 3 | namespace CharacterEditor.Character 4 | { 5 | // CREDIT Ntl3fty 6 | public class NameGenerator 7 | { 8 | private static readonly IDictionary PartialNames = new Dictionary 9 | { 10 | { 11 | -1, 12 | new[,] 13 | { 14 | { "Kro", "Aru", "As", "Ge", "Kur", "Lugo", "Iko", "Liku", "Tero", "Var", "An", "The", "Ga", "Lan", "Dura", "Dama", "Se", "Thal", "Nar", "San" }, 15 | { "no", "mi", "la", "sel", "ron", "ion", "kor", "lon", "rok", "tar", "den", "gar", "dar", "dara", "lan", "ka", "gor", "rior", "ria", "mor" } 16 | } 17 | }, 18 | 19 | { 20 | 0, 21 | new[,] 22 | { 23 | { "El", "Li", "Dri", "Elan", "Le", "Ly", "A", "Tho", "Da", "Les" }, 24 | { "ric", "kun", "zic", "dor", "las", "sander", "reon", "reas", "lundra", "andor" } 25 | } 26 | }, 27 | 28 | { 29 | 1, 30 | new[,] 31 | { 32 | { "Ar", "A", "Si", "Mer", "Lu", "Ari", "Su", "Sira", "Hia", "Li" }, 33 | { "weya", "luna", "laya", "leya", "ma", "lia", "matra", "vy", "zyna", "ly" } 34 | } 35 | }, 36 | 37 | { 38 | 2, 39 | new[,] 40 | { 41 | { "De", "Ro", "As", "Ge", "An", "Pat", "Wolf", "Ale", "Mi", "Ben" }, 42 | { "rek", "man", "gram", "rald", "rick", "ram", "sander", "kal", "ton", "ny" } 43 | } 44 | }, 45 | 46 | { 47 | 3, new[,] 48 | { 49 | { "Sa", "Jen", "Kla", "Mi", "La", "Auri", "Mela", "Alu", "Ve", "Est" }, 50 | { "rah", "ny", "ria", "elle", "na", "ga", "ma", "riana", "rona", "una" } 51 | } 52 | }, 53 | 54 | { 55 | 4, 56 | new[,] 57 | { 58 | { "Gra", "Xe", "Ur", "Bel", "Chu", "Ki", "Go", "Zim", "Kubo", "Raz" }, 59 | { "zic", "nax", "tik", "tuk", "ruk", "bo", "rix", "mi", "tok", "nor" } 60 | } 61 | }, 62 | 63 | { 64 | 5, 65 | new[,] 66 | { 67 | { "Kur", "Xe", "Ki", "Am", "Zifa", "Zu", "Ma", "Chi", "Zi", "Mia" }, 68 | { "ra", "lia", "bi", "ba", "ly", "ki", "bara", "mi", "zy", "xa" } 69 | } 70 | }, 71 | 72 | { 73 | 7, 74 | new[,] 75 | { 76 | { "Cho", "Zer", "Kaz", "Kraz", "Zel", "Drak", "Lo", "Raz", "Spi", "Zen" }, 77 | { "rux", "rek", "zic", "tac", "mec", "kor", "rax", "zor", "ro", "go" } 78 | } 79 | }, 80 | 81 | { 82 | 8, 83 | new[,] 84 | { 85 | { "Zi", "Zer", "Az", "Ki", "Iza", "Drak", "Li", "May", "Spi", "Zan" }, 86 | { "rya", "ri", "zia", "ki", "mah", "ira", "maya", "ana", "ra", "ya" } 87 | } 88 | }, 89 | 90 | { 91 | 9, 92 | new[,] 93 | { 94 | { "Tor", "Gem", "Bar", "Me", "As", "Tem", "Arak", "Ur", "Grim", "Xor" }, 95 | { "lox", "bart", "kor", "thos", "kun", "bur", "thor", "lok", "li", "bor" } 96 | } 97 | }, 98 | 99 | { 100 | 10, 101 | new[,] 102 | { 103 | { "Mum", "Grun", "Brun", "Hei", "Mo", "Hil", "Ur", "Lum", "Grim", "Xor" }, 104 | { "pie", "hild", "di", "muna", "ki", "trud", "sa", "axa", "ira", "ika" } 105 | } 106 | }, 107 | 108 | { 109 | 11, 110 | new[,] 111 | { 112 | { "Uz", "Ur", "Chu", "Ku", "Mor", "Ura", "Ak", "Ur", "Or", "Gor" }, 113 | { "ku", "ruk", "muk", "thak", "dok", "tor", "rorok", "chak", "kaz", "rack" } 114 | } 115 | }, 116 | 117 | { 118 | 12, 119 | new[,] 120 | { 121 | { "Uz", "Ur", "Chu", "Ku", "Mor", "Ura", "Ak", "Ur", "Or", "Gor" }, 122 | { "ka", "rua", "mua", "thara", "daka", "tah", "rorah", "chaka", "kaya", "rana" } 123 | } 124 | }, 125 | 126 | { 127 | 13, 128 | new[,] 129 | { 130 | { "Qua", "Rib", "Quib", "Zib", "Il", "Wok", "Wib", "Moko", "Sli", "Bul" }, 131 | { "rik", "bit", "ble", "bik", "wak", "wok", "wib", "luk", "mey", "bak" } 132 | } 133 | }, 134 | 135 | { 136 | 14, 137 | new[,] 138 | { 139 | { "Qua", "Rib", "Quib", "Zib", "Il", "Wok", "Wib", "Moko", "Sli", "Bul" }, 140 | { "ria", "bia", "bla", "bia", "waka", "woka", "wibba", "lua", "maya", "ba" } 141 | } 142 | }, 143 | 144 | { 145 | 15, 146 | new[,] 147 | { 148 | { "Chu", "Dro", "Al", "Dem", "Mor", "Mur", "Cro", "Zul", "Dra", "The" }, 149 | { "lu", "kor", "card", "morius", "enius", "tus", "demar", "lus", "ruul", "zad" } 150 | } 151 | }, 152 | 153 | { 154 | 16, 155 | new[,] 156 | { 157 | { "Xu", "Dra", "Al", "Dem", "Mor", "Myr", "Cra", "Zul", "Dri", "Thu" }, 158 | { "la", "kira", "cara", "moria", "ena", "tana", "diria", "laza", "rah", "zazah" } 159 | } 160 | } 161 | }; 162 | 163 | static NameGenerator() 164 | { 165 | PartialNames[18] = PartialNames[2]; 166 | PartialNames[43] = PartialNames[2]; 167 | PartialNames[83] = PartialNames[2]; 168 | 169 | PartialNames[45] = PartialNames[3]; 170 | PartialNames[84] = PartialNames[3]; 171 | } 172 | 173 | public static string Generate(int id, int type = -1) 174 | { 175 | string[,] partials; 176 | if (!PartialNames.TryGetValue(type, out partials)) 177 | partials = PartialNames[-1]; 178 | 179 | int index1 = (13 * id + id / 7) % partials.GetLength(1); 180 | int index2 = (id / 10 + 7 * id) % partials.GetLength(1); 181 | 182 | return partials[0, index1] + partials[1, index2]; 183 | } 184 | } 185 | } 186 | -------------------------------------------------------------------------------- /Source/Character/Slot.cs: -------------------------------------------------------------------------------- 1 | using System.IO; 2 | 3 | namespace CharacterEditor.Character 4 | { 5 | public class Slot : ICharacterData 6 | { 7 | public const int MaxItemCount = 50; 8 | 9 | public int Count; 10 | public Item Item; 11 | 12 | public void Read(BinaryReader reader) 13 | { 14 | Count = reader.ReadInt32(); 15 | Item = new Item(); 16 | Item.Read(reader); 17 | } 18 | 19 | public void Write(BinaryWriter writer) 20 | { 21 | writer.Write(Count); 22 | Item.Write(writer); 23 | } 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /Source/Character/World.cs: -------------------------------------------------------------------------------- 1 | using System.IO; 2 | 3 | namespace CharacterEditor.Character 4 | { 5 | public class World : ICharacterData 6 | { 7 | public int Seed; 8 | public string Name; 9 | public long X; 10 | public long Y; 11 | public long Z; 12 | 13 | public void Read(BinaryReader reader) 14 | { 15 | Seed = reader.ReadInt32(); 16 | Name = reader.ReadLongString(); 17 | X = reader.ReadInt64(); 18 | Y = reader.ReadInt64(); 19 | Z = reader.ReadInt64(); 20 | } 21 | 22 | public void Write(BinaryWriter writer) 23 | { 24 | writer.Write(Seed); 25 | writer.WriteLongString(Name); 26 | writer.Write(X); 27 | writer.Write(Y); 28 | writer.Write(Z); 29 | } 30 | } 31 | } -------------------------------------------------------------------------------- /Source/CharacterEditor.csproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | Debug 5 | x86 6 | 8.0.30703 7 | 2.0 8 | {42DB9E31-B097-4870-803A-54C924271BA6} 9 | Exe 10 | Properties 11 | CharacterEditor 12 | CharacterEditor 13 | v4.0 14 | 15 | 16 | 512 17 | 18 | 19 | x86 20 | true 21 | full 22 | false 23 | bin\Debug\ 24 | DEBUG;TRACE 25 | prompt 26 | 4 27 | 28 | 29 | x86 30 | pdbonly 31 | true 32 | bin\Release\ 33 | TRACE 34 | prompt 35 | 4 36 | 37 | 38 | 39 | 40 | 41 | icon.ico 42 | 43 | 44 | 45 | 46 | 47 | 48 | False 49 | ..\References\System.Data.SQLite.dll 50 | 51 | 52 | 53 | 54 | 55 | False 56 | ..\References\zlib.net.dll 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | Editor.cs 74 | Form 75 | 76 | 77 | Form 78 | 79 | 80 | Editor.cs 81 | Form 82 | 83 | 84 | Editor.cs 85 | 86 | 87 | Editor.cs 88 | Form 89 | 90 | 91 | Editor.cs 92 | Form 93 | 94 | 95 | Form 96 | 97 | 98 | ExceptionDialog.cs 99 | 100 | 101 | Form 102 | 103 | 104 | FormItemStats.cs 105 | 106 | 107 | Form 108 | 109 | 110 | LoadCharacterDialog.cs 111 | 112 | 113 | Component 114 | 115 | 116 | 117 | 118 | True 119 | True 120 | Resources.resx 121 | 122 | 123 | 124 | Editor.cs 125 | Designer 126 | 127 | 128 | ExceptionDialog.cs 129 | 130 | 131 | FormItemStats.cs 132 | 133 | 134 | LoadCharacterDialog.cs 135 | 136 | 137 | ResXFileCodeGenerator 138 | Resources.Designer.cs 139 | Designer 140 | 141 | 142 | 143 | 144 | 145 | 146 | 147 | 148 | 149 | 150 | 157 | -------------------------------------------------------------------------------- /Source/CharacterEditor.sln: -------------------------------------------------------------------------------- 1 |  2 | Microsoft Visual Studio Solution File, Format Version 12.00 3 | # Visual Studio 2010 4 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "CharacterEditor", "CharacterEditor.csproj", "{42DB9E31-B097-4870-803A-54C924271BA6}" 5 | EndProject 6 | Global 7 | GlobalSection(SolutionConfigurationPlatforms) = preSolution 8 | Debug|Any CPU = Debug|Any CPU 9 | Debug|Mixed Platforms = Debug|Mixed Platforms 10 | Debug|x86 = Debug|x86 11 | Release|Any CPU = Release|Any CPU 12 | Release|Mixed Platforms = Release|Mixed Platforms 13 | Release|x86 = Release|x86 14 | EndGlobalSection 15 | GlobalSection(ProjectConfigurationPlatforms) = postSolution 16 | {42DB9E31-B097-4870-803A-54C924271BA6}.Debug|Any CPU.ActiveCfg = Debug|x86 17 | {42DB9E31-B097-4870-803A-54C924271BA6}.Debug|Mixed Platforms.ActiveCfg = Debug|x86 18 | {42DB9E31-B097-4870-803A-54C924271BA6}.Debug|Mixed Platforms.Build.0 = Debug|x86 19 | {42DB9E31-B097-4870-803A-54C924271BA6}.Debug|x86.ActiveCfg = Debug|x86 20 | {42DB9E31-B097-4870-803A-54C924271BA6}.Debug|x86.Build.0 = Debug|x86 21 | {42DB9E31-B097-4870-803A-54C924271BA6}.Release|Any CPU.ActiveCfg = Release|x86 22 | {42DB9E31-B097-4870-803A-54C924271BA6}.Release|Mixed Platforms.ActiveCfg = Release|x86 23 | {42DB9E31-B097-4870-803A-54C924271BA6}.Release|Mixed Platforms.Build.0 = Release|x86 24 | {42DB9E31-B097-4870-803A-54C924271BA6}.Release|x86.ActiveCfg = Release|x86 25 | {42DB9E31-B097-4870-803A-54C924271BA6}.Release|x86.Build.0 = Release|x86 26 | EndGlobalSection 27 | GlobalSection(SolutionProperties) = preSolution 28 | HideSolutionNode = FALSE 29 | EndGlobalSection 30 | EndGlobal 31 | -------------------------------------------------------------------------------- /Source/Database.cs: -------------------------------------------------------------------------------- 1 | using System.Data; 2 | using System.Data.SQLite; 3 | using System.IO; 4 | using System.Linq; 5 | using zlib; 6 | 7 | namespace CharacterEditor 8 | { 9 | public class Database 10 | { 11 | private SQLiteConnection connection; 12 | 13 | public void Load(string filename) 14 | { 15 | string connectionString = string.Format("Data Source={0};Version=3", filename); 16 | connection = new SQLiteConnection(connectionString); 17 | connection.Open(); 18 | } 19 | 20 | public byte[] ReadCharacterBlob(int index) 21 | { 22 | byte[] stream = ReadBlobByIndex(index); 23 | byte[] decompressedStream; 24 | 25 | DecompressData(stream, out decompressedStream); 26 | 27 | return decompressedStream; 28 | } 29 | 30 | public bool WriteCharacterBlob(int index, byte[] data) 31 | { 32 | byte[] compressedStream; 33 | CompressData(data, out compressedStream); 34 | 35 | return WriteBlobByIndex(index, compressedStream); 36 | } 37 | 38 | public bool WriteBlobByIndex(int index, byte[] data) 39 | { 40 | using (SQLiteCommand command = new SQLiteCommand(connection)) 41 | { 42 | command.CommandText = string.Format("UPDATE `blobs` SET `value`=@blobData WHERE `key`='{0}'", index); 43 | command.Parameters.Add(new SQLiteParameter("@blobData", DbType.Binary) 44 | { 45 | Value = data 46 | }); 47 | 48 | return command.ExecuteNonQuery() == 1; 49 | } 50 | } 51 | 52 | public byte[] ReadBlobByIndex(int index) 53 | { 54 | return ReadBlobByKey(index.ToString("G")); 55 | } 56 | 57 | public byte[] ReadBlobByKey(string index) 58 | { 59 | DataTable table = new DataTable(); 60 | 61 | using (SQLiteCommand command = new SQLiteCommand(connection)) 62 | { 63 | command.CommandText = string.Format("SELECT `value` FROM `blobs` WHERE `key`='{0}'", index); 64 | SQLiteDataReader reader = command.ExecuteReader(); 65 | table.Load(reader); 66 | reader.Close(); 67 | } 68 | 69 | if (table.Rows.Count == 0) 70 | return null; 71 | 72 | return (byte[])table.Rows[0].ItemArray.First(); 73 | } 74 | 75 | private static void CompressData(byte[] inData, out byte[] outData) 76 | { 77 | using (MemoryStream outMemoryStream = new MemoryStream()) 78 | { 79 | using (ZOutputStream outZStream = new ZOutputStream(outMemoryStream, zlibConst.Z_DEFAULT_COMPRESSION)) 80 | { 81 | using (Stream inMemoryStream = new MemoryStream(inData)) 82 | { 83 | CopyStream(inMemoryStream, outZStream); 84 | outZStream.finish(); 85 | 86 | outData = outMemoryStream.ToArray(); 87 | } 88 | } 89 | } 90 | } 91 | 92 | private static void DecompressData(byte[] inData, out byte[] outData) 93 | { 94 | using (MemoryStream outMemoryStream = new MemoryStream()) 95 | { 96 | using (ZOutputStream outZStream = new ZOutputStream(outMemoryStream)) 97 | { 98 | using (Stream inMemoryStream = new MemoryStream(inData)) 99 | { 100 | CopyStream(inMemoryStream, outZStream); 101 | outZStream.finish(); 102 | 103 | outData = outMemoryStream.ToArray(); 104 | } 105 | } 106 | } 107 | } 108 | 109 | private static void CopyStream(Stream input, Stream output) 110 | { 111 | byte[] buffer = new byte[2048]; 112 | int len; 113 | 114 | while ((len = input.Read(buffer, 0, buffer.Length)) > 0) 115 | output.Write(buffer, 0, len); 116 | 117 | output.Flush(); 118 | } 119 | } 120 | } 121 | -------------------------------------------------------------------------------- /Source/DirtyWatcher.cs: -------------------------------------------------------------------------------- 1 | using System.Windows.Forms; 2 | 3 | namespace CharacterEditor 4 | { 5 | public class DirtyWatcher 6 | { 7 | public bool Dirty; 8 | public bool IgnoreDirtiness; 9 | 10 | public DirtyWatcher(Control form) 11 | { 12 | RecurseControls(form); 13 | } 14 | 15 | private void RecurseControls(Control form) 16 | { 17 | foreach (Control control in form.Controls) 18 | RecurseControlsInner(control); 19 | } 20 | 21 | private void RecurseControlsInner(Control parent) 22 | { 23 | foreach (Control control in parent.Controls) 24 | { 25 | if (control is TextBox) 26 | { 27 | control.TextChanged += (o, e) => Dirty = !IgnoreDirtiness || Dirty; 28 | } 29 | else if (control is ComboBox) 30 | { 31 | ComboBox comboBox = (ComboBox)control; 32 | comboBox.SelectedIndexChanged += (o, e) => Dirty = !IgnoreDirtiness || Dirty; 33 | } 34 | else if (control is NumericUpDown) 35 | { 36 | NumericUpDown numericUpDown = (NumericUpDown)control; 37 | numericUpDown.ValueChanged += (o, e) => Dirty = !IgnoreDirtiness || Dirty; 38 | } 39 | else if (control is CheckBox) 40 | { 41 | CheckBox checkBox = (CheckBox)control; 42 | checkBox.CheckedChanged += (o, e) => Dirty = !IgnoreDirtiness || Dirty; 43 | } 44 | else if (control is Button) 45 | { 46 | Button button = (Button)control; 47 | button.BackColorChanged += (o, e) => Dirty = !IgnoreDirtiness || Dirty; 48 | } 49 | 50 | RecurseControlsInner(control); 51 | } 52 | } 53 | } 54 | } 55 | -------------------------------------------------------------------------------- /Source/Forms/Editor.Character.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Windows.Forms; 3 | 4 | namespace CharacterEditor.Forms 5 | { 6 | public partial class Editor 7 | { 8 | private void ButtonHairColorClick(object sender, EventArgs e) 9 | { 10 | ColorDialog colorDialog = new ColorDialog 11 | { 12 | Color = buttonHairColor.BackColor, 13 | FullOpen = true 14 | }; 15 | 16 | colorDialog.ShowDialog(this); 17 | 18 | buttonHairColor.BackColor = colorDialog.Color; 19 | } 20 | 21 | private void ComboBoxRaceSelectedIndexChanged(object sender, EventArgs e) 22 | { 23 | int[,] faceMaximums = new[,] 24 | { 25 | { 6, 6 }, 26 | { 4, 6 }, 27 | { 5, 5 }, 28 | { 5, 4 }, 29 | { 5, 6 }, 30 | { 2, 5 }, 31 | { 6, 6 }, 32 | { 5, 4 } 33 | }; 34 | 35 | int[,] haircutMaximums = new[,] 36 | { 37 | { 15, 7 }, 38 | { 10, 10 }, 39 | { 3, 5 }, 40 | { 10, 4 }, 41 | { 6, 6 }, 42 | { 6, 6 }, 43 | { 6, 6 }, 44 | { 5, 4 } 45 | }; 46 | 47 | if (comboBoxRace.SelectedIndex == -1 || comboBoxGender.SelectedIndex == -1) 48 | return; 49 | 50 | nudFace.Maximum = faceMaximums[comboBoxRace.SelectedIndex, comboBoxGender.SelectedIndex]; 51 | nudHair.Maximum = haircutMaximums[comboBoxRace.SelectedIndex, comboBoxGender.SelectedIndex]; 52 | } 53 | 54 | private void ComboBoxClassSelectedIndexChanged(object sender, EventArgs e) 55 | { 56 | object[][] specializations = new object[][] 57 | { 58 | new[] { "Berserker", "Guardian" }, 59 | new[] { "Sniper", "Scout" }, 60 | new[] { "Fire Mage", "Water Mage" }, 61 | new[] { "Assassin", "Ninja" } 62 | }; 63 | 64 | if (comboBoxClass.SelectedIndex == -1) 65 | return; 66 | 67 | comboBoxSpecialization.Items.Clear(); 68 | comboBoxSpecialization.Items.AddRange(specializations[comboBoxClass.SelectedIndex]); 69 | 70 | comboBoxSpecialization.SelectedIndex = character.Specialization; 71 | } 72 | 73 | private void NudLevelValueChanged(object sender, EventArgs e) 74 | { 75 | nudPetLevel.Maximum = nudLevel.Value; 76 | nudExperience.Maximum = (decimal)(50 + 1000 * (1 - 1 / (((int)nudLevel.Value - 1) * 0.05 + 1))); 77 | } 78 | } 79 | } 80 | -------------------------------------------------------------------------------- /Source/Forms/Editor.Data.cs: -------------------------------------------------------------------------------- 1 | using System.Linq; 2 | using System.Windows.Forms; 3 | using CharacterEditor.Character; 4 | 5 | namespace CharacterEditor.Forms 6 | { 7 | public partial class Editor 8 | { 9 | private void SyncCharacterDataToGui() 10 | { 11 | textBoxName.Text = character.Name; 12 | nudLevel.Value = character.Level; 13 | nudExperience.Value = character.Experience; 14 | comboBoxGender.SelectedIndex = character.Gender; 15 | comboBoxRace.SelectedIndex = character.Race; 16 | comboBoxClass.SelectedIndex = (int)character.Class - 1; 17 | nudFace.Value = character.Face; 18 | nudHair.Value = character.Hair; 19 | 20 | buttonHairColor.BackColor = character.HairColor; 21 | 22 | nudPetMasterSkillLevel.Value = character.PetMasterSkillLevel; 23 | nudPetRidingSkillLevel.Value = character.PetRidingSkillLevel; 24 | nudClimbingSkillLevel.Value = character.ClimbingSkillLevel; 25 | nudHangGlidingSkillLevel.Value = character.HangGlidingSkillLevel; 26 | nudSwimmingSkillLevel.Value = character.SwimmingSkillLevel; 27 | nudSailingSkillLevel.Value = character.SailingSkillLevel; 28 | nudTierOneSkillLevel.Value = character.TierOneSkillLevel; 29 | nudTierTwoSkillLevel.Value = character.TierTwoSkillLevel; 30 | nudTierThreeSkillLevel.Value = character.TierThreeSkillLevel; 31 | 32 | for (int i = 0; i < Character.Character.EquipmentCount; ++i) 33 | { 34 | Item item = character.Equipment[i]; 35 | 36 | // Do not add unused and pet equipment 37 | if (i == 0 || i == 12) 38 | continue; 39 | 40 | TabPage tabPage = CreateEquipmentTab(i); 41 | tabPage.Tag = item; 42 | 43 | tabControlEquipment.TabPages.Add(tabPage); 44 | } 45 | 46 | Item petEquipment = character.Equipment.Last(); 47 | comboBoxPetKind.SelectedIndex = Utility.NormalizeIndex(petEquipment.Subtype, Constants.ItemSubtypes[(int)Constants.ItemType.Pets]) + 1; 48 | if (comboBoxPetKind.SelectedIndex == -1) 49 | comboBoxPetKind.SelectedIndex = 0; 50 | 51 | nudPetLevel.Value = petEquipment.Level; 52 | nudPetExperience.Value = petEquipment.Modifier; 53 | textBoxPetName.Text = petEquipment.Attributes.Aggregate("", (c, a) => c + (char)a.Material); 54 | 55 | nudCoinsGold.Value = (character.Coins / 10000) % 100; 56 | nudCoinsSilver.Value = (character.Coins / 100) % 100; 57 | nudCoinsCopper.Value = character.Coins % 100; 58 | nudCoinsPlatinum.Value = character.PlatinumCoins; 59 | 60 | // Sync inventory to GUI 61 | for (int i = 0; i < Character.Character.InventoryCount; ++i) 62 | { 63 | Inventory inventory = character.Inventories[i]; 64 | 65 | TabPage tabPage = new TabPage(new[] { "Equipment", "Items", "Ingredients", "Pets" }[i]); 66 | ListView listView = new ListView 67 | { 68 | Activation = ItemActivation.OneClick, 69 | BorderStyle = BorderStyle.None, 70 | Dock = DockStyle.Fill, 71 | HideSelection = false, 72 | LargeImageList = imageListInventory, 73 | MultiSelect = false, 74 | UseCompatibleStateImageBehavior = false 75 | }; 76 | 77 | // Ok .NET 2.0, have it your way 78 | listView.SelectedIndexChanged += ListViewInventorySelectedIndexChanged; 79 | 80 | foreach (Slot slot in inventory.Items) 81 | { 82 | ListViewItem listViewItem; 83 | 84 | if (slot.Count > 0 && slot.Item.Type != 0x00) 85 | { 86 | listViewItem = new ListViewItem 87 | { 88 | ImageIndex = slot.Item.Type, 89 | Text = slot.Item.FriendlyName, 90 | Tag = slot.Item 91 | }; 92 | } 93 | else 94 | { 95 | listViewItem = new ListViewItem 96 | { 97 | ImageIndex = 0, 98 | Text = "", 99 | Tag = slot.Item 100 | }; 101 | } 102 | 103 | listView.Items.Add(listViewItem); 104 | } 105 | 106 | tabPage.Controls.Add(listView); 107 | tabControlInventory.TabPages.Add(tabPage); 108 | } 109 | 110 | if (dirtyWatcher != null) 111 | dirtyWatcher.Dirty = false; 112 | } 113 | 114 | private void SyncGuiToCharacterData() 115 | { 116 | // TODO Shouldn't I be able to link all this with a DataModel? 117 | 118 | character.Name = textBoxName.Text; 119 | character.Level = (int)nudLevel.Value; 120 | character.Experience = (int)nudExperience.Value; 121 | character.Gender = (byte)comboBoxGender.SelectedIndex; 122 | character.Race = comboBoxRace.SelectedIndex; 123 | character.Class = (Character.Character.ClassType)(comboBoxClass.SelectedIndex + 1); 124 | character.Specialization = (byte)comboBoxSpecialization.SelectedIndex; 125 | character.Face = (int)nudFace.Value; 126 | character.Hair = (int)nudHair.Value; 127 | character.HairColor = buttonHairColor.BackColor; 128 | 129 | character.PetMasterSkillLevel = (int)nudPetMasterSkillLevel.Value; 130 | character.PetRidingSkillLevel = (int)nudPetRidingSkillLevel.Value; 131 | character.ClimbingSkillLevel = (int)nudClimbingSkillLevel.Value; 132 | character.HangGlidingSkillLevel = (int)nudHangGlidingSkillLevel.Value; 133 | character.SwimmingSkillLevel = (int)nudSwimmingSkillLevel.Value; 134 | character.SailingSkillLevel = (int)nudSailingSkillLevel.Value; 135 | character.TierOneSkillLevel = (int)nudTierOneSkillLevel.Value; 136 | character.TierTwoSkillLevel = (int)nudTierTwoSkillLevel.Value; 137 | character.TierThreeSkillLevel = (int)nudTierThreeSkillLevel.Value; 138 | 139 | character.Coins = (int)(nudCoinsGold.Value * 10000 + nudCoinsSilver.Value * 100 + nudCoinsCopper.Value); 140 | character.PlatinumCoins = (int)nudCoinsPlatinum.Value; 141 | 142 | Item petEquipment = character.Equipment.Last(); 143 | petEquipment.Type = (byte)(comboBoxPetKind.SelectedIndex <= 0 ? (int)Constants.ItemType.None : (int)Constants.ItemType.Pets); 144 | petEquipment.Subtype = (byte)Utility.GoofyIndex(comboBoxPetKind.SelectedIndex - 1, Constants.ItemSubtypes[(int)Constants.ItemType.Pets]); 145 | petEquipment.Level = (short)nudPetLevel.Value; 146 | // TODO Fix pets.......... 147 | //petEquipment.Modifier = (short)nudPetExperience.Value; 148 | 149 | for (int i = 0; i < textBoxPetName.Text.Length; ++i) 150 | petEquipment.Attributes[i].Material = (byte)textBoxPetName.Text[i]; 151 | 152 | dirtyWatcher.Dirty = false; 153 | } 154 | } 155 | } 156 | -------------------------------------------------------------------------------- /Source/Forms/Editor.Equipment.cs: -------------------------------------------------------------------------------- 1 | using System.Windows.Forms; 2 | 3 | namespace CharacterEditor.Forms 4 | { 5 | public partial class Editor 6 | { 7 | private TabPage CreateEquipmentTab(int i) 8 | { 9 | TabPage tabPage = 10 | new TabPage( 11 | new[] 12 | { 13 | "", "Neck", "Chest", "Feet", "Hands", "Shoulder Armor", "Left Weapon", "Right Weapon", "Left Ring", "Right Ring", 14 | "Light", "Special", "Pet" 15 | }[i]); 16 | 17 | ComboBox comboBoxEquipmentItemMaterial = new ComboBox 18 | { 19 | DropDownStyle = ComboBoxStyle.DropDownList, 20 | Location = new System.Drawing.Point(266, 32), 21 | Size = new System.Drawing.Size(124, 21) 22 | }; 23 | 24 | Label labelEquipmentItemMaterial = new Label 25 | { 26 | AutoSize = true, 27 | Location = new System.Drawing.Point(267, 16), 28 | Size = new System.Drawing.Size(47, 13), 29 | Text = "Material:" 30 | }; 31 | 32 | SafeNumericUpDown nudEquipmentItemLevel = new SafeNumericUpDown 33 | { 34 | Location = new System.Drawing.Point(136, 77), 35 | Maximum = 0x7FFF, 36 | Size = new System.Drawing.Size(124, 20) 37 | }; 38 | 39 | Label labelEquipmentItemLevel = new Label 40 | { 41 | AutoSize = true, 42 | Location = new System.Drawing.Point(133, 60), 43 | Size = new System.Drawing.Size(36, 13), 44 | Text = "Level:" 45 | }; 46 | 47 | ComboBox comboBoxEquipmentItemModifier = new ComboBox 48 | { 49 | DropDownStyle = ComboBoxStyle.DropDownList, 50 | Location = new System.Drawing.Point(136, 32), 51 | Size = new System.Drawing.Size(124, 21), 52 | }; 53 | 54 | //comboBoxEquipmentItemModifier.Items.AddRange(Constants.ItemModifiers[comboBoxItemRarity.SelectedIndex].Where(x => !String.IsNullOrEmpty(x)).ToArray()); 55 | 56 | Label labelEquipmentItemModifier = new Label 57 | { 58 | AutoSize = true, 59 | Location = new System.Drawing.Point(133, 16), 60 | Size = new System.Drawing.Size(47, 13), 61 | Text = "Modifier:" 62 | }; 63 | 64 | Label labelEquipmentItemSubtype = new Label 65 | { 66 | AutoSize = true, 67 | Location = new System.Drawing.Point(7, 60), 68 | Size = new System.Drawing.Size(49, 13), 69 | Text = "Subtype:" 70 | }; 71 | 72 | Label labelEquipmentItemType = new Label 73 | { 74 | AutoSize = true, 75 | Location = new System.Drawing.Point(6, 16), 76 | Size = new System.Drawing.Size(34, 13), 77 | Text = "Type:" 78 | }; 79 | 80 | ComboBox comboBoxEquipmentItemSubtype = new ComboBox 81 | { 82 | DropDownStyle = ComboBoxStyle.DropDownList, 83 | Location = new System.Drawing.Point(6, 76), 84 | Size = new System.Drawing.Size(124, 21) 85 | }; 86 | 87 | ComboBox comboBoxEquipmentItemType = new ComboBox 88 | { 89 | DropDownStyle = ComboBoxStyle.DropDownList, 90 | Location = new System.Drawing.Point(6, 32), 91 | Size = new System.Drawing.Size(124, 21) 92 | }; 93 | 94 | GroupBox groupBoxEquipmentItem = new GroupBox 95 | { 96 | Enabled = false, 97 | Location = new System.Drawing.Point(6, 6), 98 | Size = new System.Drawing.Size(522, 189), 99 | TabStop = false, 100 | Text = "Item" 101 | }; 102 | 103 | groupBoxEquipmentItem.Controls.AddRange(new Control[] 104 | { 105 | comboBoxEquipmentItemMaterial, 106 | labelEquipmentItemMaterial, 107 | nudEquipmentItemLevel, 108 | labelEquipmentItemLevel, 109 | comboBoxEquipmentItemModifier, 110 | labelEquipmentItemModifier, 111 | labelEquipmentItemSubtype, 112 | labelEquipmentItemType, 113 | comboBoxEquipmentItemSubtype, 114 | comboBoxEquipmentItemType 115 | }); 116 | 117 | tabPage.Controls.Add(groupBoxEquipmentItem); 118 | 119 | return tabPage; 120 | } 121 | } 122 | } 123 | -------------------------------------------------------------------------------- /Source/Forms/Editor.Inventory.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Linq; 3 | using System.Windows.Forms; 4 | using CharacterEditor.Character; 5 | 6 | namespace CharacterEditor.Forms 7 | { 8 | public partial class Editor 9 | { 10 | private Item SelectedItem 11 | { 12 | get 13 | { 14 | ListView listView = tabControlInventory.SelectedTab.Controls.OfType().FirstOrDefault(); 15 | if (listView == null || listView.SelectedItems.Count == 0) 16 | return null; 17 | 18 | return (Item)listView.SelectedItems[0].Tag; 19 | } 20 | } 21 | 22 | private Slot SelectedSlot 23 | { 24 | get 25 | { 26 | Inventory inventory = character.Inventories[tabControlInventory.SelectedIndex]; 27 | return inventory.Items.SingleOrDefault(t => t.Item == SelectedItem); 28 | } 29 | } 30 | 31 | // ListView Select 32 | private void ListViewInventorySelectedIndexChanged(object sender, EventArgs e) 33 | { 34 | if (SelectedItem == null) 35 | return; 36 | 37 | // Ignore dirtiness 38 | lock (dirtyWatcher) 39 | dirtyWatcher.IgnoreDirtiness = true; 40 | 41 | // Update controls if needed 42 | UpdateItemControls(); 43 | 44 | if (SelectedSlot.Count != 0) 45 | { 46 | // There's an item here, update controls 47 | comboBoxItemType.SelectedIndex = Utility.NormalizeIndex(SelectedItem.Type, Constants.ItemTypeNames); 48 | comboBoxItemSubtype.SelectedIndex = Utility.NormalizeIndex(SelectedItem.Subtype, Constants.ItemSubtypes[SelectedItem.Type]); 49 | comboBoxItemMaterial.SelectedIndex = Utility.NormalizeIndex(SelectedItem.Material, Constants.ItemMaterialNames); 50 | //if (SelectedItem.Modifier != 0) 51 | // comboBoxItemPrefixId.SelectedIndex = (SelectedItem.Modifier - 1) % 10 + 1; 52 | //else 53 | // comboBoxItemPrefixId.SelectedIndex = 0; 54 | 55 | comboBoxItemPrefixId.SelectedIndex = SelectedItem.PrefixId; 56 | nudItemModelId.Value = SelectedItem.ModelId; 57 | nudItemEffectId.Value = SelectedItem.EffectId; 58 | 59 | nudItemHP.Value = (decimal)SelectedItem.Life; 60 | nudItemArmor.Value = (decimal)SelectedItem.Armor; 61 | nudItemResistance.Value = (decimal)SelectedItem.Resistance; 62 | nudItemTempo.Value = (decimal)SelectedItem.Tempo; 63 | nudItemCrit.Value = (decimal)SelectedItem.Critical; 64 | nudItemReg.Value = (decimal)SelectedItem.Regeneration; 65 | 66 | nudItemLevel.Value = SelectedItem.Level; 67 | comboBoxItemRarity.SelectedIndex = SelectedItem.Rarity; 68 | checkBoxItemAdapted.Checked = SelectedItem.Flags.HasFlag(Item.ItemFlags.Adapted); 69 | nudItemCount.Value = SelectedSlot.Count; 70 | } 71 | else 72 | { 73 | // No item here, update controls 74 | comboBoxItemType.SelectedIndex = -1; 75 | comboBoxItemSubtype.SelectedIndex = -1; 76 | comboBoxItemMaterial.SelectedIndex = -1; 77 | comboBoxItemPrefixId.SelectedIndex = -1; 78 | nudItemLevel.Value = 0; 79 | comboBoxItemRarity.SelectedIndex = -1; 80 | checkBoxItemAdapted.Checked = false; 81 | nudItemCount.Value = 0; 82 | } 83 | 84 | // Stop ignoring dirtiness 85 | lock (dirtyWatcher) 86 | dirtyWatcher.IgnoreDirtiness = false; 87 | } 88 | 89 | // Type 90 | private void ComboBoxItemTypeSelectedIndexChanged(object sender, EventArgs e) 91 | { 92 | if (SelectedItem == null) 93 | return; 94 | 95 | if (comboBoxItemType.SelectedIndex == -1) 96 | comboBoxItemType.SelectedIndex = 0; 97 | 98 | SelectedItem.Type = (byte)Utility.GoofyIndex(comboBoxItemType.SelectedIndex, Constants.ItemTypeNames); 99 | 100 | int subtypeIndex = Utility.GoofyIndex(comboBoxItemType.SelectedIndex, Constants.ItemTypeNames); 101 | 102 | comboBoxItemSubtype.Items.Clear(); 103 | 104 | if (subtypeIndex <= 0) 105 | return; 106 | 107 | comboBoxItemSubtype.Items.AddRange(Constants.ItemSubtypes[subtypeIndex].Where(x => !String.IsNullOrEmpty(x)).ToArray()); 108 | comboBoxItemSubtype.SelectedIndex = 0; 109 | 110 | UpdateItemAvatar(); 111 | } 112 | 113 | // Subtype 114 | private void ComboBoxItemSubtypeSelectedIndexChanged(object sender, EventArgs e) 115 | { 116 | if (SelectedItem == null) 117 | return; 118 | 119 | SelectedItem.Subtype = (byte)Utility.GoofyIndex(comboBoxItemSubtype.SelectedIndex, 120 | Constants.ItemSubtypes[SelectedItem.Type]); 121 | UpdateItemAvatar(); 122 | } 123 | 124 | // Material 125 | private void ComboBoxItemMaterialSelectedIndexChanged(object sender, EventArgs e) 126 | { 127 | if (SelectedItem == null) 128 | return; 129 | 130 | SelectedItem.Material = (byte)Utility.GoofyIndex(comboBoxItemMaterial.SelectedIndex, Constants.ItemMaterialNames); 131 | UpdateItemAvatar(); 132 | } 133 | 134 | // Modifer 135 | private void ComboBoxItemModifierSelectedIndexChanged(object sender, EventArgs e) 136 | { 137 | if (SelectedItem == null) 138 | return; 139 | 140 | // TODO Magic code right here 141 | //int offset = 0; 142 | //int offsetInitial = ((SelectedItem.ActualModifier - 1) % 10 + 1); 143 | //if (comboBoxItemPrefixId.SelectedIndex != 0) 144 | // offset = comboBoxItemPrefixId.SelectedIndex - offsetInitial; 145 | 146 | //SelectedItem.Modifier = (short)(SelectedItem.ActualModifier + offset); 147 | UpdateItemAvatar(); 148 | } 149 | 150 | // Level 151 | private void NudItemLevelValueChanged(object sender, EventArgs e) 152 | { 153 | if (SelectedItem == null) 154 | return; 155 | 156 | SelectedItem.Level = (short)nudItemLevel.Value; 157 | UpdateItemAvatar(); 158 | } 159 | 160 | // Rarity 161 | private void ComboBoxItemRaritySelectedIndexChanged(object sender, EventArgs e) 162 | { 163 | if (SelectedItem == null || comboBoxItemRarity.SelectedIndex == -1) 164 | return; 165 | 166 | SelectedItem.Rarity = (byte)comboBoxItemRarity.SelectedIndex; 167 | 168 | string[] modifierList = (string[])Constants.ItemModifiers[SelectedItem.Rarity].Clone(); 169 | 170 | for (int i = 0; i < modifierList.Length; i++) 171 | { 172 | modifierList[i] = modifierList[i].Replace("{0}", "*"); 173 | modifierList[i] = modifierList[i].Replace("{1}", "*"); 174 | } 175 | 176 | int restoreIndex = comboBoxItemPrefixId.SelectedIndex; 177 | comboBoxItemPrefixId.Items.Clear(); 178 | comboBoxItemPrefixId.Items.Add("None"); 179 | comboBoxItemPrefixId.Items.AddRange(modifierList); 180 | comboBoxItemPrefixId.SelectedIndex = restoreIndex; 181 | } 182 | 183 | // Adapted 184 | private void CheckBoxItemAdaptedCheckedChanged(object sender, EventArgs e) 185 | { 186 | if (SelectedItem == null) 187 | return; 188 | 189 | if (checkBoxItemAdapted.Checked) 190 | SelectedItem.Flags |= Item.ItemFlags.Adapted; 191 | else 192 | SelectedItem.Flags &= ~Item.ItemFlags.Adapted; 193 | } 194 | 195 | // Item Count 196 | private void NudItemCountValueChanged(object sender, EventArgs e) 197 | { 198 | if (SelectedSlot == null) 199 | return; 200 | 201 | SelectedSlot.Count = (int)nudItemCount.Value; 202 | } 203 | 204 | private void UpdateItemAvatar() 205 | { 206 | if (SelectedSlot.Count == 0) 207 | return; 208 | 209 | ListView listView = tabControlInventory.SelectedTab.Controls.OfType().FirstOrDefault(); 210 | if (listView == null || listView.SelectedItems.Count == 0) 211 | return; 212 | 213 | ListViewItem selectedItem = listView.SelectedItems[0]; 214 | Item item = (Item)selectedItem.Tag; 215 | 216 | selectedItem.Text = item.FriendlyName; 217 | selectedItem.ImageIndex = item.Type; 218 | 219 | // TODO Might be somewhat out of place 220 | nudItemHP.Value = (decimal)SelectedItem.Life; 221 | nudItemArmor.Value = (decimal)SelectedItem.Armor; 222 | nudItemResistance.Value = (decimal)SelectedItem.Resistance; 223 | nudItemTempo.Value = (decimal)SelectedItem.Tempo; 224 | nudItemCrit.Value = (decimal)SelectedItem.Critical; 225 | nudItemReg.Value = (decimal)SelectedItem.Regeneration; 226 | } 227 | 228 | private void UpdateItemControls() 229 | { 230 | if (comboBoxItemType.Items.Count == 0) 231 | comboBoxItemType.Items.AddRange(Constants.ItemTypeNames.Where(x => !String.IsNullOrEmpty(x)).ToArray()); 232 | 233 | if (comboBoxItemMaterial.Items.Count == 0) 234 | comboBoxItemMaterial.Items.AddRange(Constants.ItemMaterialNames.Where(x => !String.IsNullOrEmpty(x)).ToArray()); 235 | 236 | if (comboBoxItemPrefixId.Items.Count == 0) 237 | { 238 | string[] modifierList = (string[])Constants.ItemModifiers[0].Clone(); 239 | //modifierList[0] = "None"; 240 | 241 | for (int i = 0; i < modifierList.Length; i++) 242 | { 243 | modifierList[i] = modifierList[i].Replace("{0}", null); 244 | modifierList[i] = modifierList[i].Replace("{1}", null); 245 | } 246 | 247 | comboBoxItemPrefixId.Items.Clear(); 248 | comboBoxItemPrefixId.Items.Add("None"); 249 | comboBoxItemPrefixId.Items.AddRange(modifierList); 250 | } 251 | 252 | if (comboBoxItemRarity.Items.Count == 0) 253 | comboBoxItemRarity.Items.AddRange(new object[] { "Normal", "Uncommon", "Rare", "Epic", "Legendary" }); 254 | } 255 | } 256 | } 257 | -------------------------------------------------------------------------------- /Source/Forms/Editor.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Diagnostics; 3 | using System.Linq; 4 | using System.Threading; 5 | using System.Windows.Forms; 6 | using CharacterEditor.Character; 7 | 8 | namespace CharacterEditor.Forms 9 | { 10 | public partial class Editor : Form 11 | { 12 | private readonly Database database; 13 | private Character.Character character; 14 | private DirtyWatcher dirtyWatcher; 15 | private Thread dirtyThread; 16 | private readonly FormItemStats itemStats; 17 | 18 | public Editor() 19 | { 20 | database = new Database(); 21 | itemStats = new FormItemStats(); 22 | 23 | InitializeComponent(); 24 | 25 | labelAboutEditorName.Text += " v" + Program.Version; 26 | 27 | comboBoxPetKind.Items.Add("None"); 28 | string[] pets = Constants.ItemSubtypes[(int)Constants.ItemType.Pets]; 29 | comboBoxPetKind.Items.AddRange(pets.Where(x => !String.IsNullOrEmpty(x)).ToArray()); 30 | } 31 | 32 | private void FormEditorShown(object sender, EventArgs e) 33 | { 34 | Text = "Character Editor v" + Program.Version; 35 | LoadCharacterDatabase(); 36 | 37 | if (character == null) 38 | { 39 | Close(); 40 | return; 41 | } 42 | 43 | dirtyWatcher = new DirtyWatcher(this); 44 | dirtyThread = new Thread(obj => 45 | { 46 | bool previousDirty = !dirtyWatcher.Dirty; 47 | 48 | while (!IsDisposed) 49 | { 50 | lock (dirtyWatcher) 51 | { 52 | if (dirtyWatcher.Dirty != previousDirty && !dirtyWatcher.IgnoreDirtiness) 53 | { 54 | string title = "Character Editor v" + Program.Version + " [" + character.Name + "]"; 55 | 56 | if (dirtyWatcher.Dirty) 57 | title += " *"; 58 | 59 | if (InvokeRequired) 60 | Invoke(new MethodInvoker(() => Text = title)); 61 | else 62 | Text = title; 63 | 64 | previousDirty = dirtyWatcher.Dirty; 65 | } 66 | else if (dirtyWatcher.IgnoreDirtiness) 67 | dirtyWatcher.Dirty = false; 68 | } 69 | 70 | Thread.Sleep(1); 71 | } 72 | }); 73 | 74 | dirtyThread.Start(); 75 | } 76 | 77 | private void FormEditorClosing(object sender, FormClosingEventArgs e) 78 | { 79 | if (dirtyWatcher == null || !dirtyWatcher.Dirty) 80 | return; 81 | 82 | DialogResult result = MessageBox.Show(this, "Would you like to save changes before closing?", "Character Editor", 83 | MessageBoxButtons.YesNoCancel, MessageBoxIcon.Question); 84 | switch (result) 85 | { 86 | case DialogResult.Yes: 87 | SyncGuiToCharacterData(); 88 | character.Save(database); 89 | break; 90 | 91 | case DialogResult.No: 92 | break; 93 | 94 | case DialogResult.Cancel: 95 | e.Cancel = true; 96 | return; 97 | } 98 | 99 | dirtyThread.Abort(); 100 | } 101 | 102 | private void ButtonSaveCharacterClick(object sender, EventArgs e) 103 | { 104 | SyncGuiToCharacterData(); 105 | 106 | try 107 | { 108 | if (!character.Save(database)) 109 | MessageBox.Show(this, "Something went wrong trying to save your character to the database.", "Character Editor", 110 | MessageBoxButtons.OK); 111 | } 112 | catch (System.Data.SQLite.SQLiteException) 113 | { 114 | MessageBox.Show(this, 115 | "Cannot save because the database is currently read only.\r\nTry running the editor as Administrator.", 116 | "Character Editor", 117 | MessageBoxButtons.OK, MessageBoxIcon.Error); 118 | } 119 | } 120 | 121 | private void ButtonLoadNewCharacterClick(object sender, EventArgs e) 122 | { 123 | if (dirtyWatcher.Dirty) 124 | { 125 | DialogResult result = MessageBox.Show(this, "Would you like to save changes before loading a new character?", "Character Editor", 126 | MessageBoxButtons.YesNoCancel, MessageBoxIcon.Question); 127 | switch (result) 128 | { 129 | case DialogResult.Yes: 130 | SyncGuiToCharacterData(); 131 | character.Save(database); 132 | break; 133 | 134 | case DialogResult.No: 135 | break; 136 | 137 | case DialogResult.Cancel: 138 | return; 139 | } 140 | } 141 | 142 | LoadCharacterDatabase(); 143 | } 144 | 145 | private void LoadCharacterDatabase() 146 | { 147 | Enabled = false; 148 | 149 | LoadCharacterDialog loadCharacter = new LoadCharacterDialog(database) 150 | { 151 | StartPosition = FormStartPosition.CenterParent 152 | }; 153 | 154 | DialogResult result = loadCharacter.ShowDialog(this); 155 | 156 | if (result == DialogResult.OK) 157 | { 158 | tabControlInventory.TabPages.Clear(); 159 | tabControlEquipment.TabPages.Clear(); 160 | 161 | character = loadCharacter.SelectedCharacter; 162 | 163 | SyncCharacterDataToGui(); 164 | } 165 | 166 | Enabled = character != null; 167 | } 168 | 169 | private void LinkLabelX2048LinkClicked(object sender, LinkLabelLinkClickedEventArgs e) 170 | { 171 | Process.Start("http://www.x2048.com/"); 172 | } 173 | 174 | private void ButtonViewStatsClick(object sender, EventArgs e) 175 | { 176 | itemStats.Show(); 177 | } 178 | } 179 | } 180 | -------------------------------------------------------------------------------- /Source/Forms/ExceptionDialog.Designer.cs: -------------------------------------------------------------------------------- 1 | namespace CharacterEditor.Forms 2 | { 3 | partial class ExceptionDialog 4 | { 5 | /// 6 | /// Required designer variable. 7 | /// 8 | private System.ComponentModel.IContainer components = null; 9 | 10 | /// 11 | /// Clean up any resources being used. 12 | /// 13 | /// true if managed resources should be disposed; otherwise, false. 14 | protected override void Dispose(bool disposing) 15 | { 16 | if (disposing && (components != null)) 17 | { 18 | components.Dispose(); 19 | } 20 | base.Dispose(disposing); 21 | } 22 | 23 | #region Windows Form Designer generated code 24 | 25 | /// 26 | /// Required method for Designer support - do not modify 27 | /// the contents of this method with the code editor. 28 | /// 29 | private void InitializeComponent() 30 | { 31 | System.ComponentModel.ComponentResourceManager resources = new System.ComponentModel.ComponentResourceManager(typeof(ExceptionDialog)); 32 | this.labelExceptionMessage = new System.Windows.Forms.Label(); 33 | this.buttonClose = new System.Windows.Forms.Button(); 34 | this.textBoxExceptionInformation = new System.Windows.Forms.TextBox(); 35 | this.labelStackTrace = new System.Windows.Forms.Label(); 36 | this.buttonCopyToClipboard = new System.Windows.Forms.Button(); 37 | this.labelHelpMessage = new System.Windows.Forms.Label(); 38 | this.buttonContinue = new System.Windows.Forms.Button(); 39 | this.SuspendLayout(); 40 | // 41 | // labelExceptionMessage 42 | // 43 | this.labelExceptionMessage.AutoSize = true; 44 | this.labelExceptionMessage.Location = new System.Drawing.Point(12, 58); 45 | this.labelExceptionMessage.Name = "labelExceptionMessage"; 46 | this.labelExceptionMessage.Size = new System.Drawing.Size(94, 13); 47 | this.labelExceptionMessage.TabIndex = 0; 48 | this.labelExceptionMessage.Text = "General Exception"; 49 | // 50 | // buttonClose 51 | // 52 | this.buttonClose.Location = new System.Drawing.Point(537, 407); 53 | this.buttonClose.Name = "buttonClose"; 54 | this.buttonClose.Size = new System.Drawing.Size(75, 23); 55 | this.buttonClose.TabIndex = 1; 56 | this.buttonClose.Text = "Close"; 57 | this.buttonClose.UseVisualStyleBackColor = true; 58 | this.buttonClose.Click += new System.EventHandler(this.ButtonCloseClick); 59 | // 60 | // textBoxExceptionInformation 61 | // 62 | this.textBoxExceptionInformation.Location = new System.Drawing.Point(12, 87); 63 | this.textBoxExceptionInformation.Multiline = true; 64 | this.textBoxExceptionInformation.Name = "textBoxExceptionInformation"; 65 | this.textBoxExceptionInformation.ReadOnly = true; 66 | this.textBoxExceptionInformation.ScrollBars = System.Windows.Forms.ScrollBars.Both; 67 | this.textBoxExceptionInformation.Size = new System.Drawing.Size(600, 314); 68 | this.textBoxExceptionInformation.TabIndex = 2; 69 | // 70 | // labelStackTrace 71 | // 72 | this.labelStackTrace.AutoSize = true; 73 | this.labelStackTrace.Location = new System.Drawing.Point(12, 71); 74 | this.labelStackTrace.Name = "labelStackTrace"; 75 | this.labelStackTrace.Size = new System.Drawing.Size(69, 13); 76 | this.labelStackTrace.TabIndex = 3; 77 | this.labelStackTrace.Text = "Stack Trace:"; 78 | // 79 | // buttonCopyToClipboard 80 | // 81 | this.buttonCopyToClipboard.Location = new System.Drawing.Point(337, 407); 82 | this.buttonCopyToClipboard.Name = "buttonCopyToClipboard"; 83 | this.buttonCopyToClipboard.Size = new System.Drawing.Size(113, 23); 84 | this.buttonCopyToClipboard.TabIndex = 4; 85 | this.buttonCopyToClipboard.Text = "Copy to Clipboard"; 86 | this.buttonCopyToClipboard.UseVisualStyleBackColor = true; 87 | this.buttonCopyToClipboard.Click += new System.EventHandler(this.ButtonCopyToClipboardClick); 88 | // 89 | // labelHelpMessage 90 | // 91 | this.labelHelpMessage.AutoSize = true; 92 | this.labelHelpMessage.Location = new System.Drawing.Point(12, 9); 93 | this.labelHelpMessage.Name = "labelHelpMessage"; 94 | this.labelHelpMessage.Size = new System.Drawing.Size(393, 39); 95 | this.labelHelpMessage.TabIndex = 5; 96 | this.labelHelpMessage.Text = resources.GetString("labelHelpMessage.Text"); 97 | // 98 | // buttonContinue 99 | // 100 | this.buttonContinue.Location = new System.Drawing.Point(456, 407); 101 | this.buttonContinue.Name = "buttonContinue"; 102 | this.buttonContinue.Size = new System.Drawing.Size(75, 23); 103 | this.buttonContinue.TabIndex = 6; 104 | this.buttonContinue.Text = "Continue"; 105 | this.buttonContinue.UseVisualStyleBackColor = true; 106 | this.buttonContinue.Click += new System.EventHandler(this.ButtonContinueClick); 107 | // 108 | // ExceptionDialog 109 | // 110 | this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F); 111 | this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font; 112 | this.ClientSize = new System.Drawing.Size(624, 442); 113 | this.Controls.Add(this.buttonContinue); 114 | this.Controls.Add(this.labelHelpMessage); 115 | this.Controls.Add(this.buttonCopyToClipboard); 116 | this.Controls.Add(this.labelStackTrace); 117 | this.Controls.Add(this.textBoxExceptionInformation); 118 | this.Controls.Add(this.buttonClose); 119 | this.Controls.Add(this.labelExceptionMessage); 120 | this.FormBorderStyle = System.Windows.Forms.FormBorderStyle.FixedDialog; 121 | this.MaximizeBox = false; 122 | this.MinimizeBox = false; 123 | this.Name = "ExceptionDialog"; 124 | this.Text = "Character Editor Exception Occurred"; 125 | this.FormClosed += new System.Windows.Forms.FormClosedEventHandler(this.FormExceptionClosed); 126 | this.ResumeLayout(false); 127 | this.PerformLayout(); 128 | 129 | } 130 | 131 | #endregion 132 | 133 | private System.Windows.Forms.Label labelExceptionMessage; 134 | private System.Windows.Forms.Button buttonClose; 135 | private System.Windows.Forms.TextBox textBoxExceptionInformation; 136 | private System.Windows.Forms.Label labelStackTrace; 137 | private System.Windows.Forms.Button buttonCopyToClipboard; 138 | private System.Windows.Forms.Label labelHelpMessage; 139 | private System.Windows.Forms.Button buttonContinue; 140 | } 141 | } -------------------------------------------------------------------------------- /Source/Forms/ExceptionDialog.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Text; 3 | using System.Windows.Forms; 4 | 5 | namespace CharacterEditor.Forms 6 | { 7 | public partial class ExceptionDialog : Form 8 | { 9 | public ExceptionDialog(string humanMessage, Exception exception) 10 | { 11 | InitializeComponent(); 12 | 13 | labelExceptionMessage.Text = humanMessage; 14 | 15 | StringBuilder message = new StringBuilder(); 16 | 17 | message.AppendLine(exception.Message); 18 | message.AppendLine(); 19 | message.AppendLine(exception.Source); 20 | message.AppendLine(exception.StackTrace); 21 | 22 | textBoxExceptionInformation.Text = message.ToString(); 23 | } 24 | 25 | private void ButtonCloseClick(object sender, EventArgs e) 26 | { 27 | Application.Exit(); 28 | } 29 | 30 | private void ButtonCopyToClipboardClick(object sender, EventArgs e) 31 | { 32 | Clipboard.SetText(textBoxExceptionInformation.Text); 33 | } 34 | 35 | private void ButtonContinueClick(object sender, EventArgs e) 36 | { 37 | DialogResult = DialogResult.OK; 38 | Close(); 39 | } 40 | 41 | private void FormExceptionClosed(object sender, FormClosedEventArgs e) 42 | { 43 | if (DialogResult != DialogResult.OK) 44 | Application.Exit(); 45 | } 46 | } 47 | } 48 | -------------------------------------------------------------------------------- /Source/Forms/ExceptionDialog.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 | Character Editor has encountered a problem and may not be able to continue. 122 | You can either choose to end the program now, or attempt to continue. 123 | Be warned that attempting to continue running the program may result in data loss. 124 | 125 | -------------------------------------------------------------------------------- /Source/Forms/FormItemStats.Designer.cs: -------------------------------------------------------------------------------- 1 | namespace CharacterEditor.Forms 2 | { 3 | partial class FormItemStats 4 | { 5 | /// 6 | /// Required designer variable. 7 | /// 8 | private System.ComponentModel.IContainer components = null; 9 | 10 | /// 11 | /// Clean up any resources being used. 12 | /// 13 | /// true if managed resources should be disposed; otherwise, false. 14 | protected override void Dispose(bool disposing) 15 | { 16 | if (disposing && (components != null)) 17 | { 18 | components.Dispose(); 19 | } 20 | base.Dispose(disposing); 21 | } 22 | 23 | #region Windows Form Designer generated code 24 | 25 | /// 26 | /// Required method for Designer support - do not modify 27 | /// the contents of this method with the code editor. 28 | /// 29 | private void InitializeComponent() 30 | { 31 | System.ComponentModel.ComponentResourceManager resources = new System.ComponentModel.ComponentResourceManager(typeof(FormItemStats)); 32 | this.labelDamage = new System.Windows.Forms.Label(); 33 | this.labelAmor = new System.Windows.Forms.Label(); 34 | this.labelResistance = new System.Windows.Forms.Label(); 35 | this.labelTempo = new System.Windows.Forms.Label(); 36 | this.labelCritical = new System.Windows.Forms.Label(); 37 | this.labelRegeneration = new System.Windows.Forms.Label(); 38 | this.labelHP = new System.Windows.Forms.Label(); 39 | this.SuspendLayout(); 40 | // 41 | // labelDamage 42 | // 43 | this.labelDamage.AutoSize = true; 44 | this.labelDamage.Location = new System.Drawing.Point(12, 22); 45 | this.labelDamage.Name = "labelDamage"; 46 | this.labelDamage.Size = new System.Drawing.Size(47, 13); 47 | this.labelDamage.TabIndex = 0; 48 | this.labelDamage.Text = "Damage"; 49 | // 50 | // labelAmor 51 | // 52 | this.labelAmor.AutoSize = true; 53 | this.labelAmor.Location = new System.Drawing.Point(12, 37); 54 | this.labelAmor.Name = "labelAmor"; 55 | this.labelAmor.Size = new System.Drawing.Size(34, 13); 56 | this.labelAmor.TabIndex = 1; 57 | this.labelAmor.Text = "Armor"; 58 | // 59 | // labelResistance 60 | // 61 | this.labelResistance.AutoSize = true; 62 | this.labelResistance.Location = new System.Drawing.Point(12, 50); 63 | this.labelResistance.Name = "labelResistance"; 64 | this.labelResistance.Size = new System.Drawing.Size(60, 13); 65 | this.labelResistance.TabIndex = 2; 66 | this.labelResistance.Text = "Resistance"; 67 | // 68 | // labelTempo 69 | // 70 | this.labelTempo.AutoSize = true; 71 | this.labelTempo.Location = new System.Drawing.Point(12, 63); 72 | this.labelTempo.Name = "labelTempo"; 73 | this.labelTempo.Size = new System.Drawing.Size(40, 13); 74 | this.labelTempo.TabIndex = 3; 75 | this.labelTempo.Text = "Tempo"; 76 | // 77 | // labelCritical 78 | // 79 | this.labelCritical.AutoSize = true; 80 | this.labelCritical.Location = new System.Drawing.Point(12, 76); 81 | this.labelCritical.Name = "labelCritical"; 82 | this.labelCritical.Size = new System.Drawing.Size(38, 13); 83 | this.labelCritical.TabIndex = 4; 84 | this.labelCritical.Text = "Critical"; 85 | // 86 | // labelRegeneration 87 | // 88 | this.labelRegeneration.AutoSize = true; 89 | this.labelRegeneration.Location = new System.Drawing.Point(12, 89); 90 | this.labelRegeneration.Name = "labelRegeneration"; 91 | this.labelRegeneration.Size = new System.Drawing.Size(71, 13); 92 | this.labelRegeneration.TabIndex = 5; 93 | this.labelRegeneration.Text = "Regeneration"; 94 | // 95 | // labelHP 96 | // 97 | this.labelHP.AutoSize = true; 98 | this.labelHP.Location = new System.Drawing.Point(15, 6); 99 | this.labelHP.Name = "labelHP"; 100 | this.labelHP.Size = new System.Drawing.Size(22, 13); 101 | this.labelHP.TabIndex = 6; 102 | this.labelHP.Text = "HP"; 103 | // 104 | // FormItemStats 105 | // 106 | this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F); 107 | this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font; 108 | this.ClientSize = new System.Drawing.Size(356, 215); 109 | this.Controls.Add(this.labelHP); 110 | this.Controls.Add(this.labelRegeneration); 111 | this.Controls.Add(this.labelCritical); 112 | this.Controls.Add(this.labelTempo); 113 | this.Controls.Add(this.labelResistance); 114 | this.Controls.Add(this.labelAmor); 115 | this.Controls.Add(this.labelDamage); 116 | this.FormBorderStyle = System.Windows.Forms.FormBorderStyle.FixedDialog; 117 | this.Icon = ((System.Drawing.Icon)(resources.GetObject("$this.Icon"))); 118 | this.MaximizeBox = false; 119 | this.MinimizeBox = false; 120 | this.Name = "FormItemStats"; 121 | this.ShowInTaskbar = false; 122 | this.Text = "Item Stats"; 123 | this.ResumeLayout(false); 124 | this.PerformLayout(); 125 | 126 | } 127 | 128 | #endregion 129 | 130 | private System.Windows.Forms.Label labelDamage; 131 | private System.Windows.Forms.Label labelAmor; 132 | private System.Windows.Forms.Label labelResistance; 133 | private System.Windows.Forms.Label labelTempo; 134 | private System.Windows.Forms.Label labelCritical; 135 | private System.Windows.Forms.Label labelRegeneration; 136 | private System.Windows.Forms.Label labelHP; 137 | } 138 | } -------------------------------------------------------------------------------- /Source/Forms/FormItemStats.cs: -------------------------------------------------------------------------------- 1 | using System.Windows.Forms; 2 | 3 | namespace CharacterEditor.Forms 4 | { 5 | public partial class FormItemStats : Form 6 | { 7 | public FormItemStats() 8 | { 9 | InitializeComponent(); 10 | } 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /Source/Forms/LoadCharacterDialog.Designer.cs: -------------------------------------------------------------------------------- 1 | namespace CharacterEditor.Forms 2 | { 3 | partial class LoadCharacterDialog 4 | { 5 | /// 6 | /// Required designer variable. 7 | /// 8 | private System.ComponentModel.IContainer components = null; 9 | 10 | /// 11 | /// Clean up any resources being used. 12 | /// 13 | /// true if managed resources should be disposed; otherwise, false. 14 | protected override void Dispose(bool disposing) 15 | { 16 | if (disposing && (components != null)) 17 | { 18 | components.Dispose(); 19 | } 20 | base.Dispose(disposing); 21 | } 22 | 23 | #region Windows Form Designer generated code 24 | 25 | /// 26 | /// Required method for Designer support - do not modify 27 | /// the contents of this method with the code editor. 28 | /// 29 | private void InitializeComponent() 30 | { 31 | System.ComponentModel.ComponentResourceManager resources = new System.ComponentModel.ComponentResourceManager(typeof(LoadCharacterDialog)); 32 | this.buttonLoadDatabase = new System.Windows.Forms.Button(); 33 | this.listBoxCharacters = new System.Windows.Forms.ListBox(); 34 | this.SuspendLayout(); 35 | // 36 | // buttonLoadDatabase 37 | // 38 | this.buttonLoadDatabase.Location = new System.Drawing.Point(361, 247); 39 | this.buttonLoadDatabase.Name = "buttonLoadDatabase"; 40 | this.buttonLoadDatabase.Size = new System.Drawing.Size(101, 23); 41 | this.buttonLoadDatabase.TabIndex = 1; 42 | this.buttonLoadDatabase.Text = "Load Database"; 43 | this.buttonLoadDatabase.UseVisualStyleBackColor = true; 44 | this.buttonLoadDatabase.Click += new System.EventHandler(this.ButtonLoadDatabaseClick); 45 | // 46 | // listBoxCharacters 47 | // 48 | this.listBoxCharacters.FormattingEnabled = true; 49 | this.listBoxCharacters.Location = new System.Drawing.Point(12, 12); 50 | this.listBoxCharacters.Name = "listBoxCharacters"; 51 | this.listBoxCharacters.ScrollAlwaysVisible = true; 52 | this.listBoxCharacters.Size = new System.Drawing.Size(450, 225); 53 | this.listBoxCharacters.TabIndex = 0; 54 | this.listBoxCharacters.SelectedIndexChanged += new System.EventHandler(this.ListBoxCharactersSelectedIndexChanged); 55 | // 56 | // LoadCharacterDialog 57 | // 58 | this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F); 59 | this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font; 60 | this.ClientSize = new System.Drawing.Size(474, 282); 61 | this.Controls.Add(this.listBoxCharacters); 62 | this.Controls.Add(this.buttonLoadDatabase); 63 | this.FormBorderStyle = System.Windows.Forms.FormBorderStyle.FixedDialog; 64 | this.Icon = ((System.Drawing.Icon)(resources.GetObject("$this.Icon"))); 65 | this.MaximizeBox = false; 66 | this.MinimizeBox = false; 67 | this.Name = "LoadCharacterDialog"; 68 | this.ShowInTaskbar = false; 69 | this.Text = "Load a Character"; 70 | this.Load += new System.EventHandler(this.FormLoadCharacterLoad); 71 | this.ResumeLayout(false); 72 | 73 | } 74 | 75 | #endregion 76 | 77 | private System.Windows.Forms.Button buttonLoadDatabase; 78 | private System.Windows.Forms.ListBox listBoxCharacters; 79 | } 80 | } 81 | 82 | -------------------------------------------------------------------------------- /Source/Forms/LoadCharacterDialog.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.IO; 4 | using System.Windows.Forms; 5 | using Microsoft.Win32; 6 | 7 | namespace CharacterEditor.Forms 8 | { 9 | public partial class LoadCharacterDialog : Form 10 | { 11 | // TODO Backup database just in case 12 | // TODO Add character delete and add? 13 | // TODO Add character.db merging? 14 | 15 | public List Characters { get; private set; } 16 | public Character.Character SelectedCharacter { get; private set; } 17 | private readonly Database database; 18 | 19 | public LoadCharacterDialog(Database database) 20 | { 21 | Characters = new List(); 22 | this.database = database; 23 | SelectedCharacter = null; 24 | 25 | InitializeComponent(); 26 | } 27 | 28 | private void FormLoadCharacterLoad(object sender, EventArgs e) 29 | { 30 | string databasePath = FindCubeWorldDirectory(); 31 | if (!String.IsNullOrEmpty(databasePath) && File.Exists(databasePath + @"\characters.db")) 32 | DatabaseLoad(databasePath + @"\characters.db"); 33 | } 34 | 35 | private void ButtonLoadDatabaseClick(object sender, EventArgs e) 36 | { 37 | OpenFileDialog dialog = new OpenFileDialog 38 | { 39 | InitialDirectory = Environment.GetFolderPath(Environment.SpecialFolder.ProgramFilesX86), 40 | Filter = "Database|characters.db", 41 | CheckFileExists = true, 42 | CheckPathExists = true 43 | }; 44 | 45 | DialogResult result = dialog.ShowDialog(this); 46 | if (result == DialogResult.Cancel) 47 | return; 48 | 49 | DatabaseLoad(dialog.FileName); 50 | } 51 | 52 | private void ListBoxCharactersSelectedIndexChanged(object sender, EventArgs e) 53 | { 54 | if (listBoxCharacters.SelectedIndex < 0 || listBoxCharacters.SelectedIndex >= Characters.Count) 55 | return; 56 | 57 | SelectedCharacter = Characters[listBoxCharacters.SelectedIndex]; 58 | DialogResult = DialogResult.OK; 59 | Close(); 60 | } 61 | 62 | private void DatabaseLoad(string filename) 63 | { 64 | try 65 | { 66 | database.Load(filename); 67 | } 68 | catch (Exception e) 69 | { 70 | ExceptionDialog exceptionDialog = new ExceptionDialog("Database appears to be corrupted!", e); 71 | exceptionDialog.ShowDialog(this); 72 | 73 | return; 74 | } 75 | 76 | Characters.Clear(); 77 | listBoxCharacters.Items.Clear(); 78 | 79 | try 80 | { 81 | int characterCount = database.ReadBlobByKey("num")[0]; 82 | for (int i = 0; i < characterCount; ++i) 83 | { 84 | Character.Character character = new Character.Character(i); 85 | character.Load(database); 86 | 87 | Characters.Add(character); 88 | listBoxCharacters.Items.Add(character.Name); 89 | } 90 | } 91 | catch (Exception e) 92 | { 93 | ExceptionDialog exceptionDialog = new ExceptionDialog("Database appears to be corrupted!", e); 94 | exceptionDialog.ShowDialog(this); 95 | 96 | Characters.Clear(); 97 | listBoxCharacters.Items.Clear(); 98 | } 99 | } 100 | 101 | private string FindCubeWorldDirectory() 102 | { 103 | const string CubeWorldSaveDirectory = @"\Cube World\Save"; 104 | 105 | // Check if it exists in Registry 106 | string registryPath = FindCubeWorldDirectoryFromRegistry(); 107 | if (!String.IsNullOrEmpty(registryPath)) 108 | return registryPath; 109 | 110 | // Check if it exists in Program Files (32bit) 111 | string programFiles = Environment.GetFolderPath(Environment.SpecialFolder.ProgramFilesX86); 112 | if (Directory.Exists(programFiles + CubeWorldSaveDirectory)) 113 | return programFiles + CubeWorldSaveDirectory; 114 | 115 | // Check if it exists on the Desktop 116 | string desktop = Environment.GetFolderPath(Environment.SpecialFolder.DesktopDirectory); 117 | if (Directory.Exists(desktop + CubeWorldSaveDirectory)) 118 | return desktop + CubeWorldSaveDirectory; 119 | 120 | // Can't find it 121 | return String.Empty; 122 | } 123 | 124 | // Credit to Ricowan 125 | private string FindCubeWorldDirectoryFromRegistry() 126 | { 127 | // Look in 64bit local machine 128 | RegistryKey key = Registry.LocalMachine.OpenSubKey(@"SOFTWARE\Wow6432Node\Microsoft\Windows\CurrentVersion\Uninstall"); 129 | if (key != null) 130 | { 131 | foreach (String keyName in key.GetSubKeyNames()) 132 | { 133 | RegistryKey subKey = key.OpenSubKey(keyName); 134 | if (subKey == null) 135 | continue; 136 | 137 | string displayName = (string)subKey.GetValue("DisplayName"); 138 | 139 | if (!String.IsNullOrEmpty(displayName) && displayName.StartsWith("Cube World")) 140 | return subKey.GetValue("InstallLocation") + @"\Save"; 141 | } 142 | } 143 | 144 | // Look in 32bit local machine 145 | key = Registry.LocalMachine.OpenSubKey(@"SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall"); 146 | if (key != null) 147 | { 148 | foreach (String keyName in key.GetSubKeyNames()) 149 | { 150 | RegistryKey subKey = key.OpenSubKey(keyName); 151 | if (subKey == null) 152 | continue; 153 | 154 | string displayName = (string)subKey.GetValue("DisplayName"); 155 | 156 | if (!String.IsNullOrEmpty(displayName) && displayName.StartsWith("Cube World")) 157 | return subKey.GetValue("InstallLocation") + @"\Save"; 158 | } 159 | } 160 | 161 | // Look in CurrentUser 162 | key = Registry.CurrentUser.OpenSubKey(@"SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall"); 163 | if (key != null) 164 | { 165 | foreach (string keyName in key.GetSubKeyNames()) 166 | { 167 | RegistryKey subKey = key.OpenSubKey(keyName); 168 | if (subKey == null) 169 | continue; 170 | 171 | string displayName = (string)subKey.GetValue("DisplayName"); 172 | 173 | if (!String.IsNullOrEmpty(displayName) && displayName.StartsWith("Cube World")) 174 | return subKey.GetValue("InstallLocation") + @"\Save"; 175 | } 176 | } 177 | 178 | // Cannot find it 179 | return String.Empty; 180 | } 181 | } 182 | } 183 | -------------------------------------------------------------------------------- /Source/Forms/SafeNumericUpDown.cs: -------------------------------------------------------------------------------- 1 | using System.Windows.Forms; 2 | 3 | namespace CharacterEditor.Forms 4 | { 5 | public class SafeNumericUpDown : NumericUpDown 6 | { 7 | public new decimal Value 8 | { 9 | get 10 | { 11 | return base.Value; 12 | } 13 | 14 | set 15 | { 16 | if (value < Minimum) 17 | base.Value = Minimum; 18 | else if (value > Maximum) 19 | base.Value = Maximum; 20 | else 21 | base.Value = value; 22 | } 23 | } 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /Source/Program.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Diagnostics; 3 | using System.Windows.Forms; 4 | using CharacterEditor.Forms; 5 | 6 | namespace CharacterEditor 7 | { 8 | public static class Program 9 | { 10 | public const string Version = "0.4c"; 11 | 12 | [STAThread] 13 | public static void Main() 14 | { 15 | Application.EnableVisualStyles(); 16 | Application.SetCompatibleTextRenderingDefault(false); 17 | 18 | #if !DEBUG 19 | AppDomain.CurrentDomain.UnhandledException += (sender, args) => 20 | { 21 | Exception exception = (Exception)args.ExceptionObject; 22 | 23 | ExceptionDialog formException = new ExceptionDialog("An unrecoverable problem has occurred!", exception); 24 | formException.ShowDialog(); 25 | 26 | if (args.IsTerminating) 27 | Application.Exit(); 28 | }; 29 | 30 | if (Process.GetProcessesByName("Cube").Length > 0) 31 | { 32 | MessageBox.Show("Please close Cube World before running the Character Editor.", "Character Editor", MessageBoxButtons.OK, MessageBoxIcon.Error); 33 | return; 34 | } 35 | #endif 36 | 37 | Application.Run(new Editor()); 38 | } 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /Source/Properties/AssemblyInfo.cs: -------------------------------------------------------------------------------- 1 | using System.Reflection; 2 | using System.Runtime.InteropServices; 3 | 4 | // General Information about an assembly is controlled through the following 5 | // set of attributes. Change these attribute values to modify the information 6 | // associated with an assembly. 7 | [assembly: AssemblyTitle("CharacterEditor")] 8 | [assembly: AssemblyDescription("Character Editor for Cube World")] 9 | [assembly: AssemblyConfiguration("")] 10 | [assembly: AssemblyCompany("x2048")] 11 | [assembly: AssemblyProduct("CharacterEditor")] 12 | [assembly: AssemblyCopyright("Copyright © x2048 2013")] 13 | [assembly: AssemblyTrademark("")] 14 | [assembly: AssemblyCulture("")] 15 | 16 | // Setting ComVisible to false makes the types in this assembly not visible 17 | // to COM components. If you need to access a type in this assembly from 18 | // COM, set the ComVisible attribute to true on that type. 19 | [assembly: ComVisible(false)] 20 | 21 | // The following GUID is for the ID of the typelib if this project is exposed to COM 22 | [assembly: Guid("f35557de-dcc5-49e9-af49-ddde49bb1302")] 23 | 24 | // Version information for an assembly consists of the following four values: 25 | // 26 | // Major Version 27 | // Minor Version 28 | // Build Number 29 | // Revision 30 | // 31 | // You can specify all the values or you can default the Build and Revision Numbers 32 | // by using the '*' as shown below: 33 | // [assembly: AssemblyVersion("1.0.*")] 34 | [assembly: AssemblyVersion("1.0.0.0")] 35 | [assembly: AssemblyFileVersion("1.0.0.0")] 36 | -------------------------------------------------------------------------------- /Source/Properties/Resources.Designer.cs: -------------------------------------------------------------------------------- 1 | //------------------------------------------------------------------------------ 2 | // 3 | // This code was generated by a tool. 4 | // Runtime Version:4.0.30319.18052 5 | // 6 | // Changes to this file may cause incorrect behavior and will be lost if 7 | // the code is regenerated. 8 | // 9 | //------------------------------------------------------------------------------ 10 | 11 | namespace CharacterEditor.Properties { 12 | using System; 13 | 14 | 15 | /// 16 | /// A strongly-typed resource class, for looking up localized strings, etc. 17 | /// 18 | // This class was auto-generated by the StronglyTypedResourceBuilder 19 | // class via a tool like ResGen or Visual Studio. 20 | // To add or remove a member, edit your .ResX file then rerun ResGen 21 | // with the /str option, or rebuild your VS project. 22 | [global::System.CodeDom.Compiler.GeneratedCodeAttribute("System.Resources.Tools.StronglyTypedResourceBuilder", "4.0.0.0")] 23 | [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] 24 | [global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()] 25 | internal class Resources { 26 | 27 | private static global::System.Resources.ResourceManager resourceMan; 28 | 29 | private static global::System.Globalization.CultureInfo resourceCulture; 30 | 31 | [global::System.Diagnostics.CodeAnalysis.SuppressMessageAttribute("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] 32 | internal Resources() { 33 | } 34 | 35 | /// 36 | /// Returns the cached ResourceManager instance used by this class. 37 | /// 38 | [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)] 39 | internal static global::System.Resources.ResourceManager ResourceManager { 40 | get { 41 | if (object.ReferenceEquals(resourceMan, null)) { 42 | global::System.Resources.ResourceManager temp = new global::System.Resources.ResourceManager("CharacterEditor.Properties.Resources", typeof(Resources).Assembly); 43 | resourceMan = temp; 44 | } 45 | return resourceMan; 46 | } 47 | } 48 | 49 | /// 50 | /// Overrides the current thread's CurrentUICulture property for all 51 | /// resource lookups using this strongly typed resource class. 52 | /// 53 | [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)] 54 | internal static global::System.Globalization.CultureInfo Culture { 55 | get { 56 | return resourceCulture; 57 | } 58 | set { 59 | resourceCulture = value; 60 | } 61 | } 62 | 63 | /// 64 | /// Looks up a localized resource of type System.Drawing.Bitmap. 65 | /// 66 | internal static System.Drawing.Bitmap x2048 { 67 | get { 68 | object obj = ResourceManager.GetObject("x2048", resourceCulture); 69 | return ((System.Drawing.Bitmap)(obj)); 70 | } 71 | } 72 | } 73 | } 74 | -------------------------------------------------------------------------------- /Source/Properties/Resources.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 | 122 | ..\Resources\x2048.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a 123 | 124 | -------------------------------------------------------------------------------- /Source/Resources/x2048.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DatZach/CharacterEditor/974b2b9e9bd6756eb68b2a8ba349eac97ff67354/Source/Resources/x2048.png -------------------------------------------------------------------------------- /Source/Utility.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Drawing; 3 | using System.IO; 4 | using System.Text; 5 | 6 | namespace CharacterEditor 7 | { 8 | public static class Utility 9 | { 10 | public static int GoofyIndex(int index, string[] list) 11 | { 12 | int result = index; 13 | 14 | for (int i = 0, j = 0; i <= index; ++i, ++j) 15 | { 16 | if (j >= list.Length) 17 | break; 18 | 19 | while (String.IsNullOrEmpty(list[j])) 20 | { 21 | ++result; 22 | ++j; 23 | } 24 | } 25 | 26 | return result; 27 | } 28 | 29 | public static int NormalizeIndex(int index, string[] list) 30 | { 31 | int result = 0; 32 | 33 | for (int i = 0; i < index; ++i) 34 | { 35 | if (i >= list.Length) 36 | return 0; 37 | 38 | if (String.IsNullOrEmpty(list[i])) 39 | continue; 40 | 41 | ++result; 42 | } 43 | 44 | return result; 45 | } 46 | 47 | public static Color FromAbgr(int abgr) 48 | { 49 | long value = abgr & 0xFF00FF00; 50 | value |= (abgr & 0x000000FFL) << 16; 51 | value |= (abgr & 0x00FF0000L) >> 16; 52 | 53 | return Color.FromArgb((int)(value | 0xFF000000)); 54 | } 55 | 56 | public static int ToAbgr(Color color) 57 | { 58 | int argb = color.ToArgb(); 59 | long value = argb & 0xFF00FF00; 60 | value |= (argb & 0x000000FFL) << 16; 61 | value |= (argb & 0x00FF0000L) >> 16; 62 | 63 | return (int)(value | 0xFF000000); 64 | } 65 | 66 | public static void Skip(this BinaryReader reader, int count) 67 | { 68 | reader.BaseStream.Seek(count, SeekOrigin.Current); 69 | } 70 | 71 | public static void Skip(this BinaryWriter writer, int count) 72 | { 73 | writer.Write(new byte[count]); 74 | } 75 | 76 | public static string ReadLongString(this BinaryReader reader) 77 | { 78 | int length = reader.ReadInt32(); 79 | byte[] value = new byte[length]; 80 | 81 | reader.Read(value, 0, length); 82 | 83 | return Encoding.ASCII.GetString(value); 84 | } 85 | 86 | public static int ReadIntAtOffset(this BinaryReader reader, long position) 87 | { 88 | long previousPosition = reader.BaseStream.Position; 89 | reader.BaseStream.Position = position; 90 | 91 | int value = reader.ReadInt32(); 92 | 93 | reader.BaseStream.Position = previousPosition; 94 | 95 | return value; 96 | } 97 | 98 | public static float ReadSingleAtOffset(this BinaryReader reader, long position) 99 | { 100 | long previousPosition = reader.BaseStream.Position; 101 | reader.BaseStream.Position = position; 102 | 103 | float value = reader.ReadSingle(); 104 | 105 | reader.BaseStream.Position = previousPosition; 106 | 107 | return value; 108 | } 109 | 110 | public static void WriteLongString(this BinaryWriter writer, string value) 111 | { 112 | writer.Write(value.Length); 113 | writer.Write(Encoding.ASCII.GetBytes(value)); 114 | } 115 | } 116 | } 117 | -------------------------------------------------------------------------------- /Source/app.config: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /Source/icon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DatZach/CharacterEditor/974b2b9e9bd6756eb68b2a8ba349eac97ff67354/Source/icon.ico -------------------------------------------------------------------------------- /TODO.txt: -------------------------------------------------------------------------------- 1 | [ ] Fix items 2 | [ ] Modifiers 3 | [ ] Item stats 4 | [ ] Recipes 5 | [ ] "Advanced" mode 6 | [ ] Any entity as a pet 7 | [ ] Auto recipe/level scaling 8 | [ ] Database backups 9 | [ ] Model rendering -------------------------------------------------------------------------------- /characterformat.txt: -------------------------------------------------------------------------------- 1 | Charater Format 2 | 3 | Compressed Stream 4 | { 5 | [ Padding is aligned to 8 bytes ] 6 | 7 | 00 4 Entity ID (Always 1) 8 | 04 8 X Position 9 | 0C 8 Y Position 10 | 14 8 Z Position 11 | 1C 4 Pitch 12 | 20 4 Roll 13 | 24 4 Yaw 14 | 28 4 Health (Float) 15 | 2C 4 Experience 16 | 30 4 Level 17 | 34 1 Class 18 | 35 1 Specialization 19 | 36 4 Unknown (Stored at [PlayerBase + 1198h]) 20 | 3A 4 Unknown (Stored at [PlayerBase + 119Ch]) 21 | 22 | [ Equipment ] 23 | { Unused, Neck, Chest, Feet, Hands, Shoulder, Left Weapon, Right Weapon, 24 | Left Ring, Right Ring, Light, Special, Pet } 25 | For 13 26 | { 27 | 28 | } 29 | 30 | 00 4 Length { Name } 31 | 04 4 Race 32 | 08 1 Gender (0 = Male, 1 = Female) 33 | 09 3 Padding 34 | 0C 4 Face Index 35 | 10 4 Hair Index 36 | 14 1 Hair R [ Stored as bytes in the structure ] 37 | 15 1 Hair G 38 | 16 1 Hair B 39 | 17 1 Padding 40 | 18 4 InventoryCount 41 | For InventoryCount 42 | { 43 | 00 4 SlotCount 44 | For SlotCount 45 | { 46 | 47 | } 48 | } 49 | 50 | 00 4 Coins (Split into bronze, silver, gold ingame) 51 | 04 4 Platinum Coins 52 | 53 | [ Crafting recipes ] 54 | 08 4 Count 55 | For Count 56 | { 57 | 58 | } 59 | 60 | [ Worlds ] 61 | 00 4 Count 62 | For Count 63 | { 64 | 00 4 Seed 65 | 04 4 Length { Name } 66 | 08 8 X 67 | 10 8 Z 68 | 18 8 Y 69 | } 70 | 71 | 00 4 LastWorldSeed 72 | 04 4 Length { String } 73 | 74 | [ Skills ] 75 | 76 | 00 4 Mana Cubes 77 | 04 4 Skill Count 78 | 08 4 Pet Master Skill Level 79 | 0C 4 Pet Riding Level 80 | 10 4 Climbing Skill Level 81 | 14 4 Hang Gliding Skill Level 82 | 18 4 Swimming Skill Level 83 | 1C 4 Sailing Skill Level 84 | 20 4 Tier 1 Skill Level 85 | 24 4 Tier 2 Skill Level 86 | 28 4 Tier 3 Skill Level 87 | 88 | [ I think that these are two extra skills to be added in a future update ] 89 | 2C 4 Unknown Skill? (Always 0) 90 | 30 4 Unknown Skill? (Always 0) 91 | } 92 | 93 | 94 | { 95 | 00 1 Type 96 | 01 1 Subtype 97 | 02 2 Padding 98 | 04 2 Modifier 99 | 06 2 Padding 100 | 08 1 Recipe Type 101 | 09 3 Padding 102 | 0C 1 Rarity 103 | 0D 1 Material 104 | 0E 1 Item Flags 105 | 0F 1 Padding 106 | 10 2 Level 107 | 12 2 Padding 108 | 109 | [ Item Attributes ] 110 | For 32 111 | { 112 | 00 1 X Offset 113 | 01 1 Y Offset 114 | 02 1 Z Offset 115 | 03 1 Material 116 | 04 2 Level 117 | 06 2 Padding 118 | } 119 | 120 | 00 4 Attributes Used 121 | } 122 | 123 | === Notes on Player Name === 124 | Technicaly the name can be signed int max characters long, however, 125 | the game has some routine that verifies the names are less than 126 | or equal to 15 character and some other small attributes and 127 | panics if it isn't. 128 | 129 | === Notes on Pet Names === 130 | Pet names can be 15 characters long and are stored as item attributes, 131 | the material byte being used as the ASCII character. 132 | --------------------------------------------------------------------------------