mirror of
https://github.com/araxiaonline/wow-item-generator.git
synced 2026-06-13 03:02:22 -04:00
Compare commits
32 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 014079d572 | |||
| e58aa141a3 | |||
| 4b6e5320d2 | |||
| b80f7b314f | |||
| e4e3ff75fc | |||
| 74b2f9d37c | |||
| 8b5effaed7 | |||
| fffa4405e1 | |||
| 574525809d | |||
| b84a9e670c | |||
| 340d6e374f | |||
| 27b6ceebb0 | |||
| 6ead6ef52c | |||
| 4befce7728 | |||
| dc50db029b | |||
| f5f70263e2 | |||
| 131d75d943 | |||
| d612eaa9ff | |||
| a2f939da2f | |||
| 722c3b8613 | |||
| 3054f0c5f3 | |||
| 80b9ef71cf | |||
| bd39a22ccd | |||
| 1897be97ca | |||
| 506b23038b | |||
| 16c1a79ee6 | |||
| abdcde30a3 | |||
| ebfce61699 | |||
| 8ae06df805 | |||
| cd3715b13f | |||
| c2281e0c19 | |||
| dc35137e19 |
239
cmd/create_emblem_items/chaos-emblem.csv
Normal file
239
cmd/create_emblem_items/chaos-emblem.csv
Normal file
@@ -0,0 +1,239 @@
|
||||
entry,name,ItemLevel,RequiredLevel,Quality,InventoryType,class,subclass,stat_type1,stat_value1,stat_type2,stat_value2,stat_type3,stat_value3,stat_type4,stat_value4,stat_type5,stat_value5,stat_type6,stat_value6,stat_type7,stat_value7,stat_type8,stat_value8,stat_type9,stat_value9,stat_type10,stat_value10
|
||||
2051259,Sanctified Crimson Acolyte Raiments,377,85,4,20,4,1,45,302,7,215,5,215,32,176,36,176,0,0,0,0,0,0,0,0,0,0
|
||||
2051177,Sanctified Crimson Acolyte Leggings,364,85,4,7,4,1,45,265,7,190,5,190,6,167,36,142,0,0,0,0,0,0,0,0,0,0
|
||||
2051279,Sanctified Lightsworn Shoulderplates,377,85,4,3,4,4,4,227,7,240,32,139,36,127,0,0,0,0,0,0,0,0,0,0,0,0
|
||||
2051267,Sanctified Lightsworn Handguards,377,85,4,10,4,4,4,159,7,297,12,139,31,106,0,0,0,0,0,0,0,0,0,0,0,0
|
||||
2051135,Sanctified Lasherweave Pauldrons,364,85,4,3,4,2,45,204,7,142,5,142,6,124,32,111,0,0,0,0,0,0,0,0,0,0
|
||||
2051198,Sanctified Frost Witch's War-Kilt,364,85,4,7,4,3,38,285,3,251,7,198,5,131,32,155,31,119,0,0,0,0,0,0,0,0
|
||||
2051208,Sanctified Dark Coven Hood,364,85,4,1,4,1,45,251,7,190,5,190,32,155,36,142,0,0,0,0,0,0,0,0,0,0
|
||||
2051205,Sanctified Dark Coven Shoulderpads,364,85,4,3,4,1,45,204,7,142,5,142,32,124,36,111,0,0,0,0,0,0,0,0,0,0
|
||||
2051132,Sanctified Scourgelord Handguards,364,85,4,10,4,4,4,142,7,261,12,124,31,94,0,0,0,0,0,0,0,0,0,0,0,0
|
||||
2051289,Sanctified Ahn'Kahar Blood Hunter's Tunic,377,85,4,5,4,3,38,328,3,283,7,223,5,148,32,176,44,136,0,0,0,0,0,0,0,0
|
||||
2051272,Sanctified Lightsworn Headpiece,377,85,4,1,4,4,45,288,7,215,5,215,32,176,36,164,0,0,0,0,0,0,0,0,0,0
|
||||
2050981,Gloves of the Great Horned Owl,364,85,4,10,4,2,45,204,7,142,5,142,32,124,36,111,0,0,0,0,0,0,0,0,0,0
|
||||
2051137,Sanctified Lasherweave Helmet,364,85,4,1,4,2,45,251,7,190,5,190,6,155,32,142,0,0,0,0,0,0,0,0,0,0
|
||||
2050975,Ermine Coronation Robes,364,85,4,20,4,1,45,251,7,190,5,190,6,130,32,167,0,0,0,0,0,0,0,0,0,0
|
||||
2051298,Sanctified Lasherweave Raiment,377,85,4,20,4,2,38,328,3,283,7,283,32,189,44,164,0,0,0,0,0,0,0,0,0,0
|
||||
2051263,Sanctified Crimson Acolyte Robe,377,85,4,20,4,1,45,302,7,215,5,215,6,176,32,176,0,0,0,0,0,0,0,0,0,0
|
||||
2050470,Recovered Scarlet Onslaught Cape,364,85,4,16,4,1,38,162,3,139,7,139,32,93,44,80,0,0,0,0,0,0,0,0,0,0
|
||||
2051291,Sanctified Lasherweave Gloves,377,85,4,10,4,2,45,232,7,159,5,159,32,139,31,127,0,0,0,0,0,0,0,0,0,0
|
||||
2051275,Sanctified Lightsworn Battleplate,377,85,4,5,4,4,4,299,7,323,32,189,36,164,0,0,0,0,0,0,0,0,0,0,0,0
|
||||
2051229,Sanctified Ymirjar Lord's Shoulderplates,377,85,4,3,4,4,4,227,7,240,32,139,44,127,0,0,0,0,0,0,0,0,0,0,0,0
|
||||
2051210,Sanctified Ymirjar Lord's Shoulderplates,364,85,4,3,4,4,4,199,7,212,32,124,44,111,0,0,0,0,0,0,0,0,0,0,0,0
|
||||
2051226,Sanctified Ymirjar Lord's Gauntlets,377,85,4,10,4,4,4,227,7,240,32,139,31,127,0,0,0,0,0,0,0,0,0,0,0,0
|
||||
2050461,Libram of the Eternal Tower,364,85,4,28,4,7,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0
|
||||
2051225,Sanctified Ymirjar Lord's Battleplate,377,85,4,5,4,4,4,299,7,323,32,189,44,164,0,0,0,0,0,0,0,0,0,0,0,0
|
||||
2051199,Sanctified Frost Witch's Shoulderguards,364,85,4,3,4,3,38,224,3,186,7,147,5,97,32,124,36,85,0,0,0,0,0,0,0,0
|
||||
2050968,Cataclysmic Chestguard,364,85,4,5,4,4,4,190,7,320,12,167,37,127,0,0,0,0,0,0,0,0,0,0,0,0
|
||||
2050469,Volde's Cloak of the Night Sky,364,85,4,16,4,1,45,150,7,106,5,106,6,93,32,80,0,0,0,0,0,0,0,0,0,0
|
||||
2051125,Sanctified Scourgelord Shoulderplates,364,85,4,3,4,4,4,199,7,212,32,124,44,111,0,0,0,0,0,0,0,0,0,0,0,0
|
||||
2051173,Sanctified Lightsworn Faceguard,364,85,4,1,4,4,4,251,7,327,12,131,13,106,14,119,0,0,0,0,0,0,0,0,0,0
|
||||
2051224,Sanctified Ymirjar Lord's Pauldrons,377,85,4,3,4,4,4,210,7,297,12,110,13,97,14,110,0,0,0,0,0,0,0,0,0,0
|
||||
2051187,Sanctified Shadowblade Helmet,364,85,4,1,4,2,38,260,3,251,7,251,32,155,44,142,0,0,0,0,0,0,0,0,0,0
|
||||
2050978,Gauntlets of the Kraken,364,85,4,10,4,4,4,186,7,243,12,97,14,74,0,0,0,0,0,0,0,0,0,0,0,0
|
||||
2051251,Sanctified Shadowblade Gauntlets,377,85,4,10,4,2,38,255,3,210,7,210,32,139,36,127,0,0,0,0,0,0,0,0,0,0
|
||||
2051271,Sanctified Lightsworn Greaves,377,85,4,7,4,4,45,302,7,215,5,215,32,189,43,82,0,0,0,0,0,0,0,0,0,0
|
||||
2051155,Sanctified Bloodmage Shoulderpads,364,85,4,3,4,1,45,204,7,142,5,142,32,124,36,111,0,0,0,0,0,0,0,0,0,0
|
||||
2051266,Sanctified Lightsworn Faceguard,377,85,4,1,4,4,4,283,7,376,12,148,13,124,14,136,0,0,0,0,0,0,0,0,0,0
|
||||
2051274,Sanctified Lightsworn Tunic,377,85,4,5,4,4,45,302,7,215,5,215,32,189,36,164,0,0,0,0,0,0,0,0,0,0
|
||||
2051260,Sanctified Crimson Acolyte Gloves,377,85,4,10,4,1,45,232,7,159,5,159,6,139,36,127,0,0,0,0,0,0,0,0,0,0
|
||||
2050468,Drape of the Violet Tower,364,85,4,16,4,1,45,150,7,106,5,106,32,80,43,46,0,0,0,0,0,0,0,0,0,0
|
||||
2050993,Band of the Night Raven,364,85,4,6,4,3,38,249,3,161,7,147,5,97,32,124,31,72,0,0,0,0,0,0,0,0
|
||||
2051146,Sanctified Lasherweave Trousers,364,85,4,7,4,2,45,265,7,190,5,190,32,167,31,142,0,0,0,0,0,0,0,0,0,0
|
||||
2051227,Sanctified Ymirjar Lord's Helmet,377,85,4,1,4,4,4,286,7,323,32,176,44,164,0,0,0,0,0,0,0,0,0,0,0,0
|
||||
2051302,Sanctified Lasherweave Helmet,377,85,4,1,4,2,45,288,7,215,5,215,6,176,32,164,0,0,0,0,0,0,0,0,0,0
|
||||
2051223,Sanctified Ymirjar Lord's Legguards,377,85,4,7,4,4,4,215,7,389,12,164,13,189,37,144,0,0,0,0,0,0,0,0,0,0
|
||||
2050996,Belt of Omission,364,85,4,6,4,1,45,189,7,142,5,142,32,124,31,99,0,0,0,0,0,0,0,0,0,0
|
||||
2051297,Sanctified Lasherweave Legguards,377,85,4,7,4,2,38,328,3,283,7,283,44,189,37,164,0,0,0,0,0,0,0,0,0,0
|
||||
2051126,Sanctified Scourgelord Legplates,364,85,4,7,4,4,4,261,7,286,32,167,37,142,0,0,0,0,0,0,0,0,0,0,0,0
|
||||
2050987,Malevolent Girdle,364,85,4,6,4,4,4,187,7,212,32,128,31,93,0,0,0,0,0,0,0,0,0,0,0,0
|
||||
2050467,Might of the Ocean Serpent,364,85,4,16,4,1,4,147,7,159,44,100,37,69,0,0,0,0,0,0,0,0,0,0,0,0
|
||||
2051195,Sanctified Frost Witch's Chestguard,364,85,4,5,4,3,38,285,3,251,7,198,5,131,32,155,36,119,0,0,0,0,0,0,0,0
|
||||
2050983,Gloves of False Gestures,364,85,4,10,4,1,45,189,7,142,5,142,32,124,36,99,0,0,0,0,0,0,0,0,0,0
|
||||
2051306,Sanctified Scourgelord Faceguard,377,85,4,1,4,4,4,283,7,370,12,148,13,124,14,136,0,0,0,0,0,0,0,0,0,0
|
||||
2051144,Sanctified Lasherweave Handgrips,364,85,4,10,4,2,38,224,3,186,7,186,44,124,36,111,0,0,0,0,0,0,0,0,0,0
|
||||
2051222,Sanctified Ymirjar Lord's Handguards,377,85,4,10,4,4,4,159,7,297,12,139,31,106,0,0,0,0,0,0,0,0,0,0,0,0
|
||||
2051280,Sanctified Bloodmage Gloves,377,85,4,10,4,1,45,232,7,159,5,159,32,139,31,127,0,0,0,0,0,0,0,0,0,0
|
||||
2051284,Sanctified Bloodmage Shoulderpads,377,85,4,3,4,1,45,232,7,159,5,159,32,139,36,127,0,0,0,0,0,0,0,0,0,0
|
||||
2051256,Sanctified Crimson Acolyte Handwraps,377,85,4,10,4,1,45,232,7,159,5,159,32,139,31,127,0,0,0,0,0,0,0,0,0,0
|
||||
2050974,Meteor Chaser's Raiment,364,85,4,20,4,1,45,251,7,190,5,190,32,130,36,167,0,0,0,0,0,0,0,0,0,0
|
||||
2050357,Maghia's Misguided Quill,364,85,4,12,4,0,31,235,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0
|
||||
2051217,Sanctified Ymirjar Lord's Handguards,364,85,4,10,4,4,4,142,7,261,12,124,31,94,0,0,0,0,0,0,0,0,0,0,0,0
|
||||
2051163,Sanctified Lightsworn Gauntlets,364,85,4,10,4,4,4,199,7,212,32,124,31,111,0,0,0,0,0,0,0,0,0,0,0,0
|
||||
2051188,Sanctified Shadowblade Gauntlets,364,85,4,10,4,2,38,224,3,186,7,186,32,124,36,111,0,0,0,0,0,0,0,0,0,0
|
||||
2051164,Sanctified Lightsworn Battleplate,364,85,4,5,4,4,4,261,7,286,32,167,36,142,0,0,0,0,0,0,0,0,0,0,0,0
|
||||
2051234,Sanctified Dark Coven Shoulderpads,377,85,4,3,4,1,45,232,7,159,5,159,32,139,36,127,0,0,0,0,0,0,0,0,0,0
|
||||
2051245,Sanctified Frost Witch's Spaulders,377,85,4,3,4,3,45,232,7,159,5,159,32,139,36,127,0,0,0,0,0,0,0,0,0,0
|
||||
2051209,Sanctified Dark Coven Gloves,364,85,4,10,4,1,45,204,7,142,5,142,32,124,31,111,0,0,0,0,0,0,0,0,0,0
|
||||
2050992,Waistband of Despair,364,85,4,6,4,3,45,189,7,142,5,142,32,124,36,99,0,0,0,0,0,0,0,0,0,0
|
||||
2051283,Sanctified Bloodmage Robe,377,85,4,20,4,1,45,302,7,215,5,215,32,164,36,189,0,0,0,0,0,0,0,0,0,0
|
||||
2051218,Sanctified Ymirjar Lord's Greathelm,364,85,4,1,4,4,4,251,7,320,12,119,13,106,14,119,0,0,0,0,0,0,0,0,0,0
|
||||
2050977,Gatecrasher's Gauntlets,364,85,4,10,4,4,4,187,7,212,32,124,44,99,0,0,0,0,0,0,0,0,0,0,0,0
|
||||
2051287,Sanctified Ahn'Kahar Blood Hunter's Legguards,377,85,4,7,4,3,38,328,3,283,7,223,5,148,32,176,36,136,0,0,0,0,0,0,0,0
|
||||
2051241,Sanctified Frost Witch's War-Kilt,377,85,4,7,4,3,38,328,3,283,7,223,5,148,32,176,31,136,0,0,0,0,0,0,0,0
|
||||
2051206,Sanctified Dark Coven Robe,364,85,4,20,4,1,45,265,7,190,5,190,32,167,36,142,0,0,0,0,0,0,0,0,0,0
|
||||
2051162,Sanctified Lightsworn Helmet,364,85,4,1,4,4,4,249,7,286,32,155,36,142,0,0,0,0,0,0,0,0,0,0,0,0
|
||||
2051242,Sanctified Frost Witch's Faceguard,377,85,4,1,4,3,38,328,3,271,7,223,5,148,32,176,36,124,0,0,0,0,0,0,0,0
|
||||
2051300,Sanctified Lasherweave Robes,377,85,4,20,4,2,45,302,7,215,5,215,6,189,32,164,0,0,0,0,0,0,0,0,0,0
|
||||
2050462,Sigil of the Bone Gryphon,364,85,4,28,4,10,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0
|
||||
2051200,Sanctified Frost Witch's Hauberk,364,85,4,5,4,3,45,265,7,190,5,190,32,167,36,142,0,0,0,0,0,0,0,0,0,0
|
||||
2050984,Gloves of Ambivalence,364,85,4,10,4,1,45,189,7,142,5,142,6,124,32,99,0,0,0,0,0,0,0,0,0,0
|
||||
2051143,Sanctified Lasherweave Headguard,364,85,4,1,4,2,38,260,3,251,7,251,32,155,44,142,0,0,0,0,0,0,0,0,0,0
|
||||
2051230,Sanctified Dark Coven Gloves,377,85,4,10,4,1,45,232,7,159,5,159,32,139,31,127,0,0,0,0,0,0,0,0,0,0
|
||||
2051179,Sanctified Crimson Acolyte Gloves,364,85,4,10,4,1,45,204,7,142,5,142,6,124,36,111,0,0,0,0,0,0,0,0,0,0
|
||||
2051180,Sanctified Crimson Acolyte Raiments,364,85,4,20,4,1,45,265,7,190,5,190,32,155,36,155,0,0,0,0,0,0,0,0,0,0
|
||||
2051211,Sanctified Ymirjar Lord's Legplates,364,85,4,7,4,4,4,261,7,285,32,167,37,142,0,0,0,0,0,0,0,0,0,0,0,0
|
||||
2050455,Libram of Three Truths,364,85,4,28,4,7,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0
|
||||
2051138,Sanctified Lasherweave Gauntlets,364,85,4,10,4,2,45,204,7,142,5,142,6,124,36,111,0,0,0,0,0,0,0,0,0,0
|
||||
2050997,Circle of Ossus,364,85,4,6,4,1,45,189,7,142,5,142,6,99,36,124,0,0,0,0,0,0,0,0,0,0
|
||||
2051269,Sanctified Lightsworn Shoulderguards,377,85,4,3,4,4,4,210,7,297,12,110,13,97,14,110,0,0,0,0,0,0,0,0,0,0
|
||||
2050971,Mail of the Geyser,364,85,4,5,4,3,45,251,7,190,5,190,32,155,43,71,0,0,0,0,0,0,0,0,0,0
|
||||
2051310,Sanctified Scourgelord Battleplate,377,85,4,5,4,4,4,299,7,323,32,189,44,164,0,0,0,0,0,0,0,0,0,0,0,0
|
||||
2050973,Vestments of Spruce and Fir,364,85,4,20,4,2,45,251,7,190,5,190,6,130,36,167,0,0,0,0,0,0,0,0,0,0
|
||||
2050458,Bizuri's Totem of Shattered Ice,364,85,4,28,4,9,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0
|
||||
2051288,Sanctified Ahn'Kahar Blood Hunter's Spaulders,377,85,4,3,4,3,38,255,3,210,7,165,5,110,32,139,44,97,0,0,0,0,0,0,0,0
|
||||
2051255,Sanctified Crimson Acolyte Cowl,377,85,4,1,4,1,45,286,7,215,5,215,32,189,36,151,0,0,0,0,0,0,0,0,0,0
|
||||
2051286,Sanctified Ahn'Kahar Blood Hunter's Headpiece,377,85,4,1,4,3,38,328,3,271,7,223,5,148,32,164,44,136,0,0,0,0,0,0,0,0
|
||||
2051141,Sanctified Lasherweave Raiment,364,85,4,20,4,2,38,285,3,251,7,251,32,167,44,142,0,0,0,0,0,0,0,0,0,0
|
||||
2051133,Sanctified Scourgelord Faceguard,364,85,4,1,4,4,4,251,7,320,12,131,13,106,14,119,0,0,0,0,0,0,0,0,0,0
|
||||
2051305,Sanctified Scourgelord Chestguard,377,85,4,5,4,4,4,283,7,389,13,124,14,148,0,0,0,0,0,0,0,0,0,0,0,0
|
||||
2051196,Sanctified Frost Witch's Grips,364,85,4,10,4,3,38,224,3,186,7,147,5,97,32,124,31,85,0,0,0,0,0,0,0,0
|
||||
2051240,Sanctified Frost Witch's Shoulderguards,377,85,4,3,4,3,38,255,3,210,7,165,5,110,32,139,36,97,0,0,0,0,0,0,0,0
|
||||
2051204,Sanctified Frost Witch's Shoulderpads,364,85,4,3,4,3,45,204,7,142,5,142,32,124,36,111,0,0,0,0,0,0,0,0,0,0
|
||||
2051202,Sanctified Frost Witch's Helm,364,85,4,1,4,3,45,249,7,190,5,190,32,155,36,142,0,0,0,0,0,0,0,0,0,0
|
||||
2050355,Herkuml War Token,364,85,4,12,4,0,36,237,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0
|
||||
2051244,Sanctified Frost Witch's Chestguard,377,85,4,5,4,3,38,328,3,283,7,223,5,148,32,176,36,136,0,0,0,0,0,0,0,0
|
||||
2051178,Sanctified Crimson Acolyte Hood,364,85,4,1,4,1,45,251,7,190,5,190,6,142,32,155,0,0,0,0,0,0,0,0,0,0
|
||||
2051161,Sanctified Lightsworn Legplates,364,85,4,7,4,4,4,261,7,286,32,167,37,142,0,0,0,0,0,0,0,0,0,0,0,0
|
||||
2051281,Sanctified Bloodmage Hood,377,85,4,1,4,1,45,288,7,215,5,215,32,189,36,151,0,0,0,0,0,0,0,0,0,0
|
||||
2051214,Sanctified Ymirjar Lord's Battleplate,364,85,4,5,4,4,4,261,7,286,32,167,44,142,0,0,0,0,0,0,0,0,0,0,0,0
|
||||
2050464,Totem of the Surging Sea,364,85,4,28,4,9,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0
|
||||
2050976,Gauntlets of Overexposure,364,85,4,10,4,4,45,189,7,142,5,142,32,124,36,99,0,0,0,0,0,0,0,0,0,0
|
||||
2051249,Sanctified Frost Witch's Tunic,377,85,4,5,4,3,45,302,7,215,5,215,32,189,36,164,0,0,0,0,0,0,0,0,0,0
|
||||
2051254,Sanctified Shadowblade Pauldrons,377,85,4,3,4,2,38,255,3,210,7,210,32,139,31,127,0,0,0,0,0,0,0,0,0,0
|
||||
2051201,Sanctified Frost Witch's Gloves,364,85,4,10,4,3,45,204,7,142,5,142,32,124,31,111,0,0,0,0,0,0,0,0,0,0
|
||||
2050995,Vengeful Noose,364,85,4,6,4,2,38,199,3,186,7,186,36,99,44,124,0,0,0,0,0,0,0,0,0,0
|
||||
2051228,Sanctified Ymirjar Lord's Legplates,377,85,4,7,4,4,4,299,7,322,32,189,37,164,0,0,0,0,0,0,0,0,0,0,0,0
|
||||
2050463,Totem of the Avalanche,364,85,4,28,4,9,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0
|
||||
2051290,Sanctified Lasherweave Cover,377,85,4,1,4,2,45,288,7,215,5,215,32,176,36,164,0,0,0,0,0,0,0,0,0,0
|
||||
2051176,Sanctified Crimson Acolyte Robe,364,85,4,20,4,1,45,265,7,190,5,190,6,155,32,155,0,0,0,0,0,0,0,0,0,0
|
||||
2051236,Sanctified Frost Witch's Kilt,377,85,4,7,4,3,45,302,7,215,5,215,32,189,31,164,0,0,0,0,0,0,0,0,0,0
|
||||
2051140,Sanctified Lasherweave Shoulderpads,364,85,4,3,4,2,38,224,3,186,7,186,32,124,44,111,0,0,0,0,0,0,0,0,0,0
|
||||
2051142,Sanctified Lasherweave Legguards,364,85,4,7,4,2,38,285,3,251,7,251,44,167,37,142,0,0,0,0,0,0,0,0,0,0
|
||||
2051295,Sanctified Lasherweave Handgrips,377,85,4,10,4,2,38,255,3,210,7,210,44,139,36,127,0,0,0,0,0,0,0,0,0,0
|
||||
2050356,Corroded Skeleton Key,364,85,4,12,4,0,7,353,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0
|
||||
2051152,Sanctified Ahn'Kahar Blood Hunter's Legguards,364,85,4,7,4,3,38,285,3,251,7,198,5,131,32,155,36,119,0,0,0,0,0,0,0,0
|
||||
2051308,Sanctified Scourgelord Legguards,377,85,4,7,4,4,4,215,7,389,12,189,13,164,37,144,0,0,0,0,0,0,0,0,0,0
|
||||
2051165,Sanctified Lightsworn Tunic,364,85,4,5,4,4,45,265,7,190,5,190,32,167,36,142,0,0,0,0,0,0,0,0,0,0
|
||||
2051128,Sanctified Scourgelord Gauntlets,364,85,4,10,4,4,4,199,7,212,32,124,31,111,0,0,0,0,0,0,0,0,0,0,0,0
|
||||
2051313,Sanctified Scourgelord Legplates,377,85,4,7,4,4,4,299,7,323,32,189,37,164,0,0,0,0,0,0,0,0,0,0,0,0
|
||||
2051232,Sanctified Dark Coven Leggings,377,85,4,7,4,1,45,302,7,215,5,215,32,189,31,164,0,0,0,0,0,0,0,0,0,0
|
||||
2051311,Sanctified Scourgelord Gauntlets,377,85,4,10,4,4,4,227,7,240,32,139,31,127,0,0,0,0,0,0,0,0,0,0,0,0
|
||||
2051182,Sanctified Crimson Acolyte Mantle,364,85,4,3,4,1,45,204,7,142,5,142,32,124,36,111,0,0,0,0,0,0,0,0,0,0
|
||||
2051285,Sanctified Ahn'Kahar Blood Hunter's Handguards,377,85,4,10,4,3,38,255,3,210,7,165,5,110,32,127,31,110,0,0,0,0,0,0,0,0
|
||||
2051131,Sanctified Scourgelord Legguards,364,85,4,7,4,4,4,190,7,339,12,167,13,142,37,127,0,0,0,0,0,0,0,0,0,0
|
||||
2051150,Sanctified Ahn'Kahar Blood Hunter's Tunic,364,85,4,5,4,3,38,285,3,251,7,198,5,131,32,155,44,119,0,0,0,0,0,0,0,0
|
||||
2051212,Sanctified Ymirjar Lord's Helmet,364,85,4,1,4,4,4,249,7,286,32,155,44,142,0,0,0,0,0,0,0,0,0,0,0,0
|
||||
2051158,Sanctified Bloodmage Hood,364,85,4,1,4,1,45,251,7,190,5,190,32,167,36,130,0,0,0,0,0,0,0,0,0,0
|
||||
2051252,Sanctified Shadowblade Helmet,377,85,4,1,4,2,38,303,3,283,7,283,32,176,44,164,0,0,0,0,0,0,0,0,0,0
|
||||
2051184,Sanctified Crimson Acolyte Cowl,364,85,4,1,4,1,45,249,7,190,5,190,32,167,36,130,0,0,0,0,0,0,0,0,0,0
|
||||
2051207,Sanctified Dark Coven Leggings,364,85,4,7,4,1,45,265,7,190,5,190,32,167,31,142,0,0,0,0,0,0,0,0,0,0
|
||||
2051156,Sanctified Bloodmage Robe,364,85,4,20,4,1,45,265,7,190,5,190,32,142,36,167,0,0,0,0,0,0,0,0,0,0
|
||||
2051127,Sanctified Scourgelord Helmet,364,85,4,1,4,4,4,249,7,286,32,155,44,142,0,0,0,0,0,0,0,0,0,0,0,0
|
||||
2051136,Sanctified Lasherweave Legplates,364,85,4,7,4,2,45,265,7,190,5,190,6,167,36,139,0,0,0,0,0,0,0,0,0,0
|
||||
2051307,Sanctified Scourgelord Handguards,377,85,4,10,4,4,4,159,7,297,12,139,31,106,0,0,0,0,0,0,0,0,0,0,0,0
|
||||
2051130,Sanctified Scourgelord Pauldrons,364,85,4,3,4,4,4,186,7,261,12,97,13,85,14,97,0,0,0,0,0,0,0,0,0,0
|
||||
2050979,Logsplitters,364,85,4,10,4,3,38,224,3,173,7,147,5,97,32,99,44,97,0,0,0,0,0,0,0,0
|
||||
2051293,Sanctified Lasherweave Trousers,377,85,4,7,4,2,45,302,7,215,5,215,32,189,31,164,0,0,0,0,0,0,0,0,0,0
|
||||
2051261,Sanctified Crimson Acolyte Hood,377,85,4,1,4,1,45,288,7,215,5,215,6,164,32,176,0,0,0,0,0,0,0,0,0,0
|
||||
2051248,Sanctified Frost Witch's Handguards,377,85,4,10,4,3,45,232,7,159,5,159,32,139,43,63,0,0,0,0,0,0,0,0,0,0
|
||||
2051301,Sanctified Lasherweave Gauntlets,377,85,4,10,4,2,45,232,7,159,5,159,6,139,36,127,0,0,0,0,0,0,0,0,0,0
|
||||
2051221,Sanctified Ymirjar Lord's Greathelm,377,85,4,1,4,4,4,283,7,370,12,136,13,124,14,136,0,0,0,0,0,0,0,0,0,0
|
||||
2051312,Sanctified Scourgelord Helmet,377,85,4,1,4,4,4,286,7,323,32,176,44,164,0,0,0,0,0,0,0,0,0,0,0,0
|
||||
2051151,Sanctified Ahn'Kahar Blood Hunter's Spaulders,364,85,4,3,4,3,38,224,3,186,7,147,5,97,32,124,44,85,0,0,0,0,0,0,0,0
|
||||
2051253,Sanctified Shadowblade Legplates,377,85,4,7,4,2,38,328,3,283,7,283,32,189,37,164,0,0,0,0,0,0,0,0,0,0
|
||||
2051183,Sanctified Crimson Acolyte Handwraps,364,85,4,10,4,1,45,204,7,142,5,142,32,124,31,111,0,0,0,0,0,0,0,0,0,0
|
||||
2050970,Longstrider's Vest,364,85,4,5,4,3,38,285,3,226,7,198,5,131,32,167,44,106,0,0,0,0,0,0,0,0
|
||||
2051153,Sanctified Ahn'Kahar Blood Hunter's Headpiece,364,85,4,1,4,3,38,285,3,238,7,198,5,131,32,142,44,119,0,0,0,0,0,0,0,0
|
||||
2051237,Sanctified Frost Witch's Helm,377,85,4,1,4,3,45,286,7,215,5,215,32,176,36,164,0,0,0,0,0,0,0,0,0,0
|
||||
2051197,Sanctified Frost Witch's Faceguard,364,85,4,1,4,3,38,285,3,238,7,198,5,131,32,155,36,106,0,0,0,0,0,0,0,0
|
||||
2051174,Sanctified Lightsworn Chestguard,364,85,4,5,4,4,4,251,7,339,13,106,14,131,0,0,0,0,0,0,0,0,0,0,0,0
|
||||
2050460,Libram of Blinding Light,364,85,4,28,4,7,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0
|
||||
2051268,Sanctified Lightsworn Legguards,377,85,4,7,4,4,4,215,7,389,12,189,13,164,37,144,0,0,0,0,0,0,0,0,0,0
|
||||
2051157,Sanctified Bloodmage Leggings,364,85,4,7,4,1,45,265,7,190,5,190,32,167,31,142,0,0,0,0,0,0,0,0,0,0
|
||||
2050454,Idol of the Black Willow,364,85,4,28,4,8,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0
|
||||
2050358,Purified Lunar Dust,364,85,4,12,4,0,45,277,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0
|
||||
2051160,Sanctified Lightsworn Shoulderplates,364,85,4,3,4,4,4,199,7,212,32,124,36,111,0,0,0,0,0,0,0,0,0,0,0,0
|
||||
2051169,Sanctified Lightsworn Gloves,364,85,4,10,4,4,45,204,7,142,5,142,32,124,43,55,0,0,0,0,0,0,0,0,0,0
|
||||
2051299,Sanctified Lasherweave Shoulderpads,377,85,4,3,4,2,38,255,3,210,7,210,32,139,44,127,0,0,0,0,0,0,0,0,0,0
|
||||
2051192,Sanctified Frost Witch's Headpiece,364,85,4,1,4,3,45,249,7,190,5,190,32,155,36,142,0,0,0,0,0,0,0,0,0,0
|
||||
2051243,Sanctified Frost Witch's Grips,377,85,4,10,4,3,38,255,3,210,7,165,5,110,32,139,31,97,0,0,0,0,0,0,0,0
|
||||
2051139,Sanctified Lasherweave Robes,364,85,4,20,4,2,45,265,7,190,5,190,6,167,32,142,0,0,0,0,0,0,0,0,0,0
|
||||
2051181,Sanctified Crimson Acolyte Pants,364,85,4,7,4,1,45,265,7,190,5,190,32,167,31,142,0,0,0,0,0,0,0,0,0,0
|
||||
2051304,Sanctified Lasherweave Pauldrons,377,85,4,3,4,2,45,232,7,159,5,159,6,139,32,127,0,0,0,0,0,0,0,0,0,0
|
||||
2050457,Idol of the Lunar Eclipse,364,85,4,28,4,8,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0
|
||||
2051282,Sanctified Bloodmage Leggings,377,85,4,7,4,1,45,302,7,215,5,215,32,189,31,164,0,0,0,0,0,0,0,0,0,0
|
||||
2051314,Sanctified Scourgelord Shoulderplates,377,85,4,3,4,4,4,227,7,240,32,139,44,127,0,0,0,0,0,0,0,0,0,0,0,0
|
||||
2051203,Sanctified Frost Witch's Kilt,364,85,4,7,4,3,45,265,7,190,5,190,32,167,31,142,0,0,0,0,0,0,0,0,0,0
|
||||
2051292,Sanctified Lasherweave Mantle,377,85,4,3,4,2,45,232,7,159,5,159,32,139,36,127,0,0,0,0,0,0,0,0,0,0
|
||||
2050456,Idol of the Crying Moon,364,85,4,28,4,8,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0
|
||||
2051154,Sanctified Ahn'Kahar Blood Hunter's Handguards,364,85,4,10,4,3,38,224,3,186,7,147,5,97,32,111,31,97,0,0,0,0,0,0,0,0
|
||||
2051186,Sanctified Shadowblade Legplates,364,85,4,7,4,2,38,285,3,251,7,251,32,167,37,142,0,0,0,0,0,0,0,0,0,0
|
||||
2051277,Sanctified Lightsworn Helmet,377,85,4,1,4,4,4,286,7,323,32,176,36,164,0,0,0,0,0,0,0,0,0,0,0,0
|
||||
2050459,Sigil of the Hanged Man,364,85,4,28,4,10,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0
|
||||
2050991,Verdigris Chain Belt,364,85,4,6,4,4,4,186,7,243,12,97,14,97,0,0,0,0,0,0,0,0,0,0,0,0
|
||||
2050994,Belt of Petrified Ivy,364,85,4,6,4,2,45,189,7,142,5,142,32,124,36,99,0,0,0,0,0,0,0,0,0,0
|
||||
2050980,Blizzard Keeper's Mitts,364,85,4,10,4,3,45,189,7,142,5,142,32,124,36,99,0,0,0,0,0,0,0,0,0,0
|
||||
2051219,Sanctified Ymirjar Lord's Breastplate,364,85,4,5,4,4,4,251,7,339,13,119,14,119,0,0,0,0,0,0,0,0,0,0,0,0
|
||||
2051170,Sanctified Lightsworn Shoulderguards,364,85,4,3,4,4,4,186,7,261,12,97,13,85,14,97,0,0,0,0,0,0,0,0,0,0
|
||||
2051262,Sanctified Crimson Acolyte Leggings,377,85,4,7,4,1,45,302,7,215,5,215,6,189,36,164,0,0,0,0,0,0,0,0,0,0
|
||||
2051238,Sanctified Frost Witch's Gloves,377,85,4,10,4,3,45,232,7,159,5,159,32,139,31,127,0,0,0,0,0,0,0,0,0,0
|
||||
2051309,Sanctified Scourgelord Pauldrons,377,85,4,3,4,4,4,210,7,297,12,110,13,97,14,110,0,0,0,0,0,0,0,0,0,0
|
||||
2050965,Castle Breaker's Battleplate,364,85,4,5,4,4,4,249,7,286,32,130,44,167,0,0,0,0,0,0,0,0,0,0,0,0
|
||||
2051190,Sanctified Frost Witch's Tunic,364,85,4,5,4,3,45,265,7,190,5,190,32,167,36,142,0,0,0,0,0,0,0,0,0,0
|
||||
2051194,Sanctified Frost Witch's Spaulders,364,85,4,3,4,3,45,204,7,142,5,142,32,124,36,111,0,0,0,0,0,0,0,0,0,0
|
||||
2051191,Sanctified Frost Witch's Handguards,364,85,4,10,4,3,45,204,7,142,5,142,32,124,43,55,0,0,0,0,0,0,0,0,0,0
|
||||
2051303,Sanctified Lasherweave Legplates,377,85,4,7,4,2,45,302,7,215,5,215,6,189,36,161,0,0,0,0,0,0,0,0,0,0
|
||||
2051129,Sanctified Scourgelord Battleplate,364,85,4,5,4,4,4,261,7,286,32,167,44,142,0,0,0,0,0,0,0,0,0,0,0,0
|
||||
2051273,Sanctified Lightsworn Spaulders,377,85,4,3,4,4,45,232,7,159,5,159,32,139,36,127,0,0,0,0,0,0,0,0,0,0
|
||||
2051213,Sanctified Ymirjar Lord's Gauntlets,364,85,4,10,4,4,4,199,7,212,32,124,31,111,0,0,0,0,0,0,0,0,0,0,0,0
|
||||
2051270,Sanctified Lightsworn Gloves,377,85,4,10,4,4,45,232,7,159,5,159,32,139,43,63,0,0,0,0,0,0,0,0,0,0
|
||||
2051171,Sanctified Lightsworn Legguards,364,85,4,7,4,4,4,190,7,339,12,167,13,142,37,127,0,0,0,0,0,0,0,0,0,0
|
||||
2051175,Sanctified Crimson Acolyte Shoulderpads,364,85,4,3,4,1,45,204,7,142,5,142,6,124,32,111,0,0,0,0,0,0,0,0,0,0
|
||||
2050982,Cat Burglar's Grips,364,85,4,10,4,2,38,199,3,186,7,186,32,124,44,99,0,0,0,0,0,0,0,0,0,0
|
||||
2050989,Lich Killer's Lanyard,364,85,4,6,4,4,45,189,7,142,5,142,32,124,36,99,0,0,0,0,0,0,0,0,0,0
|
||||
2051278,Sanctified Lightsworn Legplates,377,85,4,7,4,4,4,299,7,323,32,189,37,164,0,0,0,0,0,0,0,0,0,0,0,0
|
||||
2051147,Sanctified Lasherweave Mantle,364,85,4,3,4,2,45,204,7,142,5,142,32,124,36,111,0,0,0,0,0,0,0,0,0,0
|
||||
2051265,Sanctified Lightsworn Chestguard,377,85,4,5,4,4,4,283,7,389,13,124,14,148,0,0,0,0,0,0,0,0,0,0,0,0
|
||||
2051264,Sanctified Crimson Acolyte Shoulderpads,377,85,4,3,4,1,45,232,7,159,5,159,6,139,32,127,0,0,0,0,0,0,0,0,0,0
|
||||
2051294,Sanctified Lasherweave Vestment,377,85,4,20,4,2,45,302,7,215,5,215,32,189,36,164,0,0,0,0,0,0,0,0,0,0
|
||||
2051215,Sanctified Ymirjar Lord's Pauldrons,364,85,4,3,4,4,4,186,7,261,12,97,13,85,14,97,0,0,0,0,0,0,0,0,0,0
|
||||
2051168,Sanctified Lightsworn Greaves,364,85,4,7,4,4,45,265,7,190,5,190,32,167,43,71,0,0,0,0,0,0,0,0,0,0
|
||||
2051247,Sanctified Frost Witch's Headpiece,377,85,4,1,4,3,45,286,7,215,5,215,32,176,36,164,0,0,0,0,0,0,0,0,0,0
|
||||
2051148,Sanctified Lasherweave Gloves,364,85,4,10,4,2,45,204,7,142,5,142,32,124,31,111,0,0,0,0,0,0,0,0,0,0
|
||||
2050972,Shadow Seeker's Tunic,364,85,4,5,4,2,38,285,3,251,7,251,32,142,37,142,0,0,0,0,0,0,0,0,0,0
|
||||
2051166,Sanctified Lightsworn Spaulders,364,85,4,3,4,4,45,204,7,142,5,142,32,124,36,111,0,0,0,0,0,0,0,0,0,0
|
||||
2051185,Sanctified Shadowblade Pauldrons,364,85,4,3,4,2,38,224,3,186,7,186,32,124,31,111,0,0,0,0,0,0,0,0,0,0
|
||||
2051167,Sanctified Lightsworn Headpiece,364,85,4,1,4,4,45,251,7,190,5,190,32,155,36,142,0,0,0,0,0,0,0,0,0,0
|
||||
2051231,Sanctified Dark Coven Hood,377,85,4,1,4,1,45,288,7,215,5,215,32,176,36,164,0,0,0,0,0,0,0,0,0,0
|
||||
2051149,Sanctified Lasherweave Cover,364,85,4,1,4,2,45,251,7,190,5,190,32,155,36,142,0,0,0,0,0,0,0,0,0,0
|
||||
2051159,Sanctified Bloodmage Gloves,364,85,4,10,4,1,45,204,7,142,5,142,32,124,31,111,0,0,0,0,0,0,0,0,0,0
|
||||
2050466,Sentinel's Winter Cloak,364,85,4,16,4,1,4,139,7,192,12,74,13,74,0,0,0,0,0,0,0,0,0,0,0,0
|
||||
2051257,Sanctified Crimson Acolyte Mantle,377,85,4,3,4,1,45,232,7,159,5,159,32,139,36,127,0,0,0,0,0,0,0,0,0,0
|
||||
2051172,Sanctified Lightsworn Handguards,364,85,4,10,4,4,4,142,7,261,12,124,31,94,0,0,0,0,0,0,0,0,0,0,0,0
|
||||
2051246,Sanctified Frost Witch's Legguards,377,85,4,7,4,3,45,302,7,215,5,215,32,189,43,82,0,0,0,0,0,0,0,0,0,0
|
||||
2051296,Sanctified Lasherweave Headguard,377,85,4,1,4,2,38,303,3,283,7,283,32,176,44,164,0,0,0,0,0,0,0,0,0,0
|
||||
2051145,Sanctified Lasherweave Vestment,364,85,4,20,4,2,45,265,7,190,5,190,32,167,36,142,0,0,0,0,0,0,0,0,0,0
|
||||
2051189,Sanctified Shadowblade Breastplate,364,85,4,5,4,2,38,285,3,251,7,251,32,167,44,142,0,0,0,0,0,0,0,0,0,0
|
||||
2051258,Sanctified Crimson Acolyte Pants,377,85,4,7,4,1,45,302,7,215,5,215,32,189,31,164,0,0,0,0,0,0,0,0,0,0
|
||||
2051239,Sanctified Frost Witch's Hauberk,377,85,4,5,4,3,45,302,7,215,5,215,32,189,36,164,0,0,0,0,0,0,0,0,0,0
|
||||
2051235,Sanctified Frost Witch's Shoulderpads,377,85,4,3,4,3,45,232,7,159,5,159,32,139,36,127,0,0,0,0,0,0,0,0,0,0
|
||||
2050969,Chestplate of Unspoken Truths,364,85,4,5,4,4,45,251,7,190,5,190,32,155,43,71,0,0,0,0,0,0,0,0,0,0
|
||||
2051216,Sanctified Ymirjar Lord's Legguards,364,85,4,7,4,4,4,190,7,339,12,142,13,167,37,127,0,0,0,0,0,0,0,0,0,0
|
||||
2051193,Sanctified Frost Witch's Legguards,364,85,4,7,4,3,45,265,7,190,5,190,32,167,43,71,0,0,0,0,0,0,0,0,0,0
|
||||
2051233,Sanctified Dark Coven Robe,377,85,4,20,4,1,45,302,7,215,5,215,32,189,36,164,0,0,0,0,0,0,0,0,0,0
|
||||
2051134,Sanctified Scourgelord Chestguard,364,85,4,5,4,4,4,251,7,339,13,106,14,131,0,0,0,0,0,0,0,0,0,0,0,0
|
||||
2050474,Shrapnel Star,364,85,4,25,2,16,38,105,3,79,7,79,32,52,36,52,0,0,0,0,0,0,0,0,0,0
|
||||
2051250,Sanctified Shadowblade Breastplate,377,85,4,5,4,2,38,328,3,283,7,283,32,189,44,164,0,0,0,0,0,0,0,0,0,0
|
||||
2051276,Sanctified Lightsworn Gauntlets,377,85,4,10,4,4,4,227,7,240,32,139,31,127,0,0,0,0,0,0,0,0,0,0,0,0
|
||||
2051220,Sanctified Ymirjar Lord's Breastplate,377,85,4,5,4,4,4,283,7,389,13,136,14,136,0,0,0,0,0,0,0,0,0,0,0,0
|
||||
|
372
cmd/create_emblem_items/compare_power_stats.go
Normal file
372
cmd/create_emblem_items/compare_power_stats.go
Normal file
@@ -0,0 +1,372 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"log"
|
||||
"math"
|
||||
|
||||
"github.com/araxiaonline/endgame-item-generator/internal/db/mysql"
|
||||
"github.com/araxiaonline/endgame-item-generator/internal/items"
|
||||
"github.com/araxiaonline/endgame-item-generator/internal/spells"
|
||||
)
|
||||
|
||||
// ComparePowerStats compares Attack Power and Spell Power stats between old generated items and new items
|
||||
// and logs the differences. This helps identify cases where new items might have lower power stats
|
||||
// despite having equal or higher item levels. Also checks for spells that add these stats.
|
||||
// If oldGenItem is empty (Entry = 0), it will only show stats for the new item.
|
||||
// Optionally filters by itemClass and itemSubClass (pass -1 to disable filtering)
|
||||
func ComparePowerStats(newItem mysql.DbItem, oldGenItem mysql.DbItem, itemName string, itemClass int, itemSubClass ...int) {
|
||||
// No need to check for nil since we're using value types
|
||||
|
||||
// Check if we should filter by item class/subclass
|
||||
if itemClass >= 0 {
|
||||
// Skip if item class doesn't match
|
||||
if newItem.Class == nil || *newItem.Class != itemClass {
|
||||
return
|
||||
}
|
||||
|
||||
// Check subclass if provided
|
||||
if len(itemSubClass) > 0 && itemSubClass[0] >= 0 {
|
||||
if newItem.Subclass == nil || *newItem.Subclass != itemSubClass[0] {
|
||||
return
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
newItemLevel := 0
|
||||
oldItemLevel := 0
|
||||
entryID := 0
|
||||
originalEntry := 0
|
||||
|
||||
if newItem.ItemLevel != nil {
|
||||
newItemLevel = *newItem.ItemLevel
|
||||
}
|
||||
|
||||
if oldGenItem.ItemLevel != nil {
|
||||
oldItemLevel = *oldGenItem.ItemLevel
|
||||
}
|
||||
|
||||
entryID = newItem.Entry
|
||||
|
||||
// Check if we have a valid old item to compare with
|
||||
isComparing := oldGenItem.Entry != 0
|
||||
|
||||
// Calculate the original entry ID by subtracting the bump (20000000) from old generated item
|
||||
if isComparing {
|
||||
originalEntry = oldGenItem.Entry - 20000000
|
||||
} else {
|
||||
// If we don't have an old item, try to use the new item's entry as the original
|
||||
originalEntry = newItem.Entry
|
||||
}
|
||||
|
||||
// Try to get the original item to get its original level
|
||||
originalItemLevel := 0
|
||||
db, err := mysql.GetDb()
|
||||
if err == nil {
|
||||
originalItem, err := db.GetItem(originalEntry)
|
||||
if err == nil && originalItem.ItemLevel != nil {
|
||||
originalItemLevel = *originalItem.ItemLevel
|
||||
log.Printf(" Original item found: Entry %d, Level %d", originalEntry, originalItemLevel)
|
||||
}
|
||||
}
|
||||
|
||||
// If we couldn't get the original item level, use the old generated item level
|
||||
if originalItemLevel == 0 {
|
||||
originalItemLevel = oldItemLevel
|
||||
}
|
||||
|
||||
// Find Attack Power and Spell Power in the new item
|
||||
newAttackPower := findStatValue(&newItem, items.STAT.AttackPower)
|
||||
newSpellPower := findStatValue(&newItem, items.STAT.SpellPower)
|
||||
|
||||
// Find Attack Power and Spell Power from spells in the new item
|
||||
newSpellAttackPower, newSpellSpellPower := findPowerFromSpells(&newItem, originalItemLevel)
|
||||
|
||||
// Add spell-based power to direct stats for the new item
|
||||
newAttackPower += newSpellAttackPower
|
||||
newSpellPower += newSpellSpellPower
|
||||
|
||||
if isComparing {
|
||||
// If we have an old item to compare with, get its stats too
|
||||
oldAttackPower := findStatValue(&oldGenItem, items.STAT.AttackPower)
|
||||
oldSpellPower := findStatValue(&oldGenItem, items.STAT.SpellPower)
|
||||
|
||||
// Find Attack Power and Spell Power from spells in the old item
|
||||
oldSpellAttackPower, oldSpellSpellPower := findPowerFromSpells(&oldGenItem)
|
||||
|
||||
// Add spell-based power to direct stats for the old item
|
||||
oldAttackPower += oldSpellAttackPower
|
||||
oldSpellPower += oldSpellSpellPower
|
||||
|
||||
// Log Attack Power comparison if either item has it
|
||||
if oldAttackPower > 0 || newAttackPower > 0 {
|
||||
log.Printf("===== ATTACK POWER COMPARISON: %s (Entry: %d) =====", itemName, entryID)
|
||||
log.Printf(" Item Level: %d -> %d", oldItemLevel, newItemLevel)
|
||||
log.Printf(" Attack Power: %d -> %d", oldAttackPower, newAttackPower)
|
||||
|
||||
// Log spell-based Attack Power if present
|
||||
if oldSpellAttackPower > 0 || newSpellAttackPower > 0 {
|
||||
log.Printf(" Attack Power from Spells: %d -> %d", oldSpellAttackPower, newSpellAttackPower)
|
||||
}
|
||||
|
||||
// Highlight if new item has lower Attack Power despite equal or higher item level
|
||||
if newItemLevel >= oldItemLevel && newAttackPower < oldAttackPower && newAttackPower > 0 {
|
||||
log.Printf(" WARNING: Attack Power DECREASED despite item level being equal or higher!")
|
||||
}
|
||||
log.Printf("==========================================")
|
||||
}
|
||||
|
||||
// Log Spell Power comparison if either item has it
|
||||
if oldSpellPower > 0 || newSpellPower > 0 {
|
||||
log.Printf("===== SPELL POWER COMPARISON: %s (Entry: %d) =====", itemName, entryID)
|
||||
log.Printf(" Item Level: %d -> %d", oldItemLevel, newItemLevel)
|
||||
log.Printf(" Spell Power: %d -> %d", oldSpellPower, newSpellPower)
|
||||
|
||||
// Log spell-based Spell Power if present
|
||||
if oldSpellSpellPower > 0 || newSpellSpellPower > 0 {
|
||||
log.Printf(" Spell Power from Spells: %d -> %d", oldSpellSpellPower, newSpellSpellPower)
|
||||
}
|
||||
|
||||
// Highlight if new item has lower Spell Power despite equal or higher item level
|
||||
if newItemLevel >= oldItemLevel && newSpellPower < oldSpellPower && newSpellPower > 0 {
|
||||
log.Printf(" WARNING: Spell Power DECREASED despite item level being equal or higher!")
|
||||
}
|
||||
log.Printf("==========================================")
|
||||
}
|
||||
} else {
|
||||
// If we don't have an old item to compare with, just show the new item's stats
|
||||
|
||||
// Log Attack Power if present
|
||||
if newAttackPower > 0 {
|
||||
log.Printf("===== NEW ITEM ATTACK POWER: %s (Entry: %d) =====", itemName, entryID)
|
||||
log.Printf(" Item Level: %d", newItemLevel)
|
||||
log.Printf(" Attack Power: %d", newAttackPower)
|
||||
|
||||
// Log spell-based Attack Power if present
|
||||
if newSpellAttackPower > 0 {
|
||||
log.Printf(" Attack Power from Spells: %d", newSpellAttackPower)
|
||||
log.Printf(" Original Item Level: %d, New Item Level: %d", originalItemLevel, newItemLevel)
|
||||
}
|
||||
log.Printf("==========================================")
|
||||
}
|
||||
|
||||
// Log Spell Power if present
|
||||
if newSpellPower > 0 {
|
||||
log.Printf("===== NEW ITEM SPELL POWER: %s (Entry: %d) =====", itemName, entryID)
|
||||
log.Printf(" Item Level: %d", newItemLevel)
|
||||
log.Printf(" Spell Power: %d", newSpellPower)
|
||||
|
||||
// Log spell-based Spell Power if present
|
||||
if newSpellSpellPower > 0 {
|
||||
log.Printf(" Spell Power from Spells: %d", newSpellSpellPower)
|
||||
log.Printf(" Original Item Level: %d, New Item Level: %d", originalItemLevel, newItemLevel)
|
||||
}
|
||||
log.Printf("==========================================")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// findStatValue searches through all stat slots in an item to find a specific stat type
|
||||
// and returns its value. Returns 0 if the stat is not found.
|
||||
func findStatValue(item *mysql.DbItem, statType int) int {
|
||||
if item == nil {
|
||||
return 0
|
||||
}
|
||||
|
||||
// Check all stat slots
|
||||
if item.StatType1 != nil && *item.StatType1 == statType && item.StatValue1 != nil {
|
||||
return *item.StatValue1
|
||||
}
|
||||
if item.StatType2 != nil && *item.StatType2 == statType && item.StatValue2 != nil {
|
||||
return *item.StatValue2
|
||||
}
|
||||
if item.StatType3 != nil && *item.StatType3 == statType && item.StatValue3 != nil {
|
||||
return *item.StatValue3
|
||||
}
|
||||
if item.StatType4 != nil && *item.StatType4 == statType && item.StatValue4 != nil {
|
||||
return *item.StatValue4
|
||||
}
|
||||
if item.StatType5 != nil && *item.StatType5 == statType && item.StatValue5 != nil {
|
||||
return *item.StatValue5
|
||||
}
|
||||
if item.StatType6 != nil && *item.StatType6 == statType && item.StatValue6 != nil {
|
||||
return *item.StatValue6
|
||||
}
|
||||
if item.StatType7 != nil && *item.StatType7 == statType && item.StatValue7 != nil {
|
||||
return *item.StatValue7
|
||||
}
|
||||
if item.StatType8 != nil && *item.StatType8 == statType && item.StatValue8 != nil {
|
||||
return *item.StatValue8
|
||||
}
|
||||
if item.StatType9 != nil && *item.StatType9 == statType && item.StatValue9 != nil {
|
||||
return *item.StatValue9
|
||||
}
|
||||
if item.StatType10 != nil && *item.StatType10 == statType && item.StatValue10 != nil {
|
||||
return *item.StatValue10
|
||||
}
|
||||
|
||||
return 0
|
||||
}
|
||||
|
||||
// findPowerFromSpells checks for spells on an item that add Attack Power or Spell Power
|
||||
// and returns the total values for each. If originalItemLevel is provided, it will be used
|
||||
// to scale the spell values to match what they would be after actual scaling.
|
||||
func findPowerFromSpells(item *mysql.DbItem, originalItemLevel ...int) (attackPower int, spellPower int) {
|
||||
if item == nil {
|
||||
return 0, 0
|
||||
}
|
||||
|
||||
// Set the spell IDs from the DbItem
|
||||
for i := 1; i <= 3; i++ {
|
||||
var spellID *int
|
||||
|
||||
switch i {
|
||||
case 1:
|
||||
spellID = item.SpellId1
|
||||
case 2:
|
||||
spellID = item.SpellId2
|
||||
case 3:
|
||||
spellID = item.SpellId3
|
||||
}
|
||||
|
||||
if spellID == nil || *spellID == 0 {
|
||||
continue
|
||||
}
|
||||
|
||||
// Get the spell from the database
|
||||
db, err := mysql.GetDb()
|
||||
if err != nil {
|
||||
log.Printf("Failed to get database connection: %v", err)
|
||||
continue
|
||||
}
|
||||
|
||||
dbSpell, err := db.GetSpell(*spellID)
|
||||
if err != nil {
|
||||
log.Printf("Failed to get spell %d: %v", *spellID, err)
|
||||
continue
|
||||
}
|
||||
|
||||
// Create a Spell struct
|
||||
spell := spells.Spell{
|
||||
DbSpell: dbSpell,
|
||||
ItemSpellSlot: i,
|
||||
}
|
||||
|
||||
// Scale the spell if we have original item level and current item level
|
||||
scaledSpell := spell
|
||||
if len(originalItemLevel) > 0 && originalItemLevel[0] > 0 && item.ItemLevel != nil && item.Quality != nil {
|
||||
// Create a copy of the spell to scale
|
||||
scaledSpell = spell
|
||||
|
||||
// Use the new ForceScaleSpell method to scale the spell regardless of effect type
|
||||
// This ensures all spells get scaled, not just the ones that qualify for ScaleSpell
|
||||
// No tier specified - use base scaling only
|
||||
err := scaledSpell.ForceScaleSpell(originalItemLevel[0], *item.ItemLevel, *item.Quality, 3)
|
||||
if err == nil {
|
||||
log.Printf(" Scaled spell %s (ID: %d) from level %d to %d using ForceScaleSpell",
|
||||
scaledSpell.Name, scaledSpell.ID, originalItemLevel[0], *item.ItemLevel)
|
||||
|
||||
// Show before/after values for effect points
|
||||
if spell.EffectBasePoints1 != 0 {
|
||||
log.Printf(" Effect1: Original value: %d, Scaled value: %d", spell.EffectBasePoints1, scaledSpell.EffectBasePoints1)
|
||||
}
|
||||
if spell.EffectBasePoints2 != 0 {
|
||||
log.Printf(" Effect2: Original value: %d, Scaled value: %d", spell.EffectBasePoints2, scaledSpell.EffectBasePoints2)
|
||||
}
|
||||
if spell.EffectBasePoints3 != 0 {
|
||||
log.Printf(" Effect3: Original value: %d, Scaled value: %d", spell.EffectBasePoints3, scaledSpell.EffectBasePoints3)
|
||||
}
|
||||
} else {
|
||||
log.Printf(" Error scaling spell %s (ID: %d): %v", spell.Name, spell.ID, err)
|
||||
}
|
||||
}
|
||||
|
||||
// Convert spell to stats
|
||||
convStats, err := scaledSpell.ConvertToStats()
|
||||
if err != nil {
|
||||
log.Printf(" Error converting spell to stats: %v", err)
|
||||
continue
|
||||
}
|
||||
|
||||
// Check for Attack Power or Spell Power in the converted stats
|
||||
for _, stat := range convStats {
|
||||
if stat.StatType == items.STAT.AttackPower {
|
||||
attackPower += stat.StatValue
|
||||
if len(originalItemLevel) > 0 && originalItemLevel[0] > 0 {
|
||||
logSpellDetails(spell, "Attack Power", stat.StatValue, item, originalItemLevel[0])
|
||||
} else {
|
||||
logSpellDetails(spell, "Attack Power", stat.StatValue, item)
|
||||
}
|
||||
} else if stat.StatType == items.STAT.SpellPower {
|
||||
spellPower += stat.StatValue
|
||||
if len(originalItemLevel) > 0 && originalItemLevel[0] > 0 {
|
||||
logSpellDetails(spell, "Spell Power", stat.StatValue, item, originalItemLevel[0])
|
||||
} else {
|
||||
logSpellDetails(spell, "Spell Power", stat.StatValue, item)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return attackPower, spellPower
|
||||
}
|
||||
|
||||
// logSpellDetails logs detailed information about a spell that adds power stats
|
||||
func logSpellDetails(spell spells.Spell, powerType string, powerValue int, item *mysql.DbItem, originalItemLevel ...int) {
|
||||
// Log basic spell information
|
||||
log.Printf(" Found %s spell: %s (ID: %d) adding %d %s Description: %s", powerType, spell.Name, spell.ID, powerValue, powerType, spell.Description)
|
||||
|
||||
// Log aura description if available
|
||||
if spell.AuraDescription != "" {
|
||||
log.Printf(" Aura: %s", spell.AuraDescription)
|
||||
}
|
||||
|
||||
// Show what the spell would look like if scaled
|
||||
if item.ItemLevel != nil && item.Quality != nil {
|
||||
// Calculate what this spell would look like if scaled to a higher item level
|
||||
currentLevel := *item.ItemLevel
|
||||
startingLevel := currentLevel
|
||||
|
||||
// If original item level is provided, use it as the starting point for scaling
|
||||
if len(originalItemLevel) > 0 && originalItemLevel[0] > 0 {
|
||||
startingLevel = originalItemLevel[0]
|
||||
log.Printf(" Using original item level %d as scaling base (current level: %d)", startingLevel, currentLevel)
|
||||
}
|
||||
|
||||
qualModifier := 1.0
|
||||
switch *item.Quality {
|
||||
case 3: // Rare
|
||||
qualModifier = 1.20
|
||||
case 4: // Epic
|
||||
qualModifier = 1.30
|
||||
case 5: // Legendary
|
||||
qualModifier = 1.40
|
||||
}
|
||||
|
||||
// Determine the appropriate multiplier based on spell effect type
|
||||
effectMultiplier := 1.0
|
||||
|
||||
// Check for stat-boosting effects (Attack Power and Spell Power)
|
||||
if powerType == "Attack Power" || powerType == "Spell Power" {
|
||||
// For stat buffs like Attack Power and Spell Power, use a higher multiplier
|
||||
// to account for the significant item level jumps
|
||||
effectMultiplier = 2.0
|
||||
}
|
||||
|
||||
// Show scaling examples for larger item level jumps
|
||||
for _, newLevel := range []int{100, 150, 200, 250} {
|
||||
if newLevel <= currentLevel {
|
||||
continue // Skip levels that are lower than current
|
||||
}
|
||||
|
||||
// Calculate level ratio with a power curve to account for exponential scaling
|
||||
// Use the original item level as the starting point if available
|
||||
levelRatio := math.Pow(float64(newLevel)/float64(startingLevel), 1.3)
|
||||
|
||||
// Simulate the spell scaling formula with enhanced scaling for large level jumps
|
||||
scaledValue := int(float64(powerValue) * levelRatio * qualModifier * effectMultiplier)
|
||||
|
||||
log.Printf(" If scaled to item level %d: ~%d %s (%.2fx increase)",
|
||||
newLevel, scaledValue, powerType, float64(scaledValue)/float64(powerValue))
|
||||
}
|
||||
}
|
||||
}
|
||||
BIN
cmd/create_emblem_items/create_emblem_items
Executable file
BIN
cmd/create_emblem_items/create_emblem_items
Executable file
Binary file not shown.
165
cmd/create_emblem_items/main.go
Normal file
165
cmd/create_emblem_items/main.go
Normal file
@@ -0,0 +1,165 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"flag"
|
||||
"log"
|
||||
"os"
|
||||
|
||||
"github.com/araxiaonline/endgame-item-generator/internal/db/mysql"
|
||||
"github.com/araxiaonline/endgame-item-generator/internal/items"
|
||||
"github.com/gocarina/gocsv"
|
||||
"github.com/joho/godotenv"
|
||||
|
||||
_ "github.com/go-sql-driver/mysql"
|
||||
)
|
||||
|
||||
// This will accept a list of existing items pre-scaled by ChatGPT and scale stats
|
||||
// based on our server modifiers and tier modifiers. A sample format is in the same directory.
|
||||
func main() {
|
||||
|
||||
log.SetFlags(log.LstdFlags | log.Lshortfile)
|
||||
godotenv.Load("../../.env")
|
||||
|
||||
filename := flag.String("filename", "", "csv of the items to read in")
|
||||
tier := flag.Int("tier", 1, "tier of the items to read in")
|
||||
flag.Parse()
|
||||
|
||||
if *filename == "" {
|
||||
log.Fatal("item file is required")
|
||||
}
|
||||
|
||||
itemsFile, err := os.OpenFile(*filename, os.O_RDWR|os.O_CREATE, os.ModePerm)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
defer itemsFile.Close()
|
||||
|
||||
// Connection to mysql database
|
||||
mysqlDb, err := mysql.Connect(&mysql.MySqlConfig{
|
||||
Host: os.Getenv("DB_HOST"),
|
||||
User: os.Getenv("DB_USER"),
|
||||
Password: os.Getenv("DB_PASSWORD"),
|
||||
Database: os.Getenv("DB_NAME"),
|
||||
})
|
||||
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
|
||||
csvItems := []*mysql.DbItemCsv{}
|
||||
|
||||
if err := gocsv.UnmarshalFile(itemsFile, &csvItems); err != nil { // Load items from file
|
||||
panic(err)
|
||||
}
|
||||
|
||||
// dbItems := []*mysql.DbItem{}
|
||||
|
||||
for _, item := range csvItems {
|
||||
// ConvertCsvToDbItem already tries to find the original item and preserve its fields
|
||||
dbItem, err := mysqlDb.ConvertCsvToDbItem(*item)
|
||||
if err != nil {
|
||||
log.Printf("Failed to convert item %d - %s to DbItem: %v", item.Entry, item.Name, err)
|
||||
continue
|
||||
}
|
||||
|
||||
// Get the original item for reference (e.g., for scaling calculations)
|
||||
originalEntry := item.Entry - 2000000
|
||||
originalItem, err := mysqlDb.GetItem(originalEntry)
|
||||
if err != nil {
|
||||
log.Printf("Failed to get original item %d - %s: %v", originalEntry, item.Name, err)
|
||||
continue
|
||||
}
|
||||
|
||||
// Create a new item from the dbItem (which already has preserved fields)
|
||||
newItem := items.ItemFromDbItem(dbItem)
|
||||
|
||||
// Scale armor based on the new item level
|
||||
newItem.ScaleArmor(*item.ItemLevel)
|
||||
|
||||
if *newItem.Class == 2 && *newItem.MinDmg1 > 0 {
|
||||
_, err := newItem.ScaleDPS(*originalItem.ItemLevel, *item.ItemLevel)
|
||||
if err != nil {
|
||||
log.Printf("Failed to scale DPS: %v", err)
|
||||
} else {
|
||||
log.Printf("Successfully scaled DPS for item %d - %s to oldMinD dmg1: %f, oldMaxDmg1: %f, minDmg1: %f, maxDmg1: %f", item.Entry, item.Name, *originalItem.MinDmg1, *originalItem.MaxDmg1, *newItem.MinDmg1, *newItem.MaxDmg1)
|
||||
}
|
||||
}
|
||||
|
||||
// Now need to apply tier modifiers and stat modifiers to the items
|
||||
newItem.ApplyTierModifiers(*tier)
|
||||
|
||||
// Make a copy of the spells for the new item
|
||||
spells, err := newItem.GetSpells()
|
||||
if err != nil {
|
||||
log.Printf("Failed to get spells for item %d - %s: %v", item.Entry, item.Name, err)
|
||||
continue
|
||||
}
|
||||
|
||||
for _, spell := range spells {
|
||||
|
||||
newSpellId := spell.ID + 3000000
|
||||
|
||||
// Copy the spell to the new vendor table (why vendor... not sure just random I guess I made up)
|
||||
mysqlDb.CopySpell("spell_dbc", "spells_new_vendor", spell.ID, newSpellId)
|
||||
|
||||
// Scale the spell now and replace the key scaling aspects.
|
||||
spell.ForceScaleSpell(*originalItem.ItemLevel, *newItem.ItemLevel, *newItem.Quality, *tier)
|
||||
|
||||
// Create a copy of the spell with the new ID for the update
|
||||
scaledSpell := spell.DbSpell
|
||||
scaledSpell.ID = newSpellId
|
||||
|
||||
// Write the scaled spell values to update the copied spell
|
||||
// log.Printf("Writing scaled spell ID %d with base points: %d, %d, %d",
|
||||
// newSpellId, scaledSpell.EffectBasePoints1, scaledSpell.EffectBasePoints2, scaledSpell.EffectBasePoints3)
|
||||
mysqlDb.WriteSpell("spells_new_vendor", scaledSpell)
|
||||
|
||||
// Update the original newItem spellID with the new scaled spell ID
|
||||
newItem.UpdateSpellID(spell.ID, newSpellId)
|
||||
}
|
||||
|
||||
// First, copy the original item to preserve all fields
|
||||
newEntry := originalEntry + 2000000
|
||||
err = mysqlDb.CopyItem("item_template", "item_template_new_vendor", originalEntry, newEntry)
|
||||
if err != nil {
|
||||
log.Printf("Failed to copy item %d: %v", originalEntry, err)
|
||||
continue
|
||||
}
|
||||
|
||||
// Then write the updated item to override specific fields
|
||||
newItem.DbItem.Entry = newEntry
|
||||
mysqlDb.WriteItem("item_template_new_vendor", newItem.DbItem)
|
||||
log.Printf("Successfully wrote item %d - %s to database", newEntry, item.Name)
|
||||
|
||||
// oldGenEntry := originalEntry + 20000000
|
||||
// oldGenItem, err := mysqlDb.GetItem(oldGenEntry)
|
||||
|
||||
// if err != nil {
|
||||
// //log.Printf("Failed to get old generated item %d - %s: %v", oldGenEntry, item.Name, err)
|
||||
// // Even if we can't find the old item, still show the new item's stats
|
||||
// emptyOldItem := mysql.DbItem{}
|
||||
// // Set the name for the comparison output
|
||||
// // Pass -1 for itemClass to disable filtering
|
||||
// ComparePowerStats(newItem.DbItem, emptyOldItem, item.Name, 4, 7)
|
||||
// } else {
|
||||
// // Compare Attack Power and Spell Power stats between old and new items
|
||||
// ComparePowerStats(newItem.DbItem, oldGenItem, item.Name, 4, 7)
|
||||
// }
|
||||
|
||||
// err = mysqlDb.WriteItem("item_template_new_vendor", dbItem)
|
||||
// if err != nil {
|
||||
// log.Printf("Failed to write item %d - %s to database: %v", item.Entry, item.Name, err)
|
||||
// continue
|
||||
// } else {
|
||||
// log.Printf("Successfully wrote item %d - %s to database", item.Entry, item.Name)
|
||||
// }
|
||||
|
||||
// Print the item in a more readable format
|
||||
// jsonData, err := json.MarshalIndent(dbItem, "", " ")
|
||||
// if err != nil {
|
||||
// log.Printf("Error marshaling item to JSON: %v", err)
|
||||
// } else {
|
||||
// log.Printf("Item %d - %s:\n%s", dbItem.Entry, dbItem.Name, string(jsonData))
|
||||
// }
|
||||
}
|
||||
}
|
||||
283
cmd/create_emblem_items/mythic-items.csv
Normal file
283
cmd/create_emblem_items/mythic-items.csv
Normal file
@@ -0,0 +1,283 @@
|
||||
entry,name,ItemLevel,RequiredLevel,Quality,InventoryType,class,subclass,stat_type1,stat_value1,stat_type2,stat_value2,stat_type3,stat_value3,stat_type4,stat_value4,stat_type5,stat_value5,stat_type6,stat_value6,stat_type7,stat_value7,stat_type8,stat_value8,stat_type9,stat_value9,stat_type10,stat_value10
|
||||
2039579,Heroes' Cryptstalker Tunic,300,80,4,5,4,3,3,93,7,117,5,62,36,79,31,62,0,0,0,0,0,0,0,0,0,0
|
||||
2040571,Valorous Redemption Headpiece,313,80,4,1,4,4,7,116,5,119,32,79,0,0,0,0,0,0,0,0,0,0,0,0,0,0
|
||||
2045212,Staff of Feral Furies,300,80,4,17,2,10,38,207,3,159,7,151,32,80,0,0,0,0,0,0,0,0,0,0,0,0
|
||||
2039557,Heroes' Dreamwalker Handgrips,300,80,4,10,4,2,3,77,7,102,32,68,36,51,0,0,0,0,0,0,0,0,0,0,0,0
|
||||
2039555,Heroes' Dreamwalker Legguards,300,80,4,7,4,2,3,113,7,139,32,79,37,57,0,0,0,0,0,0,0,0,0,0,0,0
|
||||
2040512,Valorous Earthshatter Legguards,313,80,4,7,4,3,7,153,5,119,36,91,0,0,0,0,0,0,0,0,0,0,0,0,0,0
|
||||
2039757,Idol of Worship,313,80,4,28,4,8,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0
|
||||
2040684,Mirror of Truth,300,80,4,12,4,0,32,130,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0
|
||||
2039578,Heroes' Cryptstalker Headpiece,300,80,4,1,4,3,3,113,7,108,5,72,32,68,36,46,0,0,0,0,0,0,0,0,0,0
|
||||
2039523,Heroes' Raiments of Faith,300,80,4,20,4,1,7,88,5,105,6,93,31,66,0,0,0,0,0,0,0,0,0,0,0,0
|
||||
2040565,Valorous Scourgeborne Faceguard,313,80,4,1,4,4,4,124,7,196,12,91,37,54,14,77,0,0,0,0,0,0,0,0,0,0
|
||||
2040715,Sigil of Haunted Dreams,300,80,4,28,4,10,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0
|
||||
2045210,Sen'jin Beakblade Longrifle,300,80,4,26,2,3,3,49,36,34,38,43,7,48,0,0,0,0,0,0,0,0,0,0,0,0
|
||||
2040694,Jorach's Crocolisk Skin Belt,300,80,4,6,4,2,3,62,7,94,32,71,37,58,0,0,0,0,0,0,0,0,0,0,0,0
|
||||
2040518,Valorous Earthshatter Shoulderpads,313,80,4,3,4,3,7,94,5,88,32,77,31,57,0,0,0,0,0,0,0,0,0,0,0,0
|
||||
2045077,Dagger of the Rising Moon,300,80,4,13,2,15,38,120,7,66,31,58,32,34,0,0,0,0,0,0,0,0,0,0,0,0
|
||||
2040449,Valorous Robe of Faith,313,80,4,20,4,1,7,116,5,103,6,119,0,0,0,0,0,0,0,0,0,0,0,0,0,0
|
||||
2040419,Valorous Frostfire Shoulderpads,313,80,4,3,4,1,7,88,5,88,32,82,36,54,0,0,0,0,0,0,0,0,0,0,0,0
|
||||
2039583,Heroes' Earthshatter Headpiece,300,80,4,1,4,3,7,102,5,100,36,80,0,0,0,0,0,0,0,0,0,0,0,0,0,0
|
||||
2040682,Sundial of the Exiled,300,80,4,12,4,0,32,130,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0
|
||||
2039545,Heroes' Dreamwalker Cover,300,80,4,1,4,2,7,103,5,100,32,82,31,55,0,0,0,0,0,0,0,0,0,0,0,0
|
||||
2039590,Heroes' Earthshatter Spaulders,300,80,4,3,4,3,7,75,5,79,32,68,0,0,0,0,0,0,0,0,0,0,0,0,0,0
|
||||
2040267,Totem of Hex,313,80,4,28,4,9,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0
|
||||
2039628,Heroes' Redemption Headpiece,300,80,4,1,4,4,7,103,5,106,32,68,0,0,0,0,0,0,0,0,0,0,0,0,0,0
|
||||
2039611,Heroes' Dreadnaught Breastplate,300,80,4,5,4,4,4,125,7,172,12,72,13,72,15,58,0,0,0,0,0,0,0,0,0,0
|
||||
2040421,Valorous Plagueheart Circlet,313,80,4,1,4,1,7,153,5,91,6,77,36,86,0,0,0,0,0,0,0,0,0,0,0,0
|
||||
2040500,Valorous Bonescythe Legplates,313,80,4,7,4,2,3,142,7,136,36,89,31,65,0,0,0,0,0,0,0,0,0,0,0,0
|
||||
2040712,Idol of Steadfast Renewal,300,80,4,28,4,8,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0
|
||||
2040741,Cuffs of the Shadow Ascendant,313,80,4,9,4,1,7,65,5,66,36,58,0,0,0,0,0,0,0,0,0,0,0,0,0,0
|
||||
2045214,Scalpel of the Royal Apothecary,300,80,4,21,2,15,5,58,6,58,7,43,36,46,45,632,0,0,0,0,0,0,0,0,0,0
|
||||
2039612,Heroes' Dreadnaught Legguards,300,80,4,7,4,4,4,137,7,172,12,74,14,63,13,48,0,0,0,0,0,0,0,0,0,0
|
||||
2040705,Libram of Renewal,300,80,4,28,4,7,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0
|
||||
2040737,Pigmented Clan Bindings,313,80,4,9,4,3,7,85,5,58,36,43,0,0,0,0,0,0,0,0,0,0,0,0,0,0
|
||||
2040547,Valorous Dreadnaught Legguards,313,80,4,7,4,4,4,155,7,196,12,82,14,69,13,66,0,0,0,0,0,0,0,0,0,0
|
||||
2045689,Inscribed Loop of the Kirin Tor,313,80,4,11,4,0,45,102,7,85,5,58,6,58,43,29,0,0,0,0,0,0,0,0,0,0
|
||||
2040523,Valorous Earthshatter Chestguard,313,80,4,5,4,3,3,103,7,134,5,69,31,89,37,68,0,0,0,0,0,0,0,0,0,0
|
||||
2039640,Heroes' Redemption Faceguard,300,80,4,1,4,4,4,111,7,172,12,66,37,46,0,0,0,0,0,0,0,0,0,0,0,0
|
||||
2040576,Valorous Redemption Helm,313,80,4,1,4,4,4,131,7,103,36,145,31,62,0,0,0,0,0,0,0,0,0,0,0,0
|
||||
2039606,Heroes' Dreadnaught Battleplate,300,80,4,5,4,4,4,113,7,139,32,125,31,80,0,0,0,0,0,0,0,0,0,0,0,0
|
||||
2040423,Valorous Plagueheart Robe,313,80,4,20,4,1,7,153,5,103,6,102,31,79,0,0,0,0,0,0,0,0,0,0,0,0
|
||||
2039625,Heroes' Scourgeborne Faceguard,300,80,4,1,4,4,4,111,7,172,12,75,37,46,14,66,0,0,0,0,0,0,0,0,0,0
|
||||
2040559,Valorous Scourgeborne Chestguard,313,80,4,5,4,4,4,142,7,196,12,82,14,82,13,69,0,0,0,0,0,0,0,0,0,0
|
||||
2039588,Heroes' Earthshatter Tunic,300,80,4,5,4,3,7,97,5,110,36,82,0,0,0,0,0,0,0,0,0,0,0,0,0,0
|
||||
2040503,Valorous Cryptstalker Tunic,313,80,4,5,4,3,3,103,7,134,5,69,36,89,31,68,0,0,0,0,0,0,0,0,0,0
|
||||
2039553,Heroes' Dreamwalker Headguard,300,80,4,1,4,2,3,93,7,139,32,68,44,66,0,0,0,0,0,0,0,0,0,0,0,0
|
||||
2040460,Valorous Dreamwalker Handguards,313,80,4,10,4,2,7,85,5,88,6,85,36,54,0,0,0,0,0,0,0,0,0,0,0,0
|
||||
2040424,Valorous Plagueheart Shoulderpads,313,80,4,3,4,1,7,113,5,77,36,85,31,54,45,120,0,0,0,0,0,0,0,0,0,0
|
||||
2040699,Handbook of Obscure Remedies,300,80,4,23,4,0,7,66,5,55,6,58,36,38,0,0,0,0,0,0,0,0,0,0,0,0
|
||||
2039597,Heroes' Earthshatter Chestguard,300,80,4,5,4,3,3,93,7,117,5,62,31,79,37,62,0,0,0,0,0,0,0,0,0,0
|
||||
2040719,Band of Channeled Magic,313,80,4,11,4,0,7,65,5,63,6,49,36,66,0,0,0,0,0,0,0,0,0,0,0,0
|
||||
2039592,Heroes' Earthshatter Hauberk,300,80,4,5,4,3,7,103,5,106,36,77,32,82,0,0,0,0,0,0,0,0,0,0,0,0
|
||||
2039626,Heroes' Scourgeborne Legguards,300,80,4,7,4,4,4,111,7,172,12,68,13,99,31,46,0,0,0,0,0,0,0,0,0,0
|
||||
2039519,Heroes' Gloves of Faith,300,80,4,10,4,1,7,69,5,74,6,75,32,54,0,0,0,0,0,0,0,0,0,0,0,0
|
||||
2039618,Heroes' Scourgeborne Gauntlets,300,80,4,10,4,4,4,88,7,153,32,71,31,51,0,0,0,0,0,0,0,0,0,0,0,0
|
||||
2039560,Heroes' Bonescythe Gauntlets,300,80,4,10,4,2,3,89,7,83,32,68,31,51,38,158,0,0,0,0,0,0,0,0,0,0
|
||||
2040529,Valorous Dreadnaught Legplates,313,80,4,7,4,4,4,131,7,155,32,130,37,102,0,0,0,0,0,0,0,0,0,0,0,0
|
||||
2040191,Libram of Radiance,313,80,4,28,4,7,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0
|
||||
2039613,Heroes' Dreadnaught Pauldrons,300,80,4,3,4,4,4,89,7,134,12,49,13,68,15,38,0,0,0,0,0,0,0,0,0,0
|
||||
2040738,Wristwraps of the Cutthroat,313,80,4,9,4,2,3,58,7,85,36,63,0,0,0,0,0,0,0,0,0,0,0,0,0,0
|
||||
2045076,Teldrassil Protector,300,80,4,13,2,0,4,44,7,66,12,68,14,29,0,0,0,0,0,0,0,0,0,0,0,0
|
||||
2040581,Valorous Redemption Faceguard,313,80,4,1,4,4,4,124,7,196,12,102,37,54,0,0,0,0,0,0,0,0,0,0,0,0
|
||||
2040696,Plush Sash of Guzbah,300,80,4,6,4,1,7,75,5,80,36,65,31,51,0,0,0,0,0,0,0,0,0,0,0,0
|
||||
2040710,Totem of Splintering,300,80,4,28,4,9,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0
|
||||
2040716,Lillehoff's Winged Blades,300,80,4,25,2,16,3,29,7,41,32,41,0,0,0,0,0,0,0,0,0,0,0,0,0,0
|
||||
2040509,Valorous Earthshatter Handguards,313,80,4,10,4,3,7,99,5,85,32,69,0,0,0,0,0,0,0,0,0,0,0,0,0,0
|
||||
2039593,Heroes' Earthshatter Gloves,300,80,4,10,4,3,7,88,5,74,31,58,0,0,0,0,0,0,0,0,0,0,0,0,0,0
|
||||
2040724,Cloak of Kea Feathers,313,80,4,16,4,1,7,65,5,66,36,43,0,0,0,0,0,0,0,0,0,0,0,0,0,0
|
||||
2040584,Valorous Redemption Shoulderguards,313,80,4,3,4,4,4,105,7,155,12,62,13,57,14,60,0,0,0,0,0,0,0,0,0,0
|
||||
2039499,Heroes' Plagueheart Shoulderpads,300,80,4,3,4,1,7,102,5,68,36,74,31,46,0,0,0,0,0,0,0,0,0,0,0,0
|
||||
2040746,Pack-Ice Striders,313,80,4,8,4,3,3,75,7,116,5,62,31,60,0,0,0,0,0,0,0,0,0,0,0,0
|
||||
2040465,Valorous Dreamwalker Spaulders,313,80,4,3,4,2,7,85,5,85,6,88,32,54,0,0,0,0,0,0,0,0,0,0,0,0
|
||||
2040556,Valorous Scourgeborne Legplates,313,80,4,7,4,4,4,131,7,155,32,130,36,102,0,0,0,0,0,0,0,0,0,0,0,0
|
||||
2040502,Valorous Bonescythe Pauldrons,313,80,4,3,4,2,3,85,7,113,32,89,36,66,0,0,0,0,0,0,0,0,0,0,0,0
|
||||
2039609,Heroes' Dreadnaught Gauntlets,300,80,4,10,4,4,4,88,7,153,37,71,31,51,0,0,0,0,0,0,0,0,0,0,0,0
|
||||
2039531,Heroes' Dreamwalker Headpiece,300,80,4,1,4,2,7,103,5,106,6,74,0,0,0,0,0,0,0,0,0,0,0,0,0,0
|
||||
2039631,Heroes' Redemption Spaulders,300,80,4,3,4,4,7,75,5,80,32,74,36,48,0,0,0,0,0,0,0,0,0,0,0,0
|
||||
2040471,Valorous Dreamwalker Raiments,313,80,4,20,4,2,3,131,7,158,37,62,32,88,0,0,0,0,0,0,0,0,0,0,0,0
|
||||
2040454,Valorous Handwraps of Faith,313,80,4,10,4,1,7,80,5,82,32,86,36,63,0,0,0,0,0,0,0,0,0,0,0,0
|
||||
2039539,Heroes' Dreamwalker Leggings,300,80,4,7,4,2,7,103,5,100,6,105,32,55,0,0,0,0,0,0,0,0,0,0,0,0
|
||||
2040493,Valorous Dreamwalker Legguards,313,80,4,7,4,2,3,131,7,158,32,85,37,65,0,0,0,0,0,0,0,0,0,0,0,0
|
||||
2040578,Valorous Redemption Shoulderplates,313,80,4,3,4,4,4,116,7,122,32,91,31,66,0,0,0,0,0,0,0,0,0,0,0,0
|
||||
2040466,Valorous Dreamwalker Gloves,313,80,4,10,4,2,7,88,5,88,6,54,32,82,0,0,0,0,0,0,0,0,0,0,0,0
|
||||
2039495,Heroes' Frostfire Gloves,300,80,4,10,4,1,7,88,5,79,32,74,31,51,0,0,0,0,0,0,0,0,0,0,0,0
|
||||
2040458,Valorous Raiments of Faith,313,80,4,20,4,1,7,116,5,119,6,102,31,77,0,0,0,0,0,0,0,0,0,0,0,0
|
||||
2045691,Inscribed Signet of the Kirin Tor,313,80,4,11,4,0,45,102,7,85,5,58,32,57,36,58,0,0,0,0,0,0,0,0,0,0
|
||||
2040707,Libram of Obstruction,300,80,4,28,4,7,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0
|
||||
2039544,Heroes' Dreamwalker Gloves,300,80,4,10,4,2,7,75,5,79,6,46,32,74,0,0,0,0,0,0,0,0,0,0,0,0
|
||||
2040473,Valorous Dreamwalker Headguard,313,80,4,1,4,2,3,102,7,158,32,79,44,74,0,0,0,0,0,0,0,0,0,0,0,0
|
||||
2040701,Crygil's Discarded Plate Panel,300,80,4,14,4,6,4,58,7,116,12,52,13,51,31,38,0,0,0,0,0,0,0,0,0,0
|
||||
2040517,Valorous Earthshatter Kilt,313,80,4,7,4,3,7,153,5,119,32,91,31,65,0,0,0,0,0,0,0,0,0,0,0,0
|
||||
2045129,Gnomeregan Bonechopper,300,80,4,21,2,7,7,69,5,66,32,34,31,44,45,632,0,0,0,0,0,0,0,0,0,0
|
||||
2040514,Valorous Earthshatter Hauberk,313,80,4,5,4,3,7,116,5,119,36,88,32,93,0,0,0,0,0,0,0,0,0,0,0,0
|
||||
2040416,Valorous Frostfire Circlet,313,80,4,1,4,1,7,80,5,119,6,102,32,79,0,0,0,0,0,0,0,0,0,0,0,0
|
||||
2040750,Xintor's Expeditionary Boots,313,80,4,8,4,1,7,85,5,88,6,85,31,66,0,0,0,0,0,0,0,0,0,0,0,0
|
||||
2040520,Valorous Earthshatter Grips,313,80,4,10,4,3,3,82,7,93,5,66,32,60,36,48,0,0,0,0,0,0,0,0,0,0
|
||||
2039635,Heroes' Redemption Helm,300,80,4,1,4,4,4,114,7,139,36,125,31,44,0,0,0,0,0,0,0,0,0,0,0,0
|
||||
2040462,Valorous Dreamwalker Leggings,313,80,4,7,4,2,7,116,5,111,6,119,32,65,0,0,0,0,0,0,0,0,0,0,0,0
|
||||
2040708,Totem of the Elemental Plane,300,80,4,28,4,9,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0
|
||||
2040461,Valorous Dreamwalker Headpiece,313,80,4,1,4,2,7,116,5,119,6,86,0,0,0,0,0,0,0,0,0,0,0,0,0,0
|
||||
2040546,Valorous Dreadnaught Greathelm,313,80,4,1,4,4,4,124,7,196,12,89,31,54,0,0,0,0,0,0,0,0,0,0,0,0
|
||||
2040720,Renewal of Life,313,80,4,11,4,0,7,74,5,63,32,43,0,0,0,0,0,0,0,0,0,0,0,0,0,0
|
||||
2039604,Heroes' Earthshatter Shoulderguards,300,80,4,3,4,3,3,68,7,83,5,52,32,55,37,49,0,0,0,0,0,0,0,0,0,0
|
||||
2040507,Valorous Cryptstalker Spaulders,313,80,4,3,4,3,3,102,7,97,5,60,36,63,32,58,0,0,0,0,0,0,0,0,0,0
|
||||
2040525,Valorous Dreadnaught Battleplate,313,80,4,5,4,4,4,113,7,155,32,142,31,102,0,0,0,0,0,0,0,0,0,0,0,0
|
||||
2040499,Valorous Bonescythe Helmet,313,80,4,1,4,2,3,106,7,136,32,89,37,65,0,0,0,0,0,0,0,0,0,0,0,0
|
||||
2040680,Encircling Burnished Gold Chains,300,80,4,2,4,0,7,75,5,58,6,52,31,38,45,91,0,0,0,0,0,0,0,0,0,0
|
||||
2039582,Heroes' Cryptstalker Handguards,300,80,4,10,4,3,3,74,7,80,5,58,36,54,0,0,0,0,0,0,0,0,0,0,0,0
|
||||
2040548,Valorous Dreadnaught Pauldrons,313,80,4,3,4,4,4,102,7,155,12,55,13,77,15,44,0,0,0,0,0,0,0,0,0,0
|
||||
2039634,Heroes' Redemption Gauntlets,300,80,4,10,4,4,4,88,7,153,32,71,36,51,0,0,0,0,0,0,0,0,0,0,0,0
|
||||
2039641,Heroes' Redemption Legguards,300,80,4,7,4,4,4,137,7,172,12,74,15,63,0,0,0,0,0,0,0,0,0,0,0,0
|
||||
2039491,Heroes' Frostfire Circlet,300,80,4,1,4,1,7,83,5,99,6,93,32,66,0,0,0,0,0,0,0,0,0,0,0,0
|
||||
2039497,Heroes' Plagueheart Robe,300,80,4,20,4,1,7,139,5,91,6,99,31,55,0,0,0,0,0,0,0,0,0,0,0,0
|
||||
2039556,Heroes' Dreamwalker Shoulderpads,300,80,4,3,4,2,3,89,7,117,32,68,0,0,0,0,0,0,0,0,0,0,0,0,0,0
|
||||
2040552,Valorous Scourgeborne Gauntlets,313,80,4,10,4,4,4,103,7,172,32,75,31,60,0,0,0,0,0,0,0,0,0,0,0,0
|
||||
2040573,Valorous Redemption Spaulders,313,80,4,3,4,4,7,85,5,88,32,85,36,54,0,0,0,0,0,0,0,0,0,0,0,0
|
||||
2040459,Valorous Mantle of Faith,313,80,4,3,4,1,7,88,5,88,36,77,31,63,0,0,0,0,0,0,0,0,0,0,0,0
|
||||
2040472,Valorous Dreamwalker Handgrips,313,80,4,10,4,2,3,91,7,116,32,77,36,57,0,0,0,0,0,0,0,0,0,0,0,0
|
||||
2040574,Valorous Redemption Chestpiece,313,80,4,5,4,4,4,131,7,178,32,130,36,77,0,0,0,0,0,0,0,0,0,0,0,0
|
||||
2045078,Dagger of Lunar Purity,300,80,4,21,2,15,5,58,6,58,7,43,36,46,45,632,0,0,0,0,0,0,0,0,0,0
|
||||
2040580,Valorous Redemption Handguards,313,80,4,10,4,4,4,88,7,155,12,77,13,65,31,57,0,0,0,0,0,0,0,0,0,0
|
||||
2039546,Heroes' Dreamwalker Trousers,300,80,4,7,4,2,7,103,5,100,6,80,32,80,0,0,0,0,0,0,0,0,0,0,0,0
|
||||
2039561,Heroes' Bonescythe Helmet,300,80,4,1,4,2,3,93,7,125,32,80,37,57,0,0,0,0,0,0,0,0,0,0,0,0
|
||||
2040445,Valorous Gloves of Faith,313,80,4,10,4,1,7,83,5,85,6,63,32,63,0,0,0,0,0,0,0,0,0,0,0,0
|
||||
2040494,Valorous Dreamwalker Shoulderpads,313,80,4,3,4,2,3,103,7,131,32,75,0,0,0,0,0,0,0,0,0,0,0,0,0,0
|
||||
2039637,Heroes' Redemption Shoulderplates,300,80,4,3,4,4,4,102,7,108,32,77,31,60,0,0,0,0,0,0,0,0,0,0,0,0
|
||||
2040495,Valorous Bonescythe Breastplate,313,80,4,5,4,2,3,130,7,134,32,68,36,96,0,0,0,0,0,0,0,0,0,0,0,0
|
||||
2040448,Valorous Leggings of Faith,313,80,4,7,4,1,7,116,5,119,6,103,32,77,0,0,0,0,0,0,0,0,0,0,0,0
|
||||
2045208,Blade of the Keening Banshee,300,80,4,21,2,7,7,69,5,66,32,34,31,44,45,632,0,0,0,0,0,0,0,0,0,0
|
||||
2040695,Vine Belt of the Woodland Dryad,300,80,4,6,4,2,7,75,5,79,6,58,32,62,0,0,0,0,0,0,0,0,0,0,0,0
|
||||
2039632,Heroes' Redemption Gloves,300,80,4,10,4,4,7,75,5,79,36,46,32,74,0,0,0,0,0,0,0,0,0,0,0,0
|
||||
2040508,Valorous Earthshatter Tunic,313,80,4,5,4,3,7,116,5,119,36,91,0,0,0,0,0,0,0,0,0,0,0,0,0,0
|
||||
2040422,Valorous Plagueheart Leggings,313,80,4,7,4,1,7,134,5,111,32,79,36,102,0,0,0,0,0,0,0,0,0,0,0,0
|
||||
2040506,Valorous Cryptstalker Legguards,313,80,4,7,4,3,3,103,7,120,5,102,36,80,0,0,0,0,0,0,0,0,0,0,0,0
|
||||
2040748,Boots of Captain Ellis,313,80,4,8,4,2,3,57,7,131,32,66,36,85,0,0,0,0,0,0,0,0,0,0,0,0
|
||||
2039518,Heroes' Shoulderpads of Faith,300,80,4,3,4,1,7,75,5,79,6,68,32,55,0,0,0,0,0,0,0,0,0,0,0,0
|
||||
2039621,Heroes' Scourgeborne Shoulderplates,300,80,4,3,4,4,4,102,7,108,32,77,31,60,0,0,0,0,0,0,0,0,0,0,0,0
|
||||
2039498,Heroes' Plagueheart Leggings,300,80,4,7,4,1,7,120,5,99,32,66,36,93,0,0,0,0,0,0,0,0,0,0,0,0
|
||||
2039589,Heroes' Earthshatter Legguards,300,80,4,7,4,3,7,131,5,106,36,86,0,0,0,0,0,0,0,0,0,0,0,0,0,0
|
||||
2040681,Lattice Choker of Light,300,80,4,2,4,0,7,57,5,58,32,52,45,91,43,24,0,0,0,0,0,0,0,0,0,0
|
||||
2040718,Signet of the Impregnable Fortress,313,80,4,11,4,0,4,58,7,130,12,86,31,41,37,32,0,0,0,0,0,0,0,0,0,0
|
||||
2039636,Heroes' Redemption Legplates,300,80,4,7,4,4,4,125,7,139,36,113,32,80,0,0,0,0,0,0,0,0,0,0,0,0
|
||||
2040521,Valorous Earthshatter Faceguard,313,80,4,1,4,3,3,102,7,120,5,82,32,79,31,55,0,0,0,0,0,0,0,0,0,0
|
||||
2040322,Totem of Dueling,313,80,4,28,4,9,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0
|
||||
2040702,Rolfsen's Ripper,300,80,4,22,2,15,7,60,36,77,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0
|
||||
2039608,Heroes' Dreadnaught Shoulderplates,300,80,4,3,4,4,4,102,7,108,32,77,0,0,0,0,0,0,0,0,0,0,0,0,0,0
|
||||
2039627,Heroes' Scourgeborne Pauldrons,300,80,4,3,4,4,4,89,7,134,12,43,14,69,13,44,0,0,0,0,0,0,0,0,0,0
|
||||
2040569,Valorous Redemption Tunic,313,80,4,5,4,4,7,116,5,119,36,103,0,0,0,0,0,0,0,0,0,0,0,0,0,0
|
||||
2040522,Valorous Earthshatter War-Kilt,313,80,4,7,4,3,3,103,7,102,5,102,32,79,31,55,0,0,0,0,0,0,0,0,0,0
|
||||
2039521,Heroes' Circlet of Faith,300,80,4,1,4,1,7,83,5,93,6,99,32,66,0,0,0,0,0,0,0,0,0,0,0,0
|
||||
2039494,Heroes' Frostfire Shoulderpads,300,80,4,3,4,1,7,75,5,77,32,74,36,46,0,0,0,0,0,0,0,0,0,0,0,0
|
||||
2040468,Valorous Dreamwalker Trousers,313,80,4,7,4,2,7,116,5,119,6,91,32,89,0,0,0,0,0,0,0,0,0,0,0,0
|
||||
2045204,Axe of the Sen'jin Protector,300,80,4,13,2,0,4,44,7,66,12,68,14,29,0,0,0,0,0,0,0,0,0,0,0,0
|
||||
2045688,Inscribed Band of the Kirin Tor,313,80,4,11,4,0,38,173,3,57,7,88,32,58,36,57,0,0,0,0,0,0,0,0,0,0
|
||||
2040749,Rainey's Chewed Boots,313,80,4,8,4,2,7,99,5,88,6,85,0,0,0,0,0,0,0,0,0,0,0,0,0,0
|
||||
2040567,Valorous Scourgeborne Legguards,313,80,4,7,4,4,4,124,7,196,12,77,13,111,31,54,0,0,0,0,0,0,0,0,0,0
|
||||
2040711,Idol of Lush Moss,300,80,4,28,4,8,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0
|
||||
2040418,Valorous Frostfire Robe,313,80,4,20,4,1,7,113,5,119,6,102,32,94,0,0,0,0,0,0,0,0,0,0,0,0
|
||||
2040733,Wristbands of the Sentinel Huntress,313,80,4,9,4,4,4,86,7,94,37,49,32,86,0,0,0,0,0,0,0,0,0,0,0,0
|
||||
2040723,Disguise of the Kumiho,313,80,4,16,4,1,7,74,5,58,6,57,36,63,0,0,0,0,0,0,0,0,0,0,0,0
|
||||
2040692,Vereesa's Silver Chain Belt,300,80,4,6,4,3,3,88,7,106,5,52,31,43,0,0,0,0,0,0,0,0,0,0,0,0
|
||||
2039633,Heroes' Redemption Chestpiece,300,80,4,5,4,4,4,113,7,159,32,114,36,69,0,0,0,0,0,0,0,0,0,0,0,0
|
||||
2040740,Wraps of the Astral Traveler,313,80,4,9,4,1,7,74,5,63,6,66,31,43,0,0,0,0,0,0,0,0,0,0,0,0
|
||||
2040735,Zartson's Jungle Vambraces,313,80,4,9,4,4,7,85,5,58,36,63,0,0,0,0,0,0,0,0,0,0,0,0,0,0
|
||||
2040700,Protective Barricade of the Light,300,80,4,14,4,6,7,75,5,52,32,38,0,0,0,0,0,0,0,0,0,0,0,0,0,0
|
||||
2040268,Libram of Tolerance,313,80,4,28,4,7,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0
|
||||
2039603,Heroes' Earthshatter War-Kilt,300,80,4,7,4,3,3,93,7,93,5,91,32,80,31,48,0,0,0,0,0,0,0,0,0,0
|
||||
2040557,Valorous Scourgeborne Shoulderplates,313,80,4,3,4,4,4,116,7,127,32,89,31,66,0,0,0,0,0,0,0,0,0,0,0,0
|
||||
2040698,Ward of the Violet Citadel,300,80,4,23,4,0,7,75,5,52,31,58,32,38,0,0,0,0,0,0,0,0,0,0,0,0
|
||||
2040545,Valorous Dreadnaught Handguards,313,80,4,10,4,4,4,88,7,155,12,66,14,77,37,52,0,0,0,0,0,0,0,0,0,0
|
||||
2045130,Blunderbuss of Khaz Modan,300,80,4,26,2,3,3,49,36,34,38,43,7,48,0,0,0,0,0,0,0,0,0,0,0,0
|
||||
2039595,Heroes' Earthshatter Kilt,300,80,4,7,4,3,7,131,5,106,32,86,31,57,0,0,0,0,0,0,0,0,0,0,0,0
|
||||
2040342,Idol of Awakening,313,80,4,28,4,8,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0
|
||||
2039528,Heroes' Pants of Faith,300,80,4,7,4,1,7,103,5,105,6,79,32,80,0,0,0,0,0,0,0,0,0,0,0,0
|
||||
2040685,The Egg of Mortal Essence,300,80,4,12,4,0,45,151,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0
|
||||
2040739,Bands of the Great Tree,313,80,4,9,4,2,7,74,5,63,6,43,0,0,0,0,0,0,0,0,0,0,0,0,0,0
|
||||
2039548,Heroes' Dreamwalker Mantle,300,80,4,3,4,2,7,75,5,79,36,72,31,44,0,0,0,0,0,0,0,0,0,0,0,0
|
||||
2040504,Valorous Cryptstalker Handguards,313,80,4,10,4,3,3,82,7,93,5,66,36,60,0,0,0,0,0,0,0,0,0,0,0,0
|
||||
2045074,Claymore of the Prophet,300,80,4,17,2,8,4,156,7,161,36,69,31,103,0,0,0,0,0,0,0,0,0,0,0,0
|
||||
2040337,Libram of Resurgence,313,80,4,28,4,7,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0
|
||||
2039564,Heroes' Bonescythe Legplates,300,80,4,7,4,2,3,125,7,120,36,79,31,57,0,0,0,0,0,0,0,0,0,0,0,0
|
||||
2045128,Silvery Sylvan Stave,300,80,4,17,2,10,38,207,3,159,7,151,32,80,0,0,0,0,0,0,0,0,0,0,0,0
|
||||
2040568,Valorous Scourgeborne Pauldrons,313,80,4,3,4,4,4,102,7,155,12,52,14,77,13,51,0,0,0,0,0,0,0,0,0,0
|
||||
2039581,Heroes' Cryptstalker Spaulders,300,80,4,3,4,3,3,89,7,83,5,51,36,55,32,51,0,0,0,0,0,0,0,0,0,0
|
||||
2040470,Valorous Dreamwalker Mantle,313,80,4,3,4,2,7,85,5,88,36,85,31,54,0,0,0,0,0,0,0,0,0,0,0,0
|
||||
2040321,Idol of the Shooting Star,313,80,4,28,4,8,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0
|
||||
2040734,Bracers of Dalaran's Parapets,313,80,4,9,4,4,4,66,7,130,12,57,14,58,31,43,0,0,0,0,0,0,0,0,0,0
|
||||
2040469,Valorous Dreamwalker Vestments,313,80,4,20,4,2,7,116,5,108,32,94,36,94,0,0,0,0,0,0,0,0,0,0,0,0
|
||||
2045203,Grimhorn Crusher,300,80,4,13,2,4,3,60,7,74,36,38,32,43,0,0,0,0,0,0,0,0,0,0,0,0
|
||||
2040420,Valorous Plagueheart Gloves,313,80,4,10,4,1,7,116,5,77,36,82,32,66,0,0,0,0,0,0,0,0,0,0,0,0
|
||||
2040579,Valorous Redemption Breastplate,313,80,4,5,4,4,4,155,7,196,12,71,15,82,0,0,0,0,0,0,0,0,0,0,0,0
|
||||
2039594,Heroes' Earthshatter Helm,300,80,4,1,4,3,7,102,5,100,36,80,32,66,0,0,0,0,0,0,0,0,0,0,0,0
|
||||
2040463,Valorous Dreamwalker Robe,313,80,4,20,4,2,7,116,5,111,6,119,36,65,0,0,0,0,0,0,0,0,0,0,0,0
|
||||
2040505,Valorous Cryptstalker Headpiece,313,80,4,1,4,3,3,130,7,122,5,72,32,82,36,57,0,0,0,0,0,0,0,0,0,0
|
||||
2040689,Waistguard of Living Iron,300,80,4,6,4,4,4,88,7,136,12,68,13,38,14,49,0,0,0,0,0,0,0,0,0,0
|
||||
2040745,Sabatons of Rapid Recovery,313,80,4,8,4,4,7,113,5,77,36,75,0,0,0,0,0,0,0,0,0,0,0,0,0,0
|
||||
2040457,Valorous Pants of Faith,313,80,4,7,4,1,7,116,5,119,6,89,32,91,0,0,0,0,0,0,0,0,0,0,0,0
|
||||
2040467,Valorous Dreamwalker Cover,313,80,4,1,4,2,7,116,5,111,32,94,31,65,0,0,0,0,0,0,0,0,0,0,0,0
|
||||
2040714,Sigil of the Unfaltering Knight,300,80,4,28,4,10,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0
|
||||
2039622,Heroes' Dreadnaught Handguards,300,80,4,10,4,4,4,79,7,134,12,58,14,66,37,46,0,0,0,0,0,0,0,0,0,0
|
||||
2040456,Valorous Circlet of Faith,313,80,4,1,4,1,7,97,5,111,6,99,32,79,0,0,0,0,0,0,0,0,0,0,0,0
|
||||
2039619,Heroes' Scourgeborne Helmet,300,80,4,1,4,4,4,114,7,139,32,125,31,44,0,0,0,0,0,0,0,0,0,0,0,0
|
||||
2040528,Valorous Dreadnaught Helmet,313,80,4,1,4,4,4,131,7,158,32,142,0,0,0,0,0,0,0,0,0,0,0,0,0,0
|
||||
2040691,Magroth's Meditative Cincture,300,80,4,6,4,4,7,75,5,79,32,58,36,62,0,0,0,0,0,0,0,0,0,0,0,0
|
||||
2039639,Heroes' Redemption Handguards,300,80,4,10,4,4,4,79,7,134,12,58,13,66,31,46,0,0,0,0,0,0,0,0,0,0
|
||||
2040570,Valorous Redemption Gloves,313,80,4,10,4,4,7,85,5,88,36,54,32,85,0,0,0,0,0,0,0,0,0,0,0,0
|
||||
2040706,Libram of Reciprocation,300,80,4,28,4,7,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0
|
||||
2039530,Heroes' Handwraps of Faith,300,80,4,10,4,1,7,69,5,74,32,75,36,54,0,0,0,0,0,0,0,0,0,0,0,0
|
||||
2039642,Heroes' Redemption Shoulderguards,300,80,4,3,4,4,4,93,7,134,12,52,13,51,14,54,0,0,0,0,0,0,0,0,0,0
|
||||
2040550,Valorous Scourgeborne Battleplate,313,80,4,5,4,4,4,131,7,158,36,128,32,103,0,0,0,0,0,0,0,0,0,0,0,0
|
||||
2040510,Valorous Earthshatter Headpiece,313,80,4,1,4,3,7,117,5,111,36,89,0,0,0,0,0,0,0,0,0,0,0,0,0,0
|
||||
2039517,Heroes' Leggings of Faith,300,80,4,7,4,1,7,103,5,105,6,93,32,66,0,0,0,0,0,0,0,0,0,0,0,0
|
||||
2039515,Heroes' Robe of Faith,300,80,4,20,4,1,7,103,5,93,6,105,0,0,0,0,0,0,0,0,0,0,0,0,0,0
|
||||
2039500,Heroes' Plagueheart Gloves,300,80,4,10,4,1,7,102,5,68,36,74,32,58,0,0,0,0,0,0,0,0,0,0,0,0
|
||||
2040736,Armguard of the Tower Archer,313,80,4,9,4,3,3,58,7,85,5,48,31,43,36,46,0,0,0,0,0,0,0,0,0,0
|
||||
2040447,Valorous Crown of Faith,313,80,4,1,4,1,7,97,5,106,6,103,36,77,0,0,0,0,0,0,0,0,0,0,0,0
|
||||
2039617,Heroes' Scourgeborne Battleplate,300,80,4,5,4,4,4,114,7,139,36,111,32,93,0,0,0,0,0,0,0,0,0,0,0,0
|
||||
2039607,Heroes' Dreadnaught Legplates,300,80,4,7,4,4,4,116,7,139,32,111,37,91,0,0,0,0,0,0,0,0,0,0,0,0
|
||||
2040717,Ring of Invincibility,313,80,4,11,4,0,3,43,7,85,32,66,36,58,0,0,0,0,0,0,0,0,0,0,0,0
|
||||
2040527,Valorous Dreadnaught Gauntlets,313,80,4,10,4,4,4,103,7,172,37,77,31,65,0,0,0,0,0,0,0,0,0,0,0,0
|
||||
2039610,Heroes' Dreadnaught Greathelm,300,80,4,1,4,4,4,111,7,172,12,75,31,46,0,0,0,0,0,0,0,0,0,0,0,0
|
||||
2040583,Valorous Redemption Legguards,313,80,4,7,4,4,4,155,7,196,12,83,15,80,0,0,0,0,0,0,0,0,0,0,0,0
|
||||
2039493,Heroes' Frostfire Leggings,300,80,4,7,4,1,7,103,5,105,36,99,31,55,0,0,0,0,0,0,0,0,0,0,0,0
|
||||
2040713,Idol of the Ravenous Beast,300,80,4,28,4,8,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0
|
||||
2039492,Heroes' Frostfire Robe,300,80,4,20,4,1,7,88,5,93,6,93,32,79,0,0,0,0,0,0,0,0,0,0,0,0
|
||||
2039624,Heroes' Scourgeborne Handguards,300,80,4,10,4,4,4,79,7,134,12,66,13,58,31,46,0,0,0,0,0,0,0,0,0,0
|
||||
2039565,Heroes' Bonescythe Pauldrons,300,80,4,3,4,2,3,69,7,99,32,77,36,51,0,0,0,0,0,0,0,0,0,0,0,0
|
||||
2039538,Heroes' Dreamwalker Robe,300,80,4,20,4,2,7,103,5,99,6,106,36,55,0,0,0,0,0,0,0,0,0,0,0,0
|
||||
2039543,Heroes' Dreamwalker Handguards,300,80,4,10,4,2,7,75,5,79,6,74,36,46,0,0,0,0,0,0,0,0,0,0,0,0
|
||||
2039638,Heroes' Redemption Breastplate,300,80,4,5,4,4,4,137,7,172,12,58,15,72,0,0,0,0,0,0,0,0,0,0,0,0
|
||||
2040679,Chained Military Gorget,300,80,4,2,4,0,4,63,7,116,12,51,13,49,31,32,0,0,0,0,0,0,0,0,0,0
|
||||
2039602,Heroes' Earthshatter Faceguard,300,80,4,1,4,3,3,93,7,108,5,72,32,68,31,46,0,0,0,0,0,0,0,0,0,0
|
||||
2040516,Valorous Earthshatter Helm,313,80,4,1,4,3,7,116,5,111,36,89,32,79,0,0,0,0,0,0,0,0,0,0,0,0
|
||||
2039629,Heroes' Redemption Tunic,300,80,4,5,4,4,7,103,5,106,36,93,0,0,0,0,0,0,0,0,0,0,0,0,0,0
|
||||
2040703,Grasscutter,300,80,4,22,2,7,3,38,7,60,32,58,0,0,0,0,0,0,0,0,0,0,0,0,0,0
|
||||
2040683,Valor Medal of the First War,300,80,4,12,4,0,13,130,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0
|
||||
2040697,Elegant Temple Gardens' Girdle,300,80,4,6,4,1,7,88,5,74,6,66,0,0,0,0,0,0,0,0,0,0,0,0,0,0
|
||||
2040544,Valorous Dreadnaught Breastplate,313,80,4,5,4,4,4,142,7,196,12,80,13,80,15,69,0,0,0,0,0,0,0,0,0,0
|
||||
2040704,Pride,300,80,4,22,2,13,7,60,31,77,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0
|
||||
2039558,Heroes' Bonescythe Breastplate,300,80,4,5,4,2,3,114,7,120,32,66,36,83,0,0,0,0,0,0,0,0,0,0,0,0
|
||||
2039496,Heroes' Plagueheart Circlet,300,80,4,1,4,1,7,134,5,80,6,71,36,74,0,0,0,0,0,0,0,0,0,0,0,0
|
||||
2040709,Totem of Forest Growth,300,80,4,28,4,9,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0
|
||||
2040722,Platinum Mesh Cloak,313,80,4,16,4,1,4,63,7,130,12,58,13,57,31,49,0,0,0,0,0,0,0,0,0,0
|
||||
2039601,Heroes' Earthshatter Grips,300,80,4,10,4,3,3,74,7,80,5,58,32,54,36,40,0,0,0,0,0,0,0,0,0,0
|
||||
2040513,Valorous Earthshatter Spaulders,313,80,4,3,4,3,7,85,5,88,32,77,0,0,0,0,0,0,0,0,0,0,0,0,0,0
|
||||
2040575,Valorous Redemption Gauntlets,313,80,4,10,4,4,4,103,7,172,32,77,36,65,0,0,0,0,0,0,0,0,0,0,0,0
|
||||
2039591,Heroes' Earthshatter Handguards,300,80,4,10,4,3,7,88,5,74,32,58,0,0,0,0,0,0,0,0,0,0,0,0,0,0
|
||||
2040688,Verdungo's Barbarian Cord,300,80,4,6,4,4,4,89,7,153,32,74,36,46,0,0,0,0,0,0,0,0,0,0,0,0
|
||||
2040563,Valorous Scourgeborne Handguards,313,80,4,10,4,4,4,88,7,153,12,77,13,62,31,58,0,0,0,0,0,0,0,0,0,0
|
||||
2040743,Kyzoc's Ground Stompers,313,80,4,8,4,4,4,116,7,172,12,77,13,51,14,52,0,0,0,0,0,0,0,0,0,0
|
||||
2040572,Valorous Redemption Greaves,313,80,4,7,4,4,7,116,5,119,36,102,32,79,0,0,0,0,0,0,0,0,0,0,0,0
|
||||
2040693,Beadwork Belt of Shamanic Vision,300,80,4,6,4,3,7,75,5,77,36,68,0,0,0,0,0,0,0,0,0,0,0,0,0,0
|
||||
2040450,Valorous Shoulderpads of Faith,313,80,4,3,4,1,7,85,5,88,6,77,32,65,0,0,0,0,0,0,0,0,0,0,0,0
|
||||
2040530,Valorous Dreadnaught Shoulderplates,313,80,4,3,4,4,4,116,7,127,32,89,0,0,0,0,0,0,0,0,0,0,0,0,0,0
|
||||
2039554,Heroes' Dreamwalker Raiments,300,80,4,20,4,2,3,114,7,139,37,54,32,83,0,0,0,0,0,0,0,0,0,0,0,0
|
||||
2045222,Spinal Destroyer,300,80,4,13,2,15,38,120,7,66,31,58,32,34,0,0,0,0,0,0,0,0,0,0,0,0
|
||||
2040415,Valorous Frostfire Gloves,313,80,4,10,4,1,7,99,5,88,32,82,31,58,0,0,0,0,0,0,0,0,0,0,0,0
|
||||
2040554,Valorous Scourgeborne Helmet,313,80,4,1,4,4,4,131,7,155,32,155,31,52,0,0,0,0,0,0,0,0,0,0,0,0
|
||||
2040417,Valorous Frostfire Leggings,313,80,4,7,4,1,7,134,5,119,36,103,31,66,0,0,0,0,0,0,0,0,0,0,0,0
|
||||
2040751,Slippers of the Holy Light,313,80,4,8,4,1,7,99,5,85,6,88,36,57,0,0,0,0,0,0,0,0,0,0,0,0
|
||||
2039529,Heroes' Mantle of Faith,300,80,4,3,4,1,7,77,5,77,36,68,31,55,0,0,0,0,0,0,0,0,0,0,0,0
|
||||
2045075,Ironforge Smasher,300,80,4,13,2,4,3,60,7,74,36,38,32,43,0,0,0,0,0,0,0,0,0,0,0,0
|
||||
2040721,Hammerhead Sharkskin Cloak,313,80,4,16,4,1,3,43,7,94,36,49,32,66,0,0,0,0,0,0,0,0,0,0,0,0
|
||||
2040678,Pendant of the Outcast Hero,300,80,4,2,4,0,3,69,7,79,32,58,38,155,0,0,0,0,0,0,0,0,0,0,0,0
|
||||
2039620,Heroes' Scourgeborne Legplates,300,80,4,7,4,4,4,116,7,139,32,111,36,91,0,0,0,0,0,0,0,0,0,0,0,0
|
||||
2040742,Bladed Steelboots,313,80,4,8,4,4,4,116,7,173,32,82,31,66,0,0,0,0,0,0,0,0,0,0,0,0
|
||||
2040577,Valorous Redemption Legplates,313,80,4,7,4,4,4,131,7,155,36,130,32,102,0,0,0,0,0,0,0,0,0,0,0,0
|
||||
2045690,Inscribed Ring of the Kirin Tor,313,80,4,11,4,0,4,86,7,130,32,58,37,57,0,0,0,0,0,0,0,0,0,0,0,0
|
||||
2039542,Heroes' Dreamwalker Spaulders,300,80,4,3,4,2,7,75,5,72,6,79,32,44,0,0,0,0,0,0,0,0,0,0,0,0
|
||||
2039580,Heroes' Cryptstalker Legguards,300,80,4,7,4,3,3,93,7,93,5,91,36,80,0,0,0,0,0,0,0,0,0,0,0,0
|
||||
2040207,Sigil of Awareness,313,80,4,28,4,10,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0
|
||||
2039605,Heroes' Dreadnaught Helmet,300,80,4,1,4,4,4,114,7,139,32,125,0,0,0,0,0,0,0,0,0,0,0,0,0,0
|
||||
2040747,Treads of Coastal Wandering,313,80,4,8,4,3,7,99,5,82,32,77,0,0,0,0,0,0,0,0,0,0,0,0,0,0
|
||||
2040515,Valorous Earthshatter Gloves,313,80,4,10,4,3,7,99,5,82,31,68,0,0,0,0,0,0,0,0,0,0,0,0,0,0
|
||||
2039630,Heroes' Redemption Greaves,300,80,4,7,4,4,7,103,5,105,36,93,32,68,0,0,0,0,0,0,0,0,0,0,0,0
|
||||
2040496,Valorous Bonescythe Gauntlets,313,80,4,10,4,2,3,102,7,97,32,77,31,58,38,176,0,0,0,0,0,0,0,0,0,0
|
||||
2039728,Totem of Misery,313,80,4,28,4,9,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0
|
||||
2039623,Heroes' Scourgeborne Chestguard,300,80,4,5,4,4,4,125,7,172,12,72,14,72,13,58,0,0,0,0,0,0,0,0,0,0
|
||||
2040524,Valorous Earthshatter Shoulderguards,313,80,4,3,4,3,3,77,7,93,5,62,32,63,37,58,0,0,0,0,0,0,0,0,0,0
|
||||
2045205,Greatsword of the Sin'dorei,300,80,4,17,2,8,4,156,7,161,36,69,31,103,0,0,0,0,0,0,0,0,0,0,0,0
|
||||
2039547,Heroes' Dreamwalker Vestments,300,80,4,20,4,2,7,103,5,97,32,83,36,80,0,0,0,0,0,0,0,0,0,0,0,0
|
||||
2039596,Heroes' Earthshatter Shoulderpads,300,80,4,3,4,3,7,75,5,79,32,68,31,49,0,0,0,0,0,0,0,0,0,0,0,0
|
||||
2039514,Heroes' Crown of Faith,300,80,4,1,4,1,7,83,5,93,6,99,36,66,0,0,0,0,0,0,0,0,0,0,0,0
|
||||
|
440
cmd/create_emblem_items/undeath-emblem.csv
Normal file
440
cmd/create_emblem_items/undeath-emblem.csv
Normal file
@@ -0,0 +1,440 @@
|
||||
entry,name,ItemLevel,RequiredLevel,Quality,InventoryType,class,subclass,stat_type1,stat_value1,stat_type2,stat_value2,stat_type3,stat_value3,stat_type4,stat_value4,stat_type5,stat_value5,stat_type6,stat_value6,stat_type7,stat_value7,stat_type8,stat_value8,stat_type9,stat_value9,stat_type10,stat_value10
|
||||
2048498,Koltira's Helmet of Triumph,345,85,4,1,4,4,4,203,7,240,32,127,37,114,0,0,0,0,0,0,0,0,0,0,0,0
|
||||
2048081,Velen's Mantle of Triumph,345,85,4,3,4,1,45,168,7,119,5,119,6,103,32,91,0,0,0,0,0,0,0,0,0,0
|
||||
2048610,Turalyon's Legplates of Triumph,345,85,4,7,4,4,4,215,7,240,32,127,37,127,0,0,0,0,0,0,0,0,0,0,0,0
|
||||
2048197,Runetotem's Shoulderpads of Triumph,345,85,4,3,4,2,38,209,3,144,7,156,36,103,44,91,0,0,0,0,0,0,0,0,0,0
|
||||
2048561,Koltira's Legguards of Conquest,332,85,4,7,4,4,4,142,7,243,12,88,14,82,13,97,0,0,0,0,0,0,0,0,0,0
|
||||
2048637,Turalyon's Shoulderguards of Triumph,345,85,4,3,4,4,4,119,7,215,12,103,13,103,37,66,0,0,0,0,0,0,0,0,0,0
|
||||
2048655,Liadrin's Legguards of Conquest,332,85,4,7,4,4,4,142,7,243,12,124,31,69,0,0,0,0,0,0,0,0,0,0,0,0
|
||||
2047665,Totem of Calming Tides,345,85,4,28,4,9,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0
|
||||
2048190,Runetotem's Legguards of Conquest,332,85,4,7,4,2,38,199,3,161,7,186,32,124,31,99,0,0,0,0,0,0,0,0,0,0
|
||||
2048152,Runetotem's Handguards of Triumph,345,85,4,10,4,2,45,168,7,119,5,119,6,103,32,91,0,0,0,0,0,0,0,0,0,0
|
||||
2047985,Velen's Leggings of Triumph,345,85,4,7,4,1,45,217,7,159,5,159,6,127,36,127,0,0,0,0,0,0,0,0,0,0
|
||||
2048459,Hellscream's Legguards of Conquest,332,85,4,7,4,4,4,142,7,243,12,124,31,69,0,0,0,0,0,0,0,0,0,0,0,0
|
||||
2047659,Crimson Star,345,85,4,25,2,16,38,88,3,66,7,66,37,43,44,43,0,0,0,0,0,0,0,0,0,0
|
||||
2048161,Malfurion's Mantle of Conquest,332,85,4,3,4,2,45,148,7,105,5,105,6,93,32,80,0,0,0,0,0,0,0,0,0,0
|
||||
2048657,Liadrin's Breastplate of Triumph,345,85,4,5,4,4,4,210,7,279,12,110,14,97,13,97,0,0,0,0,0,0,0,0,0,0
|
||||
2048130,Malfurion's Leggings of Conquest,332,85,4,7,4,2,45,189,7,142,5,142,6,111,36,111,0,0,0,0,0,0,0,0,0,0
|
||||
2048319,Nobundo's Kilt of Triumph,345,85,4,7,4,3,45,217,7,159,5,159,32,114,31,139,0,0,0,0,0,0,0,0,0,0
|
||||
2048094,Zabra's Pants of Triumph,345,85,4,7,4,1,45,217,7,159,5,159,36,114,31,139,0,0,0,0,0,0,0,0,0,0
|
||||
2047677,Faceplate of the Honorbound,345,85,4,1,4,4,4,159,7,260,12,127,37,106,13,114,0,0,0,0,0,0,0,0,0,0
|
||||
2047658,Brimstone Igniter,345,85,4,26,2,19,45,77,7,49,5,49,6,43,31,43,0,0,0,0,0,0,0,0,0,0
|
||||
2047675,Faceplate of Thunderous Rampage,345,85,4,1,4,4,4,203,7,240,32,114,44,127,0,0,0,0,0,0,0,0,0,0,0,0
|
||||
2047704,Epaulets of the Devourer,345,85,4,3,4,3,38,184,3,144,7,124,5,82,32,103,44,82,0,0,0,0,0,0,0,0
|
||||
2048497,Koltira's Legplates of Triumph,345,85,4,7,4,4,4,215,7,240,32,127,44,127,0,0,0,0,0,0,0,0,0,0,0,0
|
||||
2048099,Zabra's Pants of Conquest,332,85,4,7,4,1,45,189,7,142,5,142,36,99,31,124,0,0,0,0,0,0,0,0,0,0
|
||||
2048350,Nobundo's Shoulderguards of Triumph,345,85,4,3,4,3,38,288,3,91,7,124,5,82,32,103,31,82,0,0,0,0,0,0,0,0
|
||||
2047707,Mantle of the Groundbreaker,345,85,4,3,4,3,45,168,7,119,5,119,32,91,43,52,0,0,0,0,0,0,0,0,0,0
|
||||
2048504,Koltira's Legplates of Conquest,332,85,4,7,4,4,4,187,7,212,32,111,44,111,0,0,0,0,0,0,0,0,0,0,0,0
|
||||
2047702,Pauldrons of the Cavalier,345,85,4,3,4,4,45,168,7,119,5,119,32,91,36,103,0,0,0,0,0,0,0,0,0,0
|
||||
2048474,Thassarian's Battleplate of Conquest,332,85,4,5,4,4,4,187,7,212,32,111,36,111,0,0,0,0,0,0,0,0,0,0,0,0
|
||||
2047798,Gul'dan's Shoulderpads of Conquest,332,85,4,3,4,1,45,148,7,105,5,105,6,80,32,93,0,0,0,0,0,0,0,0,0,0
|
||||
2048636,Turalyon's Shoulderguards of Conquest,332,85,4,3,4,4,4,105,7,189,12,93,13,93,37,57,0,0,0,0,0,0,0,0,0,0
|
||||
2047771,Sunstrider's Hood of Triumph,345,85,4,1,4,1,45,203,7,159,5,159,36,127,31,114,0,0,0,0,0,0,0,0,0,0
|
||||
2047787,Kel'Thuzad's Shoulderpads of Conquest,332,85,4,3,4,1,45,148,7,105,5,105,6,80,32,93,0,0,0,0,0,0,0,0,0,0
|
||||
2047735,Glyph of Indomitability,345,85,4,12,4,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0
|
||||
2048531,Thassarian's Chestguard of Conquest,332,85,4,5,4,4,4,142,7,243,12,97,14,88,13,82,0,0,0,0,0,0,0,0,0,0
|
||||
2048310,Nobundo's Hauberk of Conquest,332,85,4,5,4,3,45,189,7,142,5,142,36,111,31,111,0,0,0,0,0,0,0,0,0,0
|
||||
2048238,Garona's Pauldrons of Triumph,345,85,4,3,4,2,38,184,3,156,7,156,44,103,37,91,0,0,0,0,0,0,0,0,0,0
|
||||
2048244,Garona's Gauntlets of Conquest,332,85,4,10,4,2,38,159,3,137,7,137,32,93,31,80,0,0,0,0,0,0,0,0,0,0
|
||||
2047986,Velen's Robe of Triumph,345,85,4,20,4,1,45,217,7,159,5,159,6,127,32,127,0,0,0,0,0,0,0,0,0,0
|
||||
2048095,Zabra's Circlet of Triumph,345,85,4,1,4,1,45,203,7,159,5,159,6,114,31,127,0,0,0,0,0,0,0,0,0,0
|
||||
2047980,Velen's Leggings of Conquest,332,85,4,7,4,1,45,189,7,142,5,142,6,111,36,111,0,0,0,0,0,0,0,0,0,0
|
||||
2048242,Garona's Breastplate of Triumph,345,85,4,5,4,2,38,255,3,186,7,210,32,139,31,127,0,0,0,0,0,0,0,0,0,0
|
||||
2048258,Windrunner's Legguards of Triumph,345,85,4,7,4,3,38,230,3,186,7,110,5,165,32,139,44,110,0,0,0,0,0,0,0,0
|
||||
2048394,Hellscream's Legplates of Triumph,345,85,4,7,4,4,4,215,7,240,32,127,37,127,0,0,0,0,0,0,0,0,0,0,0,0
|
||||
2048464,Hellscream's Legguards of Triumph,345,85,4,7,4,4,4,159,7,279,12,139,31,82,0,0,0,0,0,0,0,0,0,0,0,0
|
||||
2048068,Zabra's Cowl of Conquest,332,85,4,1,4,1,45,175,7,142,5,142,6,111,32,99,0,0,0,0,0,0,0,0,0,0
|
||||
2048572,Turalyon's Spaulders of Conquest,332,85,4,3,4,4,45,148,7,105,5,105,32,93,36,80,0,0,0,0,0,0,0,0,0,0
|
||||
2048625,Liadrin's Gauntlets of Triumph,345,85,4,10,4,4,4,165,7,178,32,103,31,91,0,0,0,0,0,0,0,0,0,0,0,0
|
||||
2048505,Koltira's Shoulderplates of Conquest,332,85,4,3,4,4,4,145,7,158,32,93,31,80,0,0,0,0,0,0,0,0,0,0,0,0
|
||||
2048219,VanCleef's Breastplate of Conquest,332,85,4,5,4,2,38,224,3,161,7,186,32,124,31,111,0,0,0,0,0,0,0,0,0,0
|
||||
2048076,Velen's Mantle of Conquest,332,85,4,3,4,1,45,148,7,105,5,105,6,93,32,80,0,0,0,0,0,0,0,0,0,0
|
||||
2048347,Nobundo's Grips of Triumph,345,85,4,10,4,3,38,288,3,103,7,124,5,82,37,91,32,82,0,0,0,0,0,0,0,0
|
||||
2047666,Totem of Electrifying Wind,345,85,4,28,4,9,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0
|
||||
2048253,Windrunner's Spaulders of Conquest,332,85,4,3,4,3,38,159,3,125,7,110,5,72,32,93,31,72,0,0,0,0,0,0,0,0
|
||||
2048222,VanCleef's Gauntlets of Conquest,332,85,4,10,4,2,38,159,3,137,7,137,32,93,31,80,0,0,0,0,0,0,0,0,0,0
|
||||
2048541,Thassarian's Legguards of Triumph,345,85,4,7,4,4,4,159,7,279,12,100,14,94,13,110,0,0,0,0,0,0,0,0,0,0
|
||||
2048187,Runetotem's Mantle of Conquest,332,85,4,3,4,2,45,148,7,105,5,105,6,93,32,80,0,0,0,0,0,0,0,0,0,0
|
||||
2048590,Liadrin's Spaulders of Triumph,345,85,4,3,4,4,45,168,7,119,5,119,32,103,36,91,0,0,0,0,0,0,0,0,0,0
|
||||
2048302,Thrall's Headpiece of Triumph,345,85,4,1,4,3,45,203,7,159,5,159,32,117,43,62,0,0,0,0,0,0,0,0,0,0
|
||||
2048297,Thrall's Headpiece of Conquest,332,85,4,1,4,3,45,175,7,142,5,142,32,102,43,54,0,0,0,0,0,0,0,0,0,0
|
||||
2047799,Gul'dan's Robe of Conquest,332,85,4,20,4,1,45,189,7,142,5,142,6,111,31,111,0,0,0,0,0,0,0,0,0,0
|
||||
2047708,Duskstalker Shoulderpads,345,85,4,3,4,2,38,209,3,144,7,156,32,103,44,91,0,0,0,0,0,0,0,0,0,0
|
||||
2048220,VanCleef's Legplates of Conquest,332,85,4,7,4,2,38,224,3,161,7,186,31,99,44,111,0,0,0,0,0,0,0,0,0,0
|
||||
2048167,Malfurion's Mantle of Triumph,345,85,4,3,4,2,45,168,7,119,5,119,6,103,32,91,0,0,0,0,0,0,0,0,0,0
|
||||
2048722,Shard of the Crystal Heart,345,85,4,12,4,0,31,198,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0
|
||||
2048075,Velen's Raiments of Conquest,332,85,4,20,4,1,45,189,7,142,5,142,6,111,36,111,0,0,0,0,0,0,0,0,0,0
|
||||
2048639,Turalyon's Faceguard of Triumph,345,85,4,1,4,4,4,210,7,260,12,97,13,85,0,0,0,0,0,0,0,0,0,0,0,0
|
||||
2048607,Turalyon's Battleplate of Triumph,345,85,4,5,4,4,4,215,7,240,32,127,44,127,0,0,0,0,0,0,0,0,0,0,0,0
|
||||
2047774,Sunstrider's Hood of Conquest,332,85,4,1,4,1,45,175,7,142,5,142,36,111,31,99,0,0,0,0,0,0,0,0,0,0
|
||||
2048218,VanCleef's Helmet of Conquest,332,85,4,1,4,2,38,199,3,161,7,186,32,124,37,99,0,0,0,0,0,0,0,0,0,0
|
||||
2048159,Malfurion's Vestments of Conquest,332,85,4,20,4,2,45,189,7,142,5,142,36,124,32,99,0,0,0,0,0,0,0,0,0,0
|
||||
2048652,Liadrin's Breastplate of Conquest,332,85,4,5,4,4,4,186,7,243,12,97,14,85,13,85,0,0,0,0,0,0,0,0,0,0
|
||||
2048450,Wrynn's Breastplate of Triumph,345,85,4,5,4,4,4,210,7,279,12,110,14,97,13,97,0,0,0,0,0,0,0,0,0,0
|
||||
2048640,Turalyon's Handguards of Triumph,345,85,4,10,4,4,4,156,7,215,12,82,13,69,14,82,0,0,0,0,0,0,0,0,0,0
|
||||
2048482,Thassarian's Gauntlets of Triumph,345,85,4,10,4,4,4,165,7,178,32,103,31,91,0,0,0,0,0,0,0,0,0,0,0,0
|
||||
2048225,VanCleef's Helmet of Triumph,345,85,4,1,4,2,38,230,3,186,7,210,32,139,37,114,0,0,0,0,0,0,0,0,0,0
|
||||
2048556,Koltira's Handguards of Triumph,345,85,4,10,4,4,4,156,7,215,12,82,13,82,14,69,0,0,0,0,0,0,0,0,0,0
|
||||
2048148,Runetotem's Spaulders of Triumph,345,85,4,3,4,2,45,168,7,119,5,119,6,91,36,103,0,0,0,0,0,0,0,0,0,0
|
||||
2047779,Kel'Thuzad's Robe of Triumph,345,85,4,20,4,1,45,217,7,159,5,159,6,127,31,127,0,0,0,0,0,0,0,0,0,0
|
||||
2048553,Koltira's Pauldrons of Triumph,345,85,4,3,4,4,4,119,7,215,12,103,14,103,31,66,0,0,0,0,0,0,0,0,0,0
|
||||
2048164,Malfurion's Cover of Triumph,345,85,4,1,4,2,45,203,7,159,5,159,31,127,32,114,0,0,0,0,0,0,0,0,0,0
|
||||
2048156,Runetotem's Robe of Conquest,332,85,4,20,4,2,45,189,7,142,5,142,6,111,32,111,0,0,0,0,0,0,0,0,0,0
|
||||
2048097,Zabra's Handwraps of Conquest,332,85,4,10,4,1,45,148,7,105,5,105,31,80,32,93,0,0,0,0,0,0,0,0,0,0
|
||||
2048250,Windrunner's Headpiece of Conquest,332,85,4,1,4,3,38,199,3,161,7,147,5,97,32,124,44,72,0,0,0,0,0,0,0,0
|
||||
2047755,Khadgar's Leggings of Triumph,345,85,4,7,4,1,45,217,7,159,5,159,6,114,32,139,0,0,0,0,0,0,0,0,0,0
|
||||
2048074,Velen's Pants of Conquest,332,85,4,7,4,1,45,189,7,142,5,142,36,99,31,124,0,0,0,0,0,0,0,0,0,0
|
||||
2048537,Thassarian's Handguards of Conquest,332,85,4,10,4,4,4,137,7,189,12,72,13,72,14,60,0,0,0,0,0,0,0,0,0,0
|
||||
2048226,VanCleef's Legplates of Triumph,345,85,4,7,4,2,38,255,3,186,7,210,31,114,44,127,0,0,0,0,0,0,0,0,0,0
|
||||
2047715,Pauldrons of Revered Mortality,345,85,4,3,4,1,45,168,7,119,5,119,6,103,36,91,0,0,0,0,0,0,0,0,0,0
|
||||
2048392,Hellscream's Gauntlets of Triumph,345,85,4,10,4,4,4,165,7,178,32,103,31,91,0,0,0,0,0,0,0,0,0,0,0,0
|
||||
2048386,Hellscream's Battleplate of Conquest,332,85,4,5,4,4,4,187,7,212,32,111,44,111,0,0,0,0,0,0,0,0,0,0,0,0
|
||||
2048529,Thassarian's Faceguard of Conquest,332,85,4,1,4,4,4,142,7,224,12,111,31,69,13,124,0,0,0,0,0,0,0,0,0,0
|
||||
2048623,Liadrin's Legplates of Triumph,345,85,4,7,4,4,4,215,7,240,32,127,37,127,0,0,0,0,0,0,0,0,0,0,0,0
|
||||
2048568,Turalyon's Greaves of Conquest,332,85,4,7,4,4,45,189,7,142,5,142,32,99,43,62,0,0,0,0,0,0,0,0,0,0
|
||||
2048224,VanCleef's Gauntlets of Triumph,345,85,4,10,4,2,38,184,3,156,7,156,32,103,31,91,0,0,0,0,0,0,0,0,0,0
|
||||
2048367,Thrall's Grips of Conquest,332,85,4,10,4,3,38,252,3,93,7,110,5,72,37,80,32,72,0,0,0,0,0,0,0,0
|
||||
2048372,Wrynn's Battleplate of Conquest,332,85,4,5,4,4,4,187,7,212,32,111,44,111,0,0,0,0,0,0,0,0,0,0,0,0
|
||||
2048622,Liadrin's Shoulderplates of Triumph,345,85,4,3,4,4,4,165,7,178,32,103,31,91,0,0,0,0,0,0,0,0,0,0,0,0
|
||||
2048188,Runetotem's Headguard of Conquest,332,85,4,1,4,2,38,199,3,161,7,186,32,124,37,99,0,0,0,0,0,0,0,0,0,0
|
||||
2047780,Kel'Thuzad's Leggings of Triumph,345,85,4,7,4,1,45,217,7,159,5,159,32,139,36,114,0,0,0,0,0,0,0,0,0,0
|
||||
2048062,Zabra's Shoulderpads of Triumph,345,85,4,3,4,1,45,168,7,119,5,119,6,103,32,91,0,0,0,0,0,0,0,0,0,0
|
||||
2048653,Liadrin's Handguards of Conquest,332,85,4,10,4,4,4,137,7,189,12,72,13,60,14,72,0,0,0,0,0,0,0,0,0,0
|
||||
2047709,Duskstalker Pauldrons,345,85,4,3,4,2,38,209,3,144,7,156,32,103,44,91,0,0,0,0,0,0,0,0,0,0
|
||||
2048445,Wrynn's Legguards of Conquest,332,85,4,7,4,4,4,142,7,243,12,124,31,69,0,0,0,0,0,0,0,0,0,0,0,0
|
||||
2048634,Turalyon's Faceguard of Conquest,332,85,4,1,4,4,4,186,7,224,12,85,13,72,0,0,0,0,0,0,0,0,0,0,0,0
|
||||
2048462,Hellscream's Handguards of Triumph,345,85,4,10,4,4,4,156,7,215,12,82,13,69,14,82,0,0,0,0,0,0,0,0,0,0
|
||||
2048102,Malfurion's Headpiece of Conquest,332,85,4,1,4,2,45,175,7,142,5,142,6,99,32,111,0,0,0,0,0,0,0,0,0,0
|
||||
2048073,Velen's Circlet of Conquest,332,85,4,1,4,1,45,175,7,142,5,142,6,99,31,111,0,0,0,0,0,0,0,0,0,0
|
||||
2048366,Thrall's Chestguard of Conquest,332,85,4,5,4,3,38,373,3,99,7,147,5,97,32,111,36,85,0,0,0,0,0,0,0,0
|
||||
2048559,Koltira's Handguards of Conquest,332,85,4,10,4,4,4,137,7,189,12,72,13,72,14,60,0,0,0,0,0,0,0,0,0,0
|
||||
2047668,Idol of Mutilation,345,85,4,28,4,8,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0
|
||||
2047730,Dexterous Brightstone Ring,345,85,4,11,4,0,38,156,3,117,7,117,44,77,36,77,0,0,0,0,0,0,0,0,0,0
|
||||
2048603,Turalyon's Gauntlets of Conquest,332,85,4,10,4,4,4,145,7,158,32,93,31,80,0,0,0,0,0,0,0,0,0,0,0,0
|
||||
2048481,Thassarian's Battleplate of Triumph,345,85,4,5,4,4,4,215,7,240,32,127,36,127,0,0,0,0,0,0,0,0,0,0,0,0
|
||||
2048067,Zabra's Gloves of Conquest,332,85,4,10,4,1,45,148,7,105,5,105,6,80,36,93,0,0,0,0,0,0,0,0,0,0
|
||||
2048368,Thrall's Faceguard of Conquest,332,85,4,1,4,3,38,199,3,161,7,147,5,97,31,99,32,97,0,0,0,0,0,0,0,0
|
||||
2048456,Hellscream's Breastplate of Conquest,332,85,4,5,4,4,4,186,7,243,12,97,14,85,13,85,0,0,0,0,0,0,0,0,0,0
|
||||
2047753,Khadgar's Gauntlets of Triumph,345,85,4,10,4,1,45,168,7,119,5,119,32,103,36,91,0,0,0,0,0,0,0,0,0,0
|
||||
2047768,Sunstrider's Shoulderpads of Triumph,345,85,4,3,4,1,45,168,7,119,5,119,32,91,36,103,0,0,0,0,0,0,0,0,0,0
|
||||
2048181,Runetotem's Cover of Triumph,345,85,4,1,4,2,45,203,7,159,5,159,31,127,32,114,0,0,0,0,0,0,0,0,0,0
|
||||
2048484,Thassarian's Legplates of Triumph,345,85,4,7,4,4,4,215,7,240,32,127,44,127,0,0,0,0,0,0,0,0,0,0,0,0
|
||||
2048284,Nobundo's Handguards of Conquest,332,85,4,10,4,3,45,148,7,105,5,105,36,80,43,46,0,0,0,0,0,0,0,0,0,0
|
||||
2048596,Liadrin's Greaves of Conquest,332,85,4,7,4,4,45,189,7,142,5,142,32,99,43,62,0,0,0,0,0,0,0,0,0,0
|
||||
2048185,Runetotem's Trousers of Conquest,332,85,4,7,4,2,45,189,7,142,5,142,6,99,31,124,0,0,0,0,0,0,0,0,0,0
|
||||
2048096,Zabra's Handwraps of Triumph,345,85,4,10,4,1,45,168,7,119,5,119,31,91,32,103,0,0,0,0,0,0,0,0,0,0
|
||||
2047674,Helm of Thunderous Rampage,345,85,4,1,4,4,4,203,7,240,32,114,44,127,0,0,0,0,0,0,0,0,0,0,0,0
|
||||
2048223,VanCleef's Breastplate of Triumph,345,85,4,5,4,2,38,255,3,186,7,210,32,139,31,127,0,0,0,0,0,0,0,0,0,0
|
||||
2048214,Malfurion's Headguard of Conquest,332,85,4,1,4,2,38,199,3,161,7,186,32,124,37,99,0,0,0,0,0,0,0,0,0,0
|
||||
2048389,Hellscream's Legplates of Conquest,332,85,4,7,4,4,4,187,7,212,32,111,37,111,0,0,0,0,0,0,0,0,0,0,0,0
|
||||
2048555,Koltira's Faceguard of Triumph,345,85,4,1,4,4,4,159,7,260,12,127,31,82,13,139,0,0,0,0,0,0,0,0,0,0
|
||||
2048150,Runetotem's Leggings of Triumph,345,85,4,7,4,2,45,217,7,159,5,159,6,127,36,127,0,0,0,0,0,0,0,0,0,0
|
||||
2048162,Malfurion's Gloves of Conquest,332,85,4,10,4,2,45,148,7,105,5,105,6,80,36,93,0,0,0,0,0,0,0,0,0,0
|
||||
2048160,Malfurion's Trousers of Conquest,332,85,4,7,4,2,45,189,7,142,5,142,6,99,31,124,0,0,0,0,0,0,0,0,0,0
|
||||
2047750,Khadgar's Leggings of Conquest,332,85,4,7,4,1,45,189,7,142,5,142,6,99,32,124,0,0,0,0,0,0,0,0,0,0
|
||||
2048213,Malfurion's Handgrips of Conquest,332,85,4,10,4,2,38,184,3,125,7,137,32,93,31,80,0,0,0,0,0,0,0,0,0,0
|
||||
2047802,Gul'dan's Gloves of Conquest,332,85,4,10,4,1,45,148,7,105,5,105,32,93,31,80,0,0,0,0,0,0,0,0,0,0
|
||||
2048221,VanCleef's Pauldrons of Conquest,332,85,4,3,4,2,38,159,3,137,7,137,44,93,37,80,0,0,0,0,0,0,0,0,0,0
|
||||
2048476,Thassarian's Legplates of Conquest,332,85,4,7,4,4,4,187,7,212,32,111,44,111,0,0,0,0,0,0,0,0,0,0,0,0
|
||||
2048566,Turalyon's Tunic of Conquest,332,85,4,5,4,4,45,189,7,142,5,142,32,99,43,62,0,0,0,0,0,0,0,0,0,0
|
||||
2048136,Malfurion's Robe of Triumph,345,85,4,20,4,2,45,217,7,159,5,159,6,127,32,127,0,0,0,0,0,0,0,0,0,0
|
||||
2048478,Thassarian's Shoulderplates of Conquest,332,85,4,3,4,4,4,145,7,158,32,93,31,80,0,0,0,0,0,0,0,0,0,0,0,0
|
||||
2047705,Pauldrons of the Devourer,345,85,4,3,4,3,38,184,3,144,7,124,5,82,32,103,44,82,0,0,0,0,0,0,0,0
|
||||
2048558,Koltira's Chestguard of Conquest,332,85,4,5,4,4,4,142,7,243,12,97,14,88,13,82,0,0,0,0,0,0,0,0,0,0
|
||||
2047662,Libram of Veracity,345,85,4,28,4,7,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0
|
||||
2047987,Velen's Shoulderpads of Triumph,345,85,4,3,4,1,45,168,7,119,5,119,6,103,32,91,0,0,0,0,0,0,0,0,0,0
|
||||
2048379,Wrynn's Legplates of Triumph,345,85,4,7,4,4,4,215,7,240,32,127,37,127,0,0,0,0,0,0,0,0,0,0,0,0
|
||||
2048245,Garona's Helmet of Conquest,332,85,4,1,4,2,38,199,3,161,7,186,32,124,37,99,0,0,0,0,0,0,0,0,0,0
|
||||
2048209,Malfurion's Raiments of Triumph,345,85,4,20,4,2,38,280,3,186,7,210,32,130,36,124,0,0,0,0,0,0,0,0,0,0
|
||||
2047751,Khadgar's Shoulderpads of Conquest,332,85,4,3,4,1,45,148,7,105,5,105,32,80,36,93,0,0,0,0,0,0,0,0,0,0
|
||||
2047803,Gul'dan's Gloves of Triumph,345,85,4,10,4,1,45,168,7,119,5,119,32,103,31,91,0,0,0,0,0,0,0,0,0,0
|
||||
2047769,Sunstrider's Robe of Triumph,345,85,4,20,4,1,45,217,7,159,5,159,6,139,31,114,0,0,0,0,0,0,0,0,0,0
|
||||
2048077,Velen's Handwraps of Triumph,345,85,4,10,4,1,45,168,7,119,5,119,31,91,32,103,0,0,0,0,0,0,0,0,0,0
|
||||
2048624,Liadrin's Helm of Triumph,345,85,4,1,4,4,4,203,7,240,32,127,36,114,0,0,0,0,0,0,0,0,0,0,0,0
|
||||
2048465,Hellscream's Pauldrons of Triumph,345,85,4,3,4,4,4,119,7,215,12,103,13,103,37,66,0,0,0,0,0,0,0,0,0,0
|
||||
2048472,Thassarian's Helmet of Conquest,332,85,4,1,4,4,4,175,7,212,32,111,37,99,0,0,0,0,0,0,0,0,0,0,0,0
|
||||
2047914,Velen's Cowl of Conquest,332,85,4,1,4,1,45,175,7,142,5,142,6,111,32,99,0,0,0,0,0,0,0,0,0,0
|
||||
2048641,Turalyon's Breastplate of Triumph,345,85,4,5,4,4,4,210,7,279,12,110,14,97,13,97,0,0,0,0,0,0,0,0,0,0
|
||||
2047984,Velen's Cowl of Triumph,345,85,4,1,4,1,45,203,7,159,5,159,6,127,32,114,0,0,0,0,0,0,0,0,0,0
|
||||
2048183,Runetotem's Gloves of Conquest,332,85,4,10,4,2,45,148,7,105,5,105,6,80,36,93,0,0,0,0,0,0,0,0,0,0
|
||||
2047785,Kel'Thuzad's Leggings of Conquest,332,85,4,7,4,1,45,189,7,142,5,142,32,124,36,99,0,0,0,0,0,0,0,0,0,0
|
||||
2048239,Garona's Legplates of Triumph,345,85,4,7,4,2,38,255,3,186,7,210,31,114,44,127,0,0,0,0,0,0,0,0,0,0
|
||||
2048364,Thrall's Grips of Triumph,345,85,4,10,4,3,38,288,3,103,7,124,5,82,37,91,32,82,0,0,0,0,0,0,0,0
|
||||
2048560,Koltira's Faceguard of Conquest,332,85,4,1,4,4,4,142,7,224,12,111,31,69,13,124,0,0,0,0,0,0,0,0,0,0
|
||||
2048605,Turalyon's Legplates of Conquest,332,85,4,7,4,4,4,187,7,212,32,111,37,111,0,0,0,0,0,0,0,0,0,0,0,0
|
||||
2048281,Nobundo's Tunic of Conquest,332,85,4,5,4,3,45,189,7,142,5,142,36,111,32,111,0,0,0,0,0,0,0,0,0,0
|
||||
2048072,Velen's Handwraps of Conquest,332,85,4,10,4,1,45,148,7,105,5,105,31,80,32,93,0,0,0,0,0,0,0,0,0,0
|
||||
2048500,Koltira's Battleplate of Triumph,345,85,4,5,4,4,4,215,7,240,32,127,36,127,0,0,0,0,0,0,0,0,0,0,0,0
|
||||
2048246,Garona's Legplates of Conquest,332,85,4,7,4,2,38,224,3,161,7,186,31,99,44,111,0,0,0,0,0,0,0,0,0,0
|
||||
2048337,Thrall's Gloves of Conquest,332,85,4,10,4,3,45,148,7,105,5,105,36,80,31,93,0,0,0,0,0,0,0,0,0,0
|
||||
2048463,Hellscream's Greathelm of Triumph,345,85,4,1,4,4,4,210,7,260,12,97,13,85,0,0,0,0,0,0,0,0,0,0,0,0
|
||||
2048093,Zabra's Raiments of Triumph,345,85,4,20,4,1,45,217,7,159,5,159,6,127,36,127,0,0,0,0,0,0,0,0,0,0
|
||||
2048252,Windrunner's Legguards of Conquest,332,85,4,7,4,3,38,199,3,161,7,97,5,147,32,124,44,97,0,0,0,0,0,0,0,0
|
||||
2048210,Malfurion's Legguards of Triumph,345,85,4,7,4,2,38,230,3,186,7,210,32,139,31,114,0,0,0,0,0,0,0,0,0,0
|
||||
2048178,Runetotem's Mantle of Triumph,345,85,4,3,4,2,45,168,7,119,5,119,6,103,32,91,0,0,0,0,0,0,0,0,0,0
|
||||
2047681,Heaume of the Restless Watch,345,85,4,1,4,4,45,203,7,159,5,159,32,102,43,69,0,0,0,0,0,0,0,0,0,0
|
||||
2048314,Nobundo's Kilt of Conquest,332,85,4,7,4,3,45,189,7,142,5,142,32,99,31,124,0,0,0,0,0,0,0,0,0,0
|
||||
2048312,Nobundo's Gloves of Conquest,332,85,4,10,4,3,45,148,7,105,5,105,36,80,31,93,0,0,0,0,0,0,0,0,0,0
|
||||
2048342,Nobundo's Grips of Conquest,332,85,4,10,4,3,38,252,3,93,7,110,5,72,37,80,32,72,0,0,0,0,0,0,0,0
|
||||
2048576,Turalyon's Gloves of Triumph,345,85,4,10,4,4,45,168,7,119,5,119,36,103,43,46,0,0,0,0,0,0,0,0,0,0
|
||||
2048454,Wrynn's Pauldrons of Triumph,345,85,4,3,4,4,4,119,7,215,12,103,13,103,37,66,0,0,0,0,0,0,0,0,0,0
|
||||
2047699,Shoulderguards of Enduring Order,345,85,4,3,4,4,4,156,7,215,12,82,13,69,14,82,0,0,0,0,0,0,0,0,0,0
|
||||
2048101,Zabra's Mantle of Conquest,332,85,4,3,4,1,45,148,7,105,5,105,6,93,32,80,0,0,0,0,0,0,0,0,0,0
|
||||
2048632,Turalyon's Breastplate of Conquest,332,85,4,5,4,4,4,186,7,243,12,97,14,85,13,85,0,0,0,0,0,0,0,0,0,0
|
||||
2048192,Runetotem's Handgrips of Conquest,332,85,4,10,4,2,38,184,3,125,7,137,32,93,31,80,0,0,0,0,0,0,0,0,0,0
|
||||
2048334,Thrall's Gloves of Triumph,345,85,4,10,4,3,45,168,7,119,5,119,36,91,31,103,0,0,0,0,0,0,0,0,0,0
|
||||
2048157,Runetotem's Spaulders of Conquest,332,85,4,3,4,2,45,148,7,105,5,105,6,80,36,93,0,0,0,0,0,0,0,0,0,0
|
||||
2047733,Heartmender Circle,345,85,4,11,4,0,45,137,7,89,5,89,32,77,43,38,0,0,0,0,0,0,0,0,0,0
|
||||
2048212,Malfurion's Handgrips of Triumph,345,85,4,10,4,2,38,209,3,144,7,156,32,103,31,91,0,0,0,0,0,0,0,0,0,0
|
||||
2048286,Nobundo's Handguards of Triumph,345,85,4,10,4,3,45,168,7,119,5,119,36,91,43,52,0,0,0,0,0,0,0,0,0,0
|
||||
2048298,Thrall's Legguards of Conquest,332,85,4,7,4,3,45,189,7,142,5,142,32,114,43,54,0,0,0,0,0,0,0,0,0,0
|
||||
2048333,Thrall's Helm of Triumph,345,85,4,1,4,3,45,203,7,159,5,159,32,124,36,130,0,0,0,0,0,0,0,0,0,0
|
||||
2048194,Runetotem's Headguard of Triumph,345,85,4,1,4,2,38,230,3,186,7,210,32,139,37,114,0,0,0,0,0,0,0,0,0,0
|
||||
2048611,Turalyon's Shoulderplates of Triumph,345,85,4,3,4,4,4,165,7,178,32,103,31,91,0,0,0,0,0,0,0,0,0,0,0,0
|
||||
2048132,Malfurion's Handguards of Conquest,332,85,4,10,4,2,45,148,7,105,5,105,6,93,32,80,0,0,0,0,0,0,0,0,0,0
|
||||
2048496,Koltira's Shoulderplates of Triumph,345,85,4,3,4,4,4,165,7,178,32,103,31,91,0,0,0,0,0,0,0,0,0,0,0,0
|
||||
2047982,Velen's Gloves of Conquest,332,85,4,10,4,1,45,148,7,105,5,105,6,80,36,93,0,0,0,0,0,0,0,0,0,0
|
||||
2048154,Runetotem's Headpiece of Conquest,332,85,4,1,4,2,45,175,7,142,5,142,6,99,32,111,0,0,0,0,0,0,0,0,0,0
|
||||
2047698,Shoulderplates of Enduring Order,345,85,4,3,4,4,4,156,7,215,12,82,13,69,14,82,0,0,0,0,0,0,0,0,0,0
|
||||
2047800,Gul'dan's Leggings of Conquest,332,85,4,7,4,1,45,189,7,142,5,142,32,124,36,99,0,0,0,0,0,0,0,0,0,0
|
||||
2048227,VanCleef's Pauldrons of Triumph,345,85,4,3,4,2,38,184,3,156,7,156,44,103,37,91,0,0,0,0,0,0,0,0,0,0
|
||||
2047786,Kel'Thuzad's Robe of Conquest,332,85,4,20,4,1,45,189,7,142,5,142,6,111,31,111,0,0,0,0,0,0,0,0,0,0
|
||||
2048598,Liadrin's Gloves of Conquest,332,85,4,10,4,4,45,148,7,105,5,105,36,93,43,40,0,0,0,0,0,0,0,0,0,0
|
||||
2048604,Turalyon's Helm of Conquest,332,85,4,1,4,4,4,175,7,212,32,111,36,99,0,0,0,0,0,0,0,0,0,0,0,0
|
||||
2047706,Shoulders of the Groundbreaker,345,85,4,3,4,3,45,168,7,119,5,119,32,91,43,52,0,0,0,0,0,0,0,0,0,0
|
||||
2048331,Thrall's Shoulderpads of Triumph,345,85,4,3,4,3,45,168,7,119,5,119,36,103,32,91,0,0,0,0,0,0,0,0,0,0
|
||||
2048287,Nobundo's Headpiece of Triumph,345,85,4,1,4,3,45,203,7,159,5,159,32,117,43,62,0,0,0,0,0,0,0,0,0,0
|
||||
2047784,Kel'Thuzad's Hood of Conquest,332,85,4,1,4,1,45,175,7,142,5,142,6,99,32,111,0,0,0,0,0,0,0,0,0,0
|
||||
2048724,Talisman of Resurgence,345,85,4,12,4,0,5,198,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0
|
||||
2048629,Liadrin's Helm of Conquest,332,85,4,1,4,4,4,175,7,212,32,111,36,99,0,0,0,0,0,0,0,0,0,0,0,0
|
||||
2048661,Liadrin's Shoulderguards of Triumph,345,85,4,3,4,4,4,119,7,215,12,103,13,103,37,66,0,0,0,0,0,0,0,0,0,0
|
||||
2047673,Sigil of Virulence,345,85,4,28,4,10,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0
|
||||
2048278,Windrunner's Legguards of Conquest,332,85,4,7,4,3,38,199,3,161,7,97,5,147,32,124,44,97,0,0,0,0,0,0,0,0
|
||||
2048608,Turalyon's Gauntlets of Triumph,345,85,4,10,4,4,4,165,7,178,32,103,31,91,0,0,0,0,0,0,0,0,0,0,0,0
|
||||
2048448,Wrynn's Pauldrons of Conquest,332,85,4,3,4,4,4,105,7,189,12,93,13,93,37,57,0,0,0,0,0,0,0,0,0,0
|
||||
2047712,Shoulders of the Fateful Accord,345,85,4,3,4,2,45,168,7,119,5,119,6,103,32,91,0,0,0,0,0,0,0,0,0,0
|
||||
2048391,Hellscream's Battleplate of Triumph,345,85,4,5,4,4,4,215,7,240,32,127,44,127,0,0,0,0,0,0,0,0,0,0,0,0
|
||||
2047805,Gul'dan's Leggings of Triumph,345,85,4,7,4,1,45,217,7,159,5,159,32,139,36,114,0,0,0,0,0,0,0,0,0,0
|
||||
2048279,Windrunner's Spaulders of Conquest,332,85,4,3,4,3,38,159,3,125,7,110,5,72,32,93,31,72,0,0,0,0,0,0,0,0
|
||||
2048626,Liadrin's Battleplate of Triumph,345,85,4,5,4,4,4,215,7,240,32,127,44,127,0,0,0,0,0,0,0,0,0,0,0,0
|
||||
2048158,Malfurion's Cover of Conquest,332,85,4,1,4,2,45,175,7,142,5,142,31,111,32,99,0,0,0,0,0,0,0,0,0,0
|
||||
2048254,Windrunner's Handguards of Conquest,332,85,4,10,4,3,38,184,3,125,7,110,5,72,32,80,36,72,0,0,0,0,0,0,0,0
|
||||
2048539,Thassarian's Handguards of Triumph,345,85,4,10,4,4,4,156,7,215,12,82,13,82,14,69,0,0,0,0,0,0,0,0,0,0
|
||||
2048430,Wrynn's Greathelm of Triumph,345,85,4,1,4,4,4,210,7,260,12,97,13,85,0,0,0,0,0,0,0,0,0,0,0,0
|
||||
2048628,Liadrin's Legplates of Conquest,332,85,4,7,4,4,4,187,7,212,32,111,37,111,0,0,0,0,0,0,0,0,0,0,0,0
|
||||
2048155,Runetotem's Leggings of Conquest,332,85,4,7,4,2,45,189,7,142,5,142,6,111,36,111,0,0,0,0,0,0,0,0,0,0
|
||||
2048631,Liadrin's Battleplate of Conquest,332,85,4,5,4,4,4,187,7,212,32,111,44,111,0,0,0,0,0,0,0,0,0,0,0,0
|
||||
2048633,Turalyon's Handguards of Conquest,332,85,4,10,4,4,4,137,7,189,12,72,13,60,14,72,0,0,0,0,0,0,0,0,0,0
|
||||
2048606,Turalyon's Shoulderplates of Conquest,332,85,4,3,4,4,4,145,7,158,32,93,31,80,0,0,0,0,0,0,0,0,0,0,0,0
|
||||
2047782,Kel'Thuzad's Gloves of Triumph,345,85,4,10,4,1,45,168,7,119,5,119,32,103,31,91,0,0,0,0,0,0,0,0,0,0
|
||||
2048131,Malfurion's Spaulders of Conquest,332,85,4,3,4,2,45,148,7,105,5,105,6,80,36,93,0,0,0,0,0,0,0,0,0,0
|
||||
2048578,Turalyon's Greaves of Triumph,345,85,4,7,4,4,45,217,7,159,5,159,32,114,43,69,0,0,0,0,0,0,0,0,0,0
|
||||
2048374,Wrynn's Shoulderplates of Conquest,332,85,4,3,4,4,4,145,7,158,32,93,44,80,0,0,0,0,0,0,0,0,0,0,0,0
|
||||
2048276,Windrunner's Handguards of Conquest,332,85,4,10,4,3,38,184,3,125,7,110,5,72,32,80,36,72,0,0,0,0,0,0,0,0
|
||||
2048340,Thrall's Shoulderpads of Conquest,332,85,4,3,4,3,45,148,7,105,5,105,36,93,32,80,0,0,0,0,0,0,0,0,0,0
|
||||
2048295,Thrall's Tunic of Conquest,332,85,4,5,4,3,45,189,7,142,5,142,36,111,32,111,0,0,0,0,0,0,0,0,0,0
|
||||
2048098,Zabra's Circlet of Conquest,332,85,4,1,4,1,45,175,7,142,5,142,6,99,31,111,0,0,0,0,0,0,0,0,0,0
|
||||
2048240,Garona's Helmet of Triumph,345,85,4,1,4,2,38,230,3,186,7,210,32,139,37,114,0,0,0,0,0,0,0,0,0,0
|
||||
2048318,Nobundo's Helm of Triumph,345,85,4,1,4,3,45,203,7,159,5,159,32,124,36,130,0,0,0,0,0,0,0,0,0,0
|
||||
2048256,Windrunner's Handguards of Triumph,345,85,4,10,4,3,38,209,3,144,7,124,5,82,32,91,36,82,0,0,0,0,0,0,0,0
|
||||
2047693,Hood of Fiery Aftermath,345,85,4,1,4,1,45,203,7,159,5,159,36,127,31,114,0,0,0,0,0,0,0,0,0,0
|
||||
2047667,Totem of Quaking Earth,345,85,4,28,4,9,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0
|
||||
2048182,Runetotem's Gloves of Triumph,345,85,4,10,4,2,45,168,7,119,5,119,6,91,36,103,0,0,0,0,0,0,0,0,0,0
|
||||
2048502,Koltira's Gauntlets of Conquest,332,85,4,10,4,4,4,145,7,158,32,93,31,80,0,0,0,0,0,0,0,0,0,0,0,0
|
||||
2048217,Malfurion's Shoulderpads of Conquest,332,85,4,3,4,2,38,184,3,125,7,137,36,93,44,80,0,0,0,0,0,0,0,0,0,0
|
||||
2048241,Garona's Gauntlets of Triumph,345,85,4,10,4,2,38,184,3,156,7,156,32,103,31,91,0,0,0,0,0,0,0,0,0,0
|
||||
2048485,Thassarian's Shoulderplates of Triumph,345,85,4,3,4,4,4,165,7,178,32,103,31,91,0,0,0,0,0,0,0,0,0,0,0,0
|
||||
2048458,Hellscream's Greathelm of Conquest,332,85,4,1,4,4,4,186,7,224,12,85,13,72,0,0,0,0,0,0,0,0,0,0,0,0
|
||||
2048393,Hellscream's Helmet of Triumph,345,85,4,1,4,4,4,203,7,240,32,114,31,127,0,0,0,0,0,0,0,0,0,0,0,0
|
||||
2048153,Runetotem's Handguards of Conquest,332,85,4,10,4,2,45,148,7,105,5,105,6,93,32,80,0,0,0,0,0,0,0,0,0,0
|
||||
2047778,Kel'Thuzad's Hood of Triumph,345,85,4,1,4,1,45,203,7,159,5,159,6,114,32,127,0,0,0,0,0,0,0,0,0,0
|
||||
2047729,Bloodshed Band,345,85,4,11,4,0,4,133,7,133,32,83,31,68,0,0,0,0,0,0,0,0,0,0,0,0
|
||||
2048215,Malfurion's Legguards of Conquest,332,85,4,7,4,2,38,199,3,161,7,186,32,124,31,99,0,0,0,0,0,0,0,0,0,0
|
||||
2048449,Wrynn's Handguards of Conquest,332,85,4,10,4,4,4,137,7,189,12,72,13,60,14,72,0,0,0,0,0,0,0,0,0,0
|
||||
2048460,Hellscream's Pauldrons of Conquest,332,85,4,3,4,4,4,105,7,189,12,93,13,93,37,57,0,0,0,0,0,0,0,0,0,0
|
||||
2048332,Thrall's Kilt of Triumph,345,85,4,7,4,3,45,217,7,159,5,159,32,114,31,139,0,0,0,0,0,0,0,0,0,0
|
||||
2048660,Liadrin's Legguards of Triumph,345,85,4,7,4,4,4,159,7,279,12,139,31,82,0,0,0,0,0,0,0,0,0,0,0,0
|
||||
2048255,Windrunner's Tunic of Triumph,345,85,4,5,4,3,38,420,3,114,7,165,5,110,32,127,31,97,0,0,0,0,0,0,0,0
|
||||
2048274,Windrunner's Tunic of Triumph,345,85,4,5,4,3,38,420,3,114,7,165,5,110,32,127,31,97,0,0,0,0,0,0,0,0
|
||||
2048129,Malfurion's Robe of Conquest,332,85,4,20,4,2,45,189,7,142,5,142,6,111,32,111,0,0,0,0,0,0,0,0,0,0
|
||||
2048349,Nobundo's War-Kilt of Triumph,345,85,4,7,4,3,38,230,3,186,7,110,5,165,32,139,31,110,0,0,0,0,0,0,0,0
|
||||
2048452,Wrynn's Handguards of Triumph,345,85,4,10,4,4,4,156,7,215,12,82,13,69,14,82,0,0,0,0,0,0,0,0,0,0
|
||||
2047983,Velen's Gloves of Triumph,345,85,4,10,4,1,45,168,7,119,5,119,6,91,36,103,0,0,0,0,0,0,0,0,0,0
|
||||
2048289,Nobundo's Spaulders of Triumph,345,85,4,3,4,3,45,168,7,119,5,119,36,91,43,52,0,0,0,0,0,0,0,0,0,0
|
||||
2048376,Wrynn's Battleplate of Triumph,345,85,4,5,4,4,4,215,7,240,32,127,44,127,0,0,0,0,0,0,0,0,0,0,0,0
|
||||
2048064,Zabra's Leggings of Triumph,345,85,4,7,4,1,45,217,7,159,5,159,6,127,36,127,0,0,0,0,0,0,0,0,0,0
|
||||
2048251,Windrunner's Tunic of Conquest,332,85,4,5,4,3,38,373,3,99,7,147,5,97,32,111,31,85,0,0,0,0,0,0,0,0
|
||||
2048151,Runetotem's Headpiece of Triumph,345,85,4,1,4,2,45,203,7,159,5,159,6,114,32,127,0,0,0,0,0,0,0,0,0,0
|
||||
2048137,Malfurion's Spaulders of Triumph,345,85,4,3,4,2,45,168,7,119,5,119,6,91,36,103,0,0,0,0,0,0,0,0,0,0
|
||||
2048079,Velen's Pants of Triumph,345,85,4,7,4,1,45,217,7,159,5,159,36,114,31,139,0,0,0,0,0,0,0,0,0,0
|
||||
2048348,Nobundo's Faceguard of Triumph,345,85,4,1,4,3,38,230,3,186,7,165,5,110,31,114,32,110,0,0,0,0,0,0,0,0
|
||||
2048599,Liadrin's Tunic of Conquest,332,85,4,5,4,4,45,189,7,142,5,142,32,99,43,62,0,0,0,0,0,0,0,0,0,0
|
||||
2048338,Thrall's Helm of Conquest,332,85,4,1,4,3,45,175,7,142,5,142,32,108,36,114,0,0,0,0,0,0,0,0,0,0
|
||||
2047682,Helm of the Restless Watch,345,85,4,1,4,4,45,203,7,159,5,159,32,102,43,69,0,0,0,0,0,0,0,0,0,0
|
||||
2048361,Thrall's Shoulderguards of Triumph,345,85,4,3,4,3,38,288,3,91,7,124,5,82,32,103,31,82,0,0,0,0,0,0,0,0
|
||||
2048277,Windrunner's Headpiece of Conquest,332,85,4,1,4,3,38,199,3,161,7,147,5,97,32,124,44,72,0,0,0,0,0,0,0,0
|
||||
2048092,Zabra's Mantle of Triumph,345,85,4,3,4,1,45,168,7,119,5,119,6,103,32,91,0,0,0,0,0,0,0,0,0,0
|
||||
2048594,Liadrin's Tunic of Triumph,345,85,4,5,4,4,45,217,7,159,5,159,32,114,43,69,0,0,0,0,0,0,0,0,0,0
|
||||
2048273,Windrunner's Handguards of Triumph,345,85,4,10,4,3,38,209,3,144,7,124,5,82,32,91,36,82,0,0,0,0,0,0,0,0
|
||||
2048283,Nobundo's Spaulders of Conquest,332,85,4,3,4,3,45,148,7,105,5,105,36,80,43,46,0,0,0,0,0,0,0,0,0,0
|
||||
2048593,Liadrin's Gloves of Triumph,345,85,4,10,4,4,45,168,7,119,5,119,36,103,43,46,0,0,0,0,0,0,0,0,0,0
|
||||
2048259,Windrunner's Spaulders of Triumph,345,85,4,3,4,3,38,184,3,144,7,124,5,82,32,103,31,82,0,0,0,0,0,0,0,0
|
||||
2048480,Thassarian's Gauntlets of Conquest,332,85,4,10,4,4,4,145,7,158,32,93,31,80,0,0,0,0,0,0,0,0,0,0,0,0
|
||||
2048320,Nobundo's Shoulderpads of Triumph,345,85,4,3,4,3,45,168,7,119,5,119,36,103,32,91,0,0,0,0,0,0,0,0,0,0
|
||||
2048373,Wrynn's Legplates of Conquest,332,85,4,7,4,4,4,187,7,212,32,111,37,111,0,0,0,0,0,0,0,0,0,0,0,0
|
||||
2047691,Mask of Abundant Growth,345,85,4,1,4,2,45,203,7,159,5,159,6,127,36,114,0,0,0,0,0,0,0,0,0,0
|
||||
2048501,Koltira's Battleplate of Conquest,332,85,4,5,4,4,4,187,7,212,32,111,36,111,0,0,0,0,0,0,0,0,0,0,0,0
|
||||
2047781,Kel'Thuzad's Shoulderpads of Triumph,345,85,4,3,4,1,45,168,7,119,5,119,6,91,32,103,0,0,0,0,0,0,0,0,0,0
|
||||
2047686,Helm of Inner Warmth,345,85,4,1,4,3,45,203,7,159,5,159,36,102,43,69,0,0,0,0,0,0,0,0,0,0
|
||||
2048195,Runetotem's Legguards of Triumph,345,85,4,7,4,2,38,230,3,186,7,210,32,139,31,114,0,0,0,0,0,0,0,0,0,0
|
||||
2047806,Gul'dan's Robe of Triumph,345,85,4,20,4,1,45,217,7,159,5,159,6,127,31,127,0,0,0,0,0,0,0,0,0,0
|
||||
2048069,Zabra's Leggings of Conquest,332,85,4,7,4,1,45,189,7,142,5,142,6,111,36,111,0,0,0,0,0,0,0,0,0,0
|
||||
2048303,Thrall's Legguards of Triumph,345,85,4,7,4,3,45,217,7,159,5,159,32,130,43,62,0,0,0,0,0,0,0,0,0,0
|
||||
2047694,Helm of Clouded Sight,345,85,4,1,4,1,45,203,7,159,5,159,6,139,32,102,0,0,0,0,0,0,0,0,0,0
|
||||
2048627,Liadrin's Shoulderplates of Conquest,332,85,4,3,4,4,4,145,7,158,32,93,31,80,0,0,0,0,0,0,0,0,0,0,0,0
|
||||
2047690,Helm of Abundant Growth,345,85,4,1,4,2,45,203,7,159,5,159,6,127,36,114,0,0,0,0,0,0,0,0,0,0
|
||||
2048063,Zabra's Robe of Triumph,345,85,4,20,4,1,45,217,7,159,5,159,6,127,32,127,0,0,0,0,0,0,0,0,0,0
|
||||
2048299,Thrall's Spaulders of Conquest,332,85,4,3,4,3,45,148,7,105,5,105,36,80,43,46,0,0,0,0,0,0,0,0,0,0
|
||||
2047773,Sunstrider's Gauntlets of Conquest,332,85,4,10,4,1,45,148,7,105,5,105,32,93,36,80,0,0,0,0,0,0,0,0,0,0
|
||||
2048375,Wrynn's Gauntlets of Conquest,332,85,4,10,4,4,4,145,7,158,32,93,31,80,0,0,0,0,0,0,0,0,0,0,0,0
|
||||
2047775,Sunstrider's Leggings of Conquest,332,85,4,7,4,1,45,189,7,142,5,142,6,99,32,124,0,0,0,0,0,0,0,0,0,0
|
||||
2047697,Pauldrons of Trembling Rage,345,85,4,3,4,4,4,165,7,178,32,103,31,91,0,0,0,0,0,0,0,0,0,0,0,0
|
||||
2048387,Hellscream's Gauntlets of Conquest,332,85,4,10,4,4,4,145,7,158,32,93,31,80,0,0,0,0,0,0,0,0,0,0,0,0
|
||||
2048345,Nobundo's Shoulderguards of Conquest,332,85,4,3,4,3,38,252,3,80,7,110,5,72,32,93,31,72,0,0,0,0,0,0,0,0
|
||||
2048243,Garona's Breastplate of Conquest,332,85,4,5,4,2,38,224,3,161,7,186,32,124,31,111,0,0,0,0,0,0,0,0,0,0
|
||||
2048363,Thrall's Faceguard of Triumph,345,85,4,1,4,3,38,230,3,186,7,165,5,110,31,114,32,110,0,0,0,0,0,0,0,0
|
||||
2048362,Thrall's War-Kilt of Triumph,345,85,4,7,4,3,38,230,3,186,7,110,5,165,32,139,31,110,0,0,0,0,0,0,0,0
|
||||
2047731,Clutch of Fortification,345,85,4,11,4,0,4,117,7,176,12,62,13,62,0,0,0,0,0,0,0,0,0,0,0,0
|
||||
2047714,Pauldrons of Catastrophic Emanation,345,85,4,3,4,1,45,168,7,119,5,119,32,91,31,103,0,0,0,0,0,0,0,0,0,0
|
||||
2047732,Band of the Invoker,345,85,4,11,4,0,45,137,7,89,5,89,6,77,36,77,0,0,0,0,0,0,0,0,0,0
|
||||
2047701,Shoulderplates of the Cavalier,345,85,4,3,4,4,45,168,7,119,5,119,32,91,36,103,0,0,0,0,0,0,0,0,0,0
|
||||
2048365,Thrall's Chestguard of Triumph,345,85,4,5,4,3,38,420,3,114,7,165,5,110,32,127,36,97,0,0,0,0,0,0,0,0
|
||||
2048535,Thassarian's Pauldrons of Conquest,332,85,4,3,4,4,4,105,7,189,12,93,14,93,31,57,0,0,0,0,0,0,0,0,0,0
|
||||
2048313,Nobundo's Helm of Conquest,332,85,4,1,4,3,45,175,7,142,5,142,32,108,36,114,0,0,0,0,0,0,0,0,0,0
|
||||
2047801,Gul'dan's Hood of Conquest,332,85,4,1,4,1,45,175,7,142,5,142,6,99,32,111,0,0,0,0,0,0,0,0,0,0
|
||||
2048100,Zabra's Raiments of Conquest,332,85,4,20,4,1,45,189,7,142,5,142,6,111,36,111,0,0,0,0,0,0,0,0,0,0
|
||||
2047749,Khadgar's Robe of Conquest,332,85,4,20,4,1,45,189,7,142,5,142,6,124,31,99,0,0,0,0,0,0,0,0,0,0
|
||||
2047684,Coif of the Brooding Dragon,345,85,4,1,4,3,38,230,3,186,7,165,5,110,44,139,36,85,0,0,0,0,0,0,0,0
|
||||
2048446,Wrynn's Legguards of Triumph,345,85,4,7,4,4,4,159,7,279,12,139,31,82,0,0,0,0,0,0,0,0,0,0,0,0
|
||||
2048078,Velen's Circlet of Triumph,345,85,4,1,4,1,45,203,7,159,5,159,6,114,31,127,0,0,0,0,0,0,0,0,0,0
|
||||
2047670,Idol of Lunar Fury,345,85,4,28,4,8,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0
|
||||
2048369,Thrall's War-Kilt of Conquest,332,85,4,7,4,3,38,199,3,161,7,97,5,147,32,124,31,97,0,0,0,0,0,0,0,0
|
||||
2048344,Nobundo's War-Kilt of Conquest,332,85,4,7,4,3,38,199,3,161,7,97,5,147,32,124,31,97,0,0,0,0,0,0,0,0
|
||||
2047752,Khadgar's Gauntlets of Conquest,332,85,4,10,4,1,45,148,7,105,5,105,32,93,36,80,0,0,0,0,0,0,0,0,0,0
|
||||
2048503,Koltira's Helmet of Conquest,332,85,4,1,4,4,4,175,7,212,32,111,37,99,0,0,0,0,0,0,0,0,0,0,0,0
|
||||
2048377,Wrynn's Gauntlets of Triumph,345,85,4,10,4,4,4,165,7,178,32,103,31,91,0,0,0,0,0,0,0,0,0,0,0,0
|
||||
2048579,Turalyon's Spaulders of Triumph,345,85,4,3,4,4,45,168,7,119,5,119,32,103,36,91,0,0,0,0,0,0,0,0,0,0
|
||||
2048296,Thrall's Handguards of Conquest,332,85,4,10,4,3,45,148,7,105,5,105,36,80,43,46,0,0,0,0,0,0,0,0,0,0
|
||||
2047734,Mark of Supremacy,345,85,4,12,4,0,31,198,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0
|
||||
2047692,Hood of Smoldering Aftermath,345,85,4,1,4,1,45,203,7,159,5,159,36,127,31,114,0,0,0,0,0,0,0,0,0,0
|
||||
2048189,Runetotem's Raiments of Conquest,332,85,4,20,4,2,38,249,3,161,7,186,32,114,36,108,0,0,0,0,0,0,0,0,0,0
|
||||
2048336,Thrall's Hauberk of Conquest,332,85,4,5,4,3,45,189,7,142,5,142,36,111,31,111,0,0,0,0,0,0,0,0,0,0
|
||||
2048208,Malfurion's Shoulderpads of Triumph,345,85,4,3,4,2,38,209,3,144,7,156,36,103,44,91,0,0,0,0,0,0,0,0,0,0
|
||||
2048654,Liadrin's Faceguard of Conquest,332,85,4,1,4,4,4,186,7,224,12,85,13,72,0,0,0,0,0,0,0,0,0,0,0,0
|
||||
2047678,Headplate of the Honorbound,345,85,4,1,4,4,4,159,7,260,12,127,37,106,13,114,0,0,0,0,0,0,0,0,0,0
|
||||
2048080,Velen's Raiments of Triumph,345,85,4,20,4,1,45,217,7,159,5,159,6,127,36,127,0,0,0,0,0,0,0,0,0,0
|
||||
2047748,Khadgar's Hood of Conquest,332,85,4,1,4,1,45,175,7,142,5,142,36,111,31,99,0,0,0,0,0,0,0,0,0,0
|
||||
2047685,Helm of the Brooding Dragon,345,85,4,1,4,3,38,230,3,186,7,165,5,110,44,139,36,85,0,0,0,0,0,0,0,0
|
||||
2047696,Shoulderplates of Trembling Rage,345,85,4,3,4,4,4,165,7,178,32,103,31,91,0,0,0,0,0,0,0,0,0,0,0,0
|
||||
2048335,Thrall's Hauberk of Triumph,345,85,4,5,4,3,45,217,7,159,5,159,36,127,31,127,0,0,0,0,0,0,0,0,0,0
|
||||
2048554,Koltira's Legguards of Triumph,345,85,4,7,4,4,4,159,7,279,12,100,14,94,13,110,0,0,0,0,0,0,0,0,0,0
|
||||
2048635,Turalyon's Legguards of Conquest,332,85,4,7,4,4,4,142,7,243,12,124,31,69,0,0,0,0,0,0,0,0,0,0,0,0
|
||||
2048630,Liadrin's Gauntlets of Conquest,332,85,4,10,4,4,4,145,7,158,32,93,31,80,0,0,0,0,0,0,0,0,0,0,0,0
|
||||
2047777,Sunstrider's Shoulderpads of Conquest,332,85,4,3,4,1,45,148,7,105,5,105,32,80,36,93,0,0,0,0,0,0,0,0,0,0
|
||||
2048564,Turalyon's Headpiece of Conquest,332,85,4,1,4,4,45,175,7,142,5,142,32,99,36,111,0,0,0,0,0,0,0,0,0,0
|
||||
2048133,Malfurion's Handguards of Triumph,345,85,4,10,4,2,45,168,7,119,5,119,6,103,32,91,0,0,0,0,0,0,0,0,0,0
|
||||
2048658,Liadrin's Handguards of Triumph,345,85,4,10,4,4,4,156,7,215,12,82,13,69,14,82,0,0,0,0,0,0,0,0,0,0
|
||||
2048315,Nobundo's Shoulderpads of Conquest,332,85,4,3,4,3,45,148,7,105,5,105,36,93,32,80,0,0,0,0,0,0,0,0,0,0
|
||||
2048659,Liadrin's Faceguard of Triumph,345,85,4,1,4,4,4,210,7,260,12,97,13,85,0,0,0,0,0,0,0,0,0,0,0,0
|
||||
2048429,Wrynn's Greathelm of Conquest,332,85,4,1,4,4,4,186,7,224,12,85,13,72,0,0,0,0,0,0,0,0,0,0,0,0
|
||||
2048533,Thassarian's Legguards of Conquest,332,85,4,7,4,4,4,142,7,243,12,88,14,82,13,97,0,0,0,0,0,0,0,0,0,0
|
||||
2047687,Headguard of Inner Warmth,345,85,4,1,4,3,45,203,7,159,5,159,36,102,43,69,0,0,0,0,0,0,0,0,0,0
|
||||
2048186,Runetotem's Vestments of Conquest,332,85,4,20,4,2,45,189,7,142,5,142,36,124,32,99,0,0,0,0,0,0,0,0,0,0
|
||||
2047695,Hood of Clouded Sight,345,85,4,1,4,1,45,203,7,159,5,159,6,139,32,102,0,0,0,0,0,0,0,0,0,0
|
||||
2048193,Runetotem's Handgrips of Triumph,345,85,4,10,4,2,38,209,3,144,7,156,32,103,31,91,0,0,0,0,0,0,0,0,0,0
|
||||
2047688,Mask of Lethal Intent,345,85,4,1,4,2,38,255,3,186,7,210,31,127,44,114,0,0,0,0,0,0,0,0,0,0
|
||||
2048371,Wrynn's Helmet of Conquest,332,85,4,1,4,4,4,175,7,212,32,99,31,111,0,0,0,0,0,0,0,0,0,0,0,0
|
||||
2048370,Thrall's Shoulderguards of Conquest,332,85,4,3,4,3,38,252,3,80,7,110,5,72,32,93,31,72,0,0,0,0,0,0,0,0
|
||||
2047770,Sunstrider's Leggings of Triumph,345,85,4,7,4,1,45,217,7,159,5,159,6,114,32,139,0,0,0,0,0,0,0,0,0,0
|
||||
2048538,Thassarian's Chestguard of Triumph,345,85,4,5,4,4,4,159,7,279,12,110,14,100,13,94,0,0,0,0,0,0,0,0,0,0
|
||||
2048179,Runetotem's Vestments of Triumph,345,85,4,20,4,2,45,217,7,159,5,159,36,139,32,114,0,0,0,0,0,0,0,0,0,0
|
||||
2048270,Windrunner's Spaulders of Triumph,345,85,4,3,4,3,38,184,3,144,7,124,5,82,32,103,31,82,0,0,0,0,0,0,0,0
|
||||
2047936,Velen's Robe of Conquest,332,85,4,20,4,1,45,189,7,142,5,142,6,111,32,111,0,0,0,0,0,0,0,0,0,0
|
||||
2048390,Hellscream's Shoulderplates of Conquest,332,85,4,3,4,4,4,145,7,158,32,93,44,80,0,0,0,0,0,0,0,0,0,0,0,0
|
||||
2048592,Liadrin's Headpiece of Triumph,345,85,4,1,4,4,45,203,7,159,5,159,32,114,36,127,0,0,0,0,0,0,0,0,0,0
|
||||
2048216,Malfurion's Raiments of Conquest,332,85,4,20,4,2,38,249,3,161,7,186,32,114,36,108,0,0,0,0,0,0,0,0,0,0
|
||||
2047757,Khadgar's Shoulderpads of Triumph,345,85,4,3,4,1,45,168,7,119,5,119,32,91,36,103,0,0,0,0,0,0,0,0,0,0
|
||||
2047671,Idol of Flaring Growth,345,85,4,28,4,8,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0
|
||||
2047807,Gul'dan's Shoulderpads of Triumph,345,85,4,3,4,1,45,168,7,119,5,119,6,91,32,103,0,0,0,0,0,0,0,0,0,0
|
||||
2048656,Liadrin's Shoulderguards of Conquest,332,85,4,3,4,4,4,105,7,189,12,93,13,93,37,57,0,0,0,0,0,0,0,0,0,0
|
||||
2048638,Turalyon's Legguards of Triumph,345,85,4,7,4,4,4,159,7,279,12,139,31,82,0,0,0,0,0,0,0,0,0,0,0,0
|
||||
2048591,Liadrin's Greaves of Triumph,345,85,4,7,4,4,45,217,7,159,5,159,32,114,43,69,0,0,0,0,0,0,0,0,0,0
|
||||
2047716,Mantle of Revered Mortality,345,85,4,3,4,1,45,168,7,119,5,119,6,103,36,91,0,0,0,0,0,0,0,0,0,0
|
||||
2048595,Liadrin's Spaulders of Conquest,332,85,4,3,4,4,45,148,7,105,5,105,32,93,36,80,0,0,0,0,0,0,0,0,0,0
|
||||
2048272,Windrunner's Headpiece of Triumph,345,85,4,1,4,3,38,230,3,186,7,165,5,110,32,139,44,85,0,0,0,0,0,0,0,0
|
||||
2048395,Hellscream's Shoulderplates of Triumph,345,85,4,3,4,4,4,165,7,178,32,103,44,91,0,0,0,0,0,0,0,0,0,0,0,0
|
||||
2048574,Turalyon's Gloves of Conquest,332,85,4,10,4,4,45,148,7,105,5,105,36,93,43,40,0,0,0,0,0,0,0,0,0,0
|
||||
2048071,Zabra's Shoulderpads of Conquest,332,85,4,3,4,1,45,148,7,105,5,105,6,93,32,80,0,0,0,0,0,0,0,0,0,0
|
||||
2048247,Garona's Pauldrons of Conquest,332,85,4,3,4,2,38,159,3,137,7,137,44,93,37,80,0,0,0,0,0,0,0,0,0,0
|
||||
2048317,Nobundo's Gloves of Triumph,345,85,4,10,4,3,45,168,7,119,5,119,36,91,31,103,0,0,0,0,0,0,0,0,0,0
|
||||
2048597,Liadrin's Headpiece of Conquest,332,85,4,1,4,4,45,175,7,142,5,142,32,99,36,111,0,0,0,0,0,0,0,0,0,0
|
||||
2048285,Nobundo's Tunic of Triumph,345,85,4,5,4,3,45,217,7,159,5,159,36,127,32,127,0,0,0,0,0,0,0,0,0,0
|
||||
2047661,Libram of Valiance,345,85,4,28,4,7,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0
|
||||
2048339,Thrall's Kilt of Conquest,332,85,4,7,4,3,45,189,7,142,5,142,32,99,31,124,0,0,0,0,0,0,0,0,0,0
|
||||
2048271,Windrunner's Legguards of Triumph,345,85,4,7,4,3,38,230,3,186,7,110,5,165,32,139,44,110,0,0,0,0,0,0,0,0
|
||||
2048134,Malfurion's Headpiece of Triumph,345,85,4,1,4,2,45,203,7,159,5,159,6,114,32,127,0,0,0,0,0,0,0,0,0,0
|
||||
2048184,Runetotem's Cover of Conquest,332,85,4,1,4,2,45,175,7,142,5,142,31,111,32,99,0,0,0,0,0,0,0,0,0,0
|
||||
2048457,Hellscream's Handguards of Conquest,332,85,4,10,4,4,4,137,7,189,12,72,13,60,14,72,0,0,0,0,0,0,0,0,0,0
|
||||
2048388,Hellscream's Helmet of Conquest,332,85,4,1,4,4,4,175,7,212,32,99,31,111,0,0,0,0,0,0,0,0,0,0,0,0
|
||||
2047756,Khadgar's Robe of Triumph,345,85,4,20,4,1,45,217,7,159,5,159,6,139,31,114,0,0,0,0,0,0,0,0,0,0
|
||||
2048542,Thassarian's Pauldrons of Triumph,345,85,4,3,4,4,4,119,7,215,12,103,14,103,31,66,0,0,0,0,0,0,0,0,0,0
|
||||
2048066,Zabra's Gloves of Triumph,345,85,4,10,4,1,45,168,7,119,5,119,6,91,36,103,0,0,0,0,0,0,0,0,0,0
|
||||
2048609,Turalyon's Helm of Triumph,345,85,4,1,4,4,4,203,7,240,32,127,36,114,0,0,0,0,0,0,0,0,0,0,0,0
|
||||
2048499,Koltira's Gauntlets of Triumph,345,85,4,10,4,4,4,165,7,178,32,103,31,91,0,0,0,0,0,0,0,0,0,0,0,0
|
||||
2048304,Thrall's Spaulders of Triumph,345,85,4,3,4,3,45,168,7,119,5,119,36,91,43,52,0,0,0,0,0,0,0,0,0,0
|
||||
2047710,Epaulets of the Fateful Accord,345,85,4,3,4,2,45,168,7,119,5,119,6,103,32,91,0,0,0,0,0,0,0,0,0,0
|
||||
2047804,Gul'dan's Hood of Triumph,345,85,4,1,4,1,45,203,7,159,5,159,6,114,32,127,0,0,0,0,0,0,0,0,0,0
|
||||
2048380,Wrynn's Shoulderplates of Triumph,345,85,4,3,4,4,4,165,7,178,32,103,44,91,0,0,0,0,0,0,0,0,0,0,0,0
|
||||
2048191,Runetotem's Shoulderpads of Conquest,332,85,4,3,4,2,38,184,3,125,7,137,36,93,44,80,0,0,0,0,0,0,0,0,0,0
|
||||
2048165,Malfurion's Trousers of Triumph,345,85,4,7,4,2,45,217,7,159,5,159,6,114,31,139,0,0,0,0,0,0,0,0,0,0
|
||||
2048378,Wrynn's Helmet of Triumph,345,85,4,1,4,4,4,203,7,240,32,114,31,127,0,0,0,0,0,0,0,0,0,0,0,0
|
||||
2048211,Malfurion's Headguard of Triumph,345,85,4,1,4,2,38,230,3,186,7,210,32,139,37,114,0,0,0,0,0,0,0,0,0,0
|
||||
2048540,Thassarian's Faceguard of Triumph,345,85,4,1,4,4,4,159,7,260,12,127,31,82,13,139,0,0,0,0,0,0,0,0,0,0
|
||||
2047772,Sunstrider's Gauntlets of Triumph,345,85,4,10,4,1,45,168,7,119,5,119,32,103,36,91,0,0,0,0,0,0,0,0,0,0
|
||||
2047713,Mantle of Catastrophic Emanation,345,85,4,3,4,1,45,168,7,119,5,119,32,91,31,103,0,0,0,0,0,0,0,0,0,0
|
||||
2048316,Nobundo's Hauberk of Triumph,345,85,4,5,4,3,45,217,7,159,5,159,36,127,31,127,0,0,0,0,0,0,0,0,0,0
|
||||
2047689,Hood of Lethal Intent,345,85,4,1,4,2,38,255,3,186,7,210,31,127,44,114,0,0,0,0,0,0,0,0,0,0
|
||||
2048436,Wrynn's Breastplate of Conquest,332,85,4,5,4,4,4,186,7,243,12,97,14,85,13,85,0,0,0,0,0,0,0,0,0,0
|
||||
2048557,Koltira's Chestguard of Triumph,345,85,4,5,4,4,4,159,7,279,12,110,14,100,13,94,0,0,0,0,0,0,0,0,0,0
|
||||
2048065,Zabra's Cowl of Triumph,345,85,4,1,4,1,45,203,7,159,5,159,6,127,32,114,0,0,0,0,0,0,0,0,0,0
|
||||
2048257,Windrunner's Headpiece of Triumph,345,85,4,1,4,3,38,230,3,186,7,165,5,110,32,139,44,85,0,0,0,0,0,0,0,0
|
||||
2047981,Velen's Shoulderpads of Conquest,332,85,4,3,4,1,45,148,7,105,5,105,6,93,32,80,0,0,0,0,0,0,0,0,0,0
|
||||
2048300,Thrall's Tunic of Triumph,345,85,4,5,4,3,45,217,7,159,5,159,36,127,32,127,0,0,0,0,0,0,0,0,0,0
|
||||
2048577,Turalyon's Headpiece of Triumph,345,85,4,1,4,4,45,203,7,159,5,159,32,114,36,127,0,0,0,0,0,0,0,0,0,0
|
||||
2048282,Nobundo's Legguards of Conquest,332,85,4,7,4,3,45,189,7,142,5,142,32,114,43,54,0,0,0,0,0,0,0,0,0,0
|
||||
2048483,Thassarian's Helmet of Triumph,345,85,4,1,4,4,4,203,7,240,32,127,37,114,0,0,0,0,0,0,0,0,0,0,0,0
|
||||
2048180,Runetotem's Trousers of Triumph,345,85,4,7,4,2,45,217,7,159,5,159,6,114,31,139,0,0,0,0,0,0,0,0,0,0
|
||||
2047783,Kel'Thuzad's Gloves of Conquest,332,85,4,10,4,1,45,148,7,105,5,105,32,93,31,80,0,0,0,0,0,0,0,0,0,0
|
||||
2048280,Nobundo's Headpiece of Conquest,332,85,4,1,4,3,45,175,7,142,5,142,32,102,43,54,0,0,0,0,0,0,0,0,0,0
|
||||
2048149,Runetotem's Robe of Triumph,345,85,4,20,4,2,45,217,7,159,5,159,6,127,32,127,0,0,0,0,0,0,0,0,0,0
|
||||
2047776,Sunstrider's Robe of Conquest,332,85,4,20,4,1,45,189,7,142,5,142,6,124,31,99,0,0,0,0,0,0,0,0,0,0
|
||||
2048461,Hellscream's Breastplate of Triumph,345,85,4,5,4,4,4,210,7,279,12,110,14,97,13,97,0,0,0,0,0,0,0,0,0,0
|
||||
2048070,Zabra's Robe of Conquest,332,85,4,20,4,1,45,189,7,142,5,142,6,111,32,111,0,0,0,0,0,0,0,0,0,0
|
||||
2048602,Turalyon's Battleplate of Conquest,332,85,4,5,4,4,4,187,7,212,32,111,44,111,0,0,0,0,0,0,0,0,0,0,0,0
|
||||
2048166,Malfurion's Vestments of Triumph,345,85,4,20,4,2,45,217,7,159,5,159,36,139,32,114,0,0,0,0,0,0,0,0,0,0
|
||||
2048562,Koltira's Pauldrons of Conquest,332,85,4,3,4,4,4,105,7,189,12,93,14,93,31,57,0,0,0,0,0,0,0,0,0,0
|
||||
2048288,Nobundo's Legguards of Triumph,345,85,4,7,4,3,45,217,7,159,5,159,32,130,43,62,0,0,0,0,0,0,0,0,0,0
|
||||
2048343,Nobundo's Faceguard of Conquest,332,85,4,1,4,3,38,199,3,161,7,147,5,97,31,99,32,97,0,0,0,0,0,0,0,0
|
||||
2048135,Malfurion's Leggings of Triumph,345,85,4,7,4,2,45,217,7,159,5,159,6,127,36,127,0,0,0,0,0,0,0,0,0,0
|
||||
2048163,Malfurion's Gloves of Triumph,345,85,4,10,4,2,45,168,7,119,5,119,6,91,36,103,0,0,0,0,0,0,0,0,0,0
|
||||
2048275,Windrunner's Tunic of Conquest,332,85,4,5,4,3,38,373,3,99,7,147,5,97,32,111,31,85,0,0,0,0,0,0,0,0
|
||||
2048301,Thrall's Handguards of Triumph,345,85,4,10,4,3,45,168,7,119,5,119,36,91,43,52,0,0,0,0,0,0,0,0,0,0
|
||||
2048341,Nobundo's Chestguard of Conquest,332,85,4,5,4,3,38,373,3,99,7,147,5,97,32,111,36,85,0,0,0,0,0,0,0,0
|
||||
2047660,Blades of the Sable Cross,345,85,4,25,2,16,4,49,7,99,12,43,13,43,31,34,0,0,0,0,0,0,0,0,0,0
|
||||
2048196,Runetotem's Raiments of Triumph,345,85,4,20,4,2,38,280,3,186,7,210,32,130,36,124,0,0,0,0,0,0,0,0,0,0
|
||||
2047672,Sigil of Insolence,345,85,4,28,4,10,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0
|
||||
2047664,Libram of Defiance,345,85,4,28,4,7,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0
|
||||
2048346,Nobundo's Chestguard of Triumph,345,85,4,5,4,3,38,420,3,114,7,165,5,110,32,127,36,97,0,0,0,0,0,0,0,0
|
||||
2047754,Khadgar's Hood of Triumph,345,85,4,1,4,1,45,203,7,159,5,159,36,127,31,114,0,0,0,0,0,0,0,0,0,0
|
||||
2048575,Turalyon's Tunic of Triumph,345,85,4,5,4,4,45,217,7,159,5,159,32,114,43,69,0,0,0,0,0,0,0,0,0,0
|
||||
|
291
cmd/create_emblem_items/veil-emblem.csv
Normal file
291
cmd/create_emblem_items/veil-emblem.csv
Normal file
@@ -0,0 +1,291 @@
|
||||
entry,name,ItemLevel,RequiredLevel,Quality,InventoryType,class,subclass,stat_type1,stat_value1,stat_type2,stat_value2,stat_type3,stat_value3,stat_type4,stat_value4,stat_type5,stat_value5,stat_type6,stat_value6,stat_type7,stat_value7,stat_type8,stat_value8,stat_type9,stat_value9,stat_type10,stat_value10
|
||||
2050825,Lasherweave Legguards,351,85,4,7,4,2,38,246,3,223,7,223,44,148,37,124,0,0,0,0,0,0,0,0,0,0
|
||||
2050765,Crimson Acolyte Hood,351,85,4,1,4,1,45,217,7,168,5,168,6,124,32,136,0,0,0,0,0,0,0,0,0,0
|
||||
2050832,Frost Witch's Faceguard,351,85,4,1,4,3,38,246,3,210,7,175,5,117,32,136,36,93,0,0,0,0,0,0,0,0
|
||||
2048231,VanCleef's Gauntlets of Triumph,358,85,4,10,4,2,38,209,3,176,7,176,32,117,31,105,0,0,0,0,0,0,0,0,0,0
|
||||
2048291,Nobundo's Legguards of Triumph,358,85,4,7,4,3,45,248,7,179,5,179,32,148,43,71,0,0,0,0,0,0,0,0,0,0
|
||||
2048548,Koltira's Chestguard of Triumph,358,85,4,5,4,4,4,179,7,319,12,124,14,114,13,108,0,0,0,0,0,0,0,0,0,0
|
||||
2047760,Khadgar's Leggings of Triumph,358,85,4,7,4,1,45,248,7,179,5,179,6,133,32,158,0,0,0,0,0,0,0,0,0,0
|
||||
2050082,Ymirjar Lord's Shoulderplates,351,85,4,3,4,4,4,176,7,189,32,110,44,97,0,0,0,0,0,0,0,0,0,0,0,0
|
||||
2048146,Runetotem's Robe of Triumph,358,85,4,20,4,2,45,248,7,179,5,179,6,145,32,145,0,0,0,0,0,0,0,0,0,0
|
||||
2048262,Windrunner's Headpiece of Triumph,358,85,4,1,4,3,38,266,3,212,7,187,5,124,32,158,44,99,0,0,0,0,0,0,0,0
|
||||
2048230,VanCleef's Helmet of Triumph,358,85,4,1,4,2,38,266,3,212,7,237,32,158,37,133,0,0,0,0,0,0,0,0,0,0
|
||||
2048357,Thrall's Grips of Triumph,358,85,4,10,4,3,38,327,3,117,7,139,5,93,37,105,32,93,0,0,0,0,0,0,0,0
|
||||
2050824,Lasherweave Shoulderpads,351,85,4,3,4,2,38,195,3,165,7,165,32,110,44,97,0,0,0,0,0,0,0,0,0,0
|
||||
2048086,Velen's Handwraps of Triumph,358,85,4,10,4,1,45,192,7,133,5,133,31,105,32,117,0,0,0,0,0,0,0,0,0,0
|
||||
2050823,Lasherweave Vestment,351,85,4,20,4,2,45,230,7,168,5,168,32,148,36,124,0,0,0,0,0,0,0,0,0,0
|
||||
2048037,Velen's Gloves of Triumph,358,85,4,10,4,1,45,192,7,133,5,133,6,105,36,117,0,0,0,0,0,0,0,0,0,0
|
||||
2048433,Wrynn's Greathelm of Triumph,358,85,4,1,4,4,4,237,7,300,12,111,13,99,0,0,0,0,0,0,0,0,0,0,0,0
|
||||
2050325,Lightsworn Legplates,351,85,4,7,4,4,4,229,7,254,32,148,37,124,0,0,0,0,0,0,0,0,0,0,0,0
|
||||
2048360,Thrall's Shoulderguards of Triumph,358,85,4,3,4,3,38,327,3,105,7,139,5,93,32,117,31,93,0,0,0,0,0,0,0,0
|
||||
2048294,Nobundo's Tunic of Triumph,358,85,4,5,4,3,45,248,7,179,5,179,36,145,32,145,0,0,0,0,0,0,0,0,0,0
|
||||
2050866,Lightsworn Greaves,351,85,4,7,4,4,45,230,7,168,5,168,32,148,43,62,0,0,0,0,0,0,0,0,0,0
|
||||
2051557,Runed Signet of the Kirin Tor,351,85,4,11,4,0,45,145,7,120,5,83,32,82,36,83,0,0,0,0,0,0,0,0,0,0
|
||||
2050393,Crimson Acolyte Pants,351,85,4,7,4,1,45,230,7,168,5,168,32,148,31,124,0,0,0,0,0,0,0,0,0,0
|
||||
2050118,Ahn'Kahar Blood Hunter's Tunic,351,85,4,5,4,3,38,246,3,223,7,175,5,117,32,136,44,105,0,0,0,0,0,0,0,0
|
||||
2050869,Lightsworn Tunic,351,85,4,5,4,4,45,230,7,168,5,168,32,148,36,124,0,0,0,0,0,0,0,0,0,0
|
||||
2048327,Thrall's Gloves of Triumph,358,85,4,10,4,3,45,192,7,133,5,133,36,105,31,117,0,0,0,0,0,0,0,0,0,0
|
||||
2047797,Gul'dan's Gloves of Triumph,358,85,4,10,4,1,45,192,7,133,5,133,32,117,31,105,0,0,0,0,0,0,0,0,0,0
|
||||
2048651,Liadrin's Breastplate of Triumph,358,85,4,5,4,4,4,237,7,319,12,124,14,111,13,111,0,0,0,0,0,0,0,0,0,0
|
||||
2048356,Thrall's Chestguard of Triumph,358,85,4,5,4,3,38,474,3,133,7,187,5,124,32,145,36,111,0,0,0,0,0,0,0,0
|
||||
2050079,Ymirjar Lord's Gauntlets,351,85,4,10,4,4,4,176,7,189,32,110,31,97,0,0,0,0,0,0,0,0,0,0,0,0
|
||||
2048397,Hellscream's Gauntlets of Triumph,358,85,4,10,4,4,4,189,7,201,32,117,31,105,0,0,0,0,0,0,0,0,0,0,0,0
|
||||
2050078,Ymirjar Lord's Battleplate,351,85,4,5,4,4,4,229,7,254,32,148,44,124,0,0,0,0,0,0,0,0,0,0,0,0
|
||||
2048549,Koltira's Handguards of Triumph,358,85,4,10,4,4,4,176,7,244,12,93,13,93,14,80,0,0,0,0,0,0,0,0,0,0
|
||||
2048168,Malfurion's Mantle of Triumph,358,85,4,3,4,2,45,192,7,133,5,133,6,117,32,105,0,0,0,0,0,0,0,0,0,0
|
||||
2048029,Velen's Shoulderpads of Triumph,358,85,4,3,4,1,45,192,7,133,5,133,6,117,32,105,0,0,0,0,0,0,0,0,0,0
|
||||
2051560,Runed Band of the Kirin Tor,351,85,4,11,4,0,38,165,3,124,7,124,32,85,36,79,0,0,0,0,0,0,0,0,0,0
|
||||
2047763,Sunstrider's Gauntlets of Triumph,358,85,4,10,4,1,45,192,7,133,5,133,32,117,36,105,0,0,0,0,0,0,0,0,0,0
|
||||
2050087,Shadowblade Breastplate,351,85,4,5,4,2,38,246,3,223,7,223,32,148,44,124,0,0,0,0,0,0,0,0,0,0
|
||||
2050828,Lasherweave Raiment,351,85,4,20,4,2,38,246,3,223,7,223,32,148,44,124,0,0,0,0,0,0,0,0,0,0
|
||||
2050394,Crimson Acolyte Raiments,351,85,4,20,4,1,45,230,7,168,5,168,32,136,36,136,0,0,0,0,0,0,0,0,0,0
|
||||
2048620,Liadrin's Legplates of Triumph,358,85,4,7,4,4,4,244,7,269,32,145,37,145,0,0,0,0,0,0,0,0,0,0,0,0
|
||||
2048618,Liadrin's Gauntlets of Triumph,358,85,4,10,4,4,4,189,7,201,32,117,31,105,0,0,0,0,0,0,0,0,0,0,0,0
|
||||
2048489,Thassarian's Gauntlets of Triumph,358,85,4,10,4,4,4,189,7,201,32,117,31,105,0,0,0,0,0,0,0,0,0,0,0,0
|
||||
2048204,Malfurion's Headguard of Triumph,358,85,4,1,4,2,38,266,3,212,7,237,32,158,37,133,0,0,0,0,0,0,0,0,0,0
|
||||
2047767,Sunstrider's Shoulderpads of Triumph,358,85,4,3,4,1,45,192,7,133,5,133,32,105,36,117,0,0,0,0,0,0,0,0,0,0
|
||||
2050820,Lasherweave Trousers,351,85,4,7,4,2,45,230,7,168,5,168,32,148,31,124,0,0,0,0,0,0,0,0,0,0
|
||||
2048330,Thrall's Shoulderpads of Triumph,358,85,4,3,4,3,45,192,7,133,5,133,36,117,32,105,0,0,0,0,0,0,0,0,0,0
|
||||
2048494,Koltira's Legplates of Triumph,358,85,4,7,4,4,4,244,7,269,32,145,44,145,0,0,0,0,0,0,0,0,0,0,0,0
|
||||
2048292,Nobundo's Headpiece of Triumph,358,85,4,1,4,3,45,234,7,179,5,179,32,136,43,71,0,0,0,0,0,0,0,0,0,0
|
||||
2048323,Nobundo's Helm of Triumph,358,85,4,1,4,3,45,234,7,179,5,179,32,142,36,148,0,0,0,0,0,0,0,0,0,0
|
||||
2048141,Malfurion's Headpiece of Triumph,358,85,4,1,4,2,45,234,7,179,5,179,6,133,32,145,0,0,0,0,0,0,0,0,0,0
|
||||
2050855,Scourgelord Faceguard,351,85,4,1,4,4,4,223,7,277,12,117,13,93,14,105,0,0,0,0,0,0,0,0,0,0
|
||||
2050109,Lasherweave Legplates,351,85,4,7,4,2,45,230,7,168,5,168,6,148,36,120,0,0,0,0,0,0,0,0,0,0
|
||||
2050088,Shadowblade Gauntlets,351,85,4,10,4,2,38,195,3,165,7,165,32,110,36,97,0,0,0,0,0,0,0,0,0,0
|
||||
2048200,Runetotem's Legguards of Triumph,358,85,4,7,4,2,38,266,3,212,7,237,32,158,31,133,0,0,0,0,0,0,0,0,0,0
|
||||
2050853,Scourgelord Pauldrons,351,85,4,3,4,4,4,165,7,229,12,86,13,74,14,86,0,0,0,0,0,0,0,0,0,0
|
||||
2048352,Nobundo's War-Kilt of Triumph,358,85,4,7,4,3,38,266,3,212,7,124,5,187,32,158,31,124,0,0,0,0,0,0,0,0
|
||||
2048451,Wrynn's Breastplate of Triumph,358,85,4,5,4,4,4,237,7,319,12,124,14,111,13,111,0,0,0,0,0,0,0,0,0,0
|
||||
2050080,Ymirjar Lord's Helmet,351,85,4,1,4,4,4,217,7,254,32,136,44,124,0,0,0,0,0,0,0,0,0,0,0,0
|
||||
2050865,Lightsworn Spaulders,351,85,4,3,4,4,45,179,7,125,5,125,32,110,36,97,0,0,0,0,0,0,0,0,0,0
|
||||
2048586,Liadrin's Greaves of Triumph,358,85,4,7,4,4,45,248,7,179,5,179,32,133,43,79,0,0,0,0,0,0,0,0,0,0
|
||||
2050846,Ymirjar Lord's Pauldrons,351,85,4,3,4,4,4,165,7,229,12,86,13,74,14,86,0,0,0,0,0,0,0,0,0,0
|
||||
2050106,Lasherweave Robes,351,85,4,20,4,2,45,230,7,168,5,168,6,148,32,124,0,0,0,0,0,0,0,0,0,0
|
||||
2048035,Velen's Cowl of Triumph,358,85,4,1,4,1,45,234,7,179,5,179,6,145,32,133,0,0,0,0,0,0,0,0,0,0
|
||||
2048453,Wrynn's Handguards of Triumph,358,85,4,10,4,4,4,176,7,244,12,93,13,80,14,93,0,0,0,0,0,0,0,0,0,0
|
||||
2048324,Nobundo's Gloves of Triumph,358,85,4,10,4,3,45,192,7,133,5,133,36,105,31,117,0,0,0,0,0,0,0,0,0,0
|
||||
2048145,Runetotem's Leggings of Triumph,358,85,4,7,4,2,45,248,7,179,5,179,6,145,36,145,0,0,0,0,0,0,0,0,0,0
|
||||
2050842,Frost Witch's Gloves,351,85,4,10,4,3,45,179,7,125,5,125,32,110,31,97,0,0,0,0,0,0,0,0,0,0
|
||||
2048544,Thassarian's Legguards of Triumph,358,85,4,7,4,4,4,179,7,319,12,114,14,108,13,124,0,0,0,0,0,0,0,0,0,0
|
||||
2048646,Turalyon's Shoulderguards of Triumph,358,85,4,3,4,4,4,133,7,244,12,117,13,117,37,77,0,0,0,0,0,0,0,0,0,0
|
||||
2048265,Windrunner's Tunic of Triumph,358,85,4,5,4,3,38,474,3,133,7,187,5,124,32,145,31,111,0,0,0,0,0,0,0,0
|
||||
2048487,Thassarian's Legplates of Triumph,358,85,4,7,4,4,4,244,7,269,32,145,44,145,0,0,0,0,0,0,0,0,0,0,0,0
|
||||
2048329,Thrall's Kilt of Triumph,358,85,4,7,4,3,45,248,7,179,5,179,32,133,31,158,0,0,0,0,0,0,0,0,0,0
|
||||
2047789,Kel'Thuzad's Hood of Triumph,358,85,4,1,4,1,45,234,7,179,5,179,6,133,32,145,0,0,0,0,0,0,0,0,0,0
|
||||
2047788,Kel'Thuzad's Gloves of Triumph,358,85,4,10,4,1,45,192,7,133,5,133,32,117,31,105,0,0,0,0,0,0,0,0,0,0
|
||||
2047794,Gul'dan's Robe of Triumph,358,85,4,20,4,1,45,248,7,179,5,179,6,145,31,145,0,0,0,0,0,0,0,0,0,0
|
||||
2048447,Wrynn's Legguards of Triumph,358,85,4,7,4,4,4,179,7,319,12,158,31,96,0,0,0,0,0,0,0,0,0,0,0,0
|
||||
2048290,Nobundo's Spaulders of Triumph,358,85,4,3,4,3,45,192,7,133,5,133,36,105,43,58,0,0,0,0,0,0,0,0,0,0
|
||||
2048139,Malfurion's Robe of Triumph,358,85,4,20,4,2,45,248,7,179,5,179,6,145,32,145,0,0,0,0,0,0,0,0,0,0
|
||||
2050843,Frost Witch's Helm,351,85,4,1,4,3,45,215,7,168,5,168,32,136,36,124,0,0,0,0,0,0,0,0,0,0
|
||||
2048547,Thassarian's Chestguard of Triumph,358,85,4,5,4,4,4,179,7,319,12,124,14,114,13,108,0,0,0,0,0,0,0,0,0,0
|
||||
2047766,Sunstrider's Robe of Triumph,358,85,4,20,4,1,45,248,7,179,5,179,6,158,31,133,0,0,0,0,0,0,0,0,0,0
|
||||
2050819,Lasherweave Mantle,351,85,4,3,4,2,45,179,7,125,5,125,32,110,36,97,0,0,0,0,0,0,0,0,0,0
|
||||
2050856,Scourgelord Handguards,351,85,4,10,4,4,4,125,7,229,12,110,31,83,0,0,0,0,0,0,0,0,0,0,0,0
|
||||
2048495,Koltira's Shoulderplates of Triumph,358,85,4,3,4,4,4,189,7,201,32,117,31,105,0,0,0,0,0,0,0,0,0,0,0,0
|
||||
2050090,Shadowblade Legplates,351,85,4,7,4,2,38,246,3,223,7,223,32,148,37,124,0,0,0,0,0,0,0,0,0,0
|
||||
2050324,Lightsworn Shoulderplates,351,85,4,3,4,4,4,176,7,189,32,110,36,97,0,0,0,0,0,0,0,0,0,0,0,0
|
||||
2048266,Windrunner's Handguards of Triumph,358,85,4,10,4,3,38,234,3,164,7,139,5,93,32,105,36,93,0,0,0,0,0,0,0,0
|
||||
2048236,Garona's Legplates of Triumph,358,85,4,7,4,2,38,291,3,212,7,237,31,133,44,145,0,0,0,0,0,0,0,0,0,0
|
||||
2048588,Liadrin's Gloves of Triumph,358,85,4,10,4,4,45,192,7,133,5,133,36,117,43,52,0,0,0,0,0,0,0,0,0,0
|
||||
2048400,Hellscream's Shoulderplates of Triumph,358,85,4,3,4,4,4,189,7,201,32,117,44,105,0,0,0,0,0,0,0,0,0,0,0,0
|
||||
2051559,Runed Ring of the Kirin Tor,351,85,4,11,4,0,4,124,7,184,32,83,37,82,0,0,0,0,0,0,0,0,0,0,0,0
|
||||
2050326,Lightsworn Helmet,351,85,4,1,4,4,4,217,7,254,32,136,36,124,0,0,0,0,0,0,0,0,0,0,0,0
|
||||
2048206,Malfurion's Raiments of Triumph,358,85,4,20,4,2,38,316,3,212,7,237,32,148,36,142,0,0,0,0,0,0,0,0,0,0
|
||||
2048176,Runetotem's Vestments of Triumph,358,85,4,20,4,2,45,248,7,179,5,179,36,158,32,133,0,0,0,0,0,0,0,0,0,0
|
||||
2048177,Runetotem's Mantle of Triumph,358,85,4,3,4,2,45,192,7,133,5,133,6,117,32,105,0,0,0,0,0,0,0,0,0,0
|
||||
2048269,Windrunner's Spaulders of Triumph,358,85,4,3,4,3,38,209,3,164,7,139,5,93,32,117,31,93,0,0,0,0,0,0,0,0
|
||||
2048617,Liadrin's Battleplate of Triumph,358,85,4,5,4,4,4,244,7,269,32,145,44,145,0,0,0,0,0,0,0,0,0,0,0,0
|
||||
2048649,Liadrin's Faceguard of Triumph,358,85,4,1,4,4,4,237,7,300,12,111,13,99,0,0,0,0,0,0,0,0,0,0,0,0
|
||||
2048090,Zabra's Raiments of Triumph,358,85,4,20,4,1,45,248,7,179,5,179,6,145,36,145,0,0,0,0,0,0,0,0,0,0
|
||||
2048057,Zabra's Gloves of Triumph,358,85,4,10,4,1,45,192,7,133,5,133,6,105,36,117,0,0,0,0,0,0,0,0,0,0
|
||||
2048307,Thrall's Headpiece of Triumph,358,85,4,1,4,3,45,234,7,179,5,179,32,136,43,71,0,0,0,0,0,0,0,0,0,0
|
||||
2048229,VanCleef's Legplates of Triumph,358,85,4,7,4,2,38,291,3,212,7,237,31,133,44,145,0,0,0,0,0,0,0,0,0,0
|
||||
2050863,Lightsworn Handguards,351,85,4,10,4,4,4,125,7,229,12,110,31,83,0,0,0,0,0,0,0,0,0,0,0,0
|
||||
2048147,Runetotem's Spaulders of Triumph,358,85,4,3,4,2,45,192,7,133,5,133,6,105,36,117,0,0,0,0,0,0,0,0,0,0
|
||||
2048488,Thassarian's Helmet of Triumph,358,85,4,1,4,4,4,232,7,269,32,145,37,133,0,0,0,0,0,0,0,0,0,0,0,0
|
||||
2050243,Dark Coven Robe,351,85,4,20,4,1,45,230,7,168,5,168,32,148,36,124,0,0,0,0,0,0,0,0,0,0
|
||||
2048616,Turalyon's Battleplate of Triumph,358,85,4,5,4,4,4,244,7,269,32,145,44,145,0,0,0,0,0,0,0,0,0,0,0,0
|
||||
2048268,Windrunner's Legguards of Triumph,358,85,4,7,4,3,38,266,3,212,7,124,5,187,32,158,44,124,0,0,0,0,0,0,0,0
|
||||
2048383,Wrynn's Helmet of Triumph,358,85,4,1,4,4,4,232,7,269,32,133,31,145,0,0,0,0,0,0,0,0,0,0,0,0
|
||||
2048144,Runetotem's Headpiece of Triumph,358,85,4,1,4,2,45,234,7,179,5,179,6,133,32,145,0,0,0,0,0,0,0,0,0,0
|
||||
2050822,Lasherweave Gloves,351,85,4,10,4,2,45,179,7,125,5,125,32,110,31,97,0,0,0,0,0,0,0,0,0,0
|
||||
2048091,Zabra's Mantle of Triumph,358,85,4,3,4,1,45,192,7,133,5,133,6,117,32,105,0,0,0,0,0,0,0,0,0,0
|
||||
2048470,Hellscream's Pauldrons of Triumph,358,85,4,3,4,4,4,133,7,244,12,117,13,117,37,77,0,0,0,0,0,0,0,0,0,0
|
||||
2048382,Wrynn's Legplates of Triumph,358,85,4,7,4,4,4,244,7,269,32,145,37,145,0,0,0,0,0,0,0,0,0,0,0,0
|
||||
2048059,Zabra's Leggings of Triumph,358,85,4,7,4,1,45,248,7,179,5,179,6,145,36,145,0,0,0,0,0,0,0,0,0,0
|
||||
2050108,Lasherweave Helmet,351,85,4,1,4,2,45,217,7,168,5,168,6,136,32,124,0,0,0,0,0,0,0,0,0,0
|
||||
2048140,Malfurion's Leggings of Triumph,358,85,4,7,4,2,45,248,7,179,5,179,6,145,36,145,0,0,0,0,0,0,0,0,0,0
|
||||
2048583,Turalyon's Gloves of Triumph,358,85,4,10,4,4,45,192,7,133,5,133,36,117,43,52,0,0,0,0,0,0,0,0,0,0
|
||||
2048351,Nobundo's Shoulderguards of Triumph,358,85,4,3,4,3,38,327,3,105,7,139,5,93,32,117,31,93,0,0,0,0,0,0,0,0
|
||||
2048031,Velen's Robe of Triumph,358,85,4,20,4,1,45,248,7,179,5,179,6,145,32,145,0,0,0,0,0,0,0,0,0,0
|
||||
2048308,Thrall's Legguards of Triumph,358,85,4,7,4,3,45,248,7,179,5,179,32,148,43,71,0,0,0,0,0,0,0,0,0,0
|
||||
2048169,Malfurion's Vestments of Triumph,358,85,4,20,4,2,45,248,7,179,5,179,36,158,32,133,0,0,0,0,0,0,0,0,0,0
|
||||
2050849,Ymirjar Lord's Handguards,351,85,4,10,4,4,4,125,7,229,12,110,31,83,0,0,0,0,0,0,0,0,0,0,0,0
|
||||
2048582,Turalyon's Headpiece of Triumph,358,85,4,1,4,4,45,234,7,179,5,179,32,133,36,145,0,0,0,0,0,0,0,0,0,0
|
||||
2048650,Liadrin's Handguards of Triumph,358,85,4,10,4,4,4,176,7,244,12,93,13,80,14,93,0,0,0,0,0,0,0,0,0,0
|
||||
2047759,Khadgar's Robe of Triumph,358,85,4,20,4,1,45,248,7,179,5,179,6,158,31,133,0,0,0,0,0,0,0,0,0,0
|
||||
2050847,Ymirjar Lord's Legguards,351,85,4,7,4,4,4,168,7,296,12,124,13,148,37,113,0,0,0,0,0,0,0,0,0,0
|
||||
2048171,Malfurion's Cover of Triumph,358,85,4,1,4,2,45,234,7,179,5,179,31,145,32,133,0,0,0,0,0,0,0,0,0,0
|
||||
2048354,Nobundo's Grips of Triumph,358,85,4,10,4,3,38,327,3,117,7,139,5,93,37,105,32,93,0,0,0,0,0,0,0,0
|
||||
2047765,Sunstrider's Leggings of Triumph,358,85,4,7,4,1,45,248,7,179,5,179,6,133,32,158,0,0,0,0,0,0,0,0,0,0
|
||||
2050116,Ahn'Kahar Blood Hunter's Legguards,351,85,4,7,4,3,38,246,3,223,7,175,5,117,32,136,36,105,0,0,0,0,0,0,0,0
|
||||
2048175,Runetotem's Trousers of Triumph,358,85,4,7,4,2,45,248,7,179,5,179,6,133,31,158,0,0,0,0,0,0,0,0,0,0
|
||||
2050868,Lightsworn Gloves,351,85,4,10,4,4,45,179,7,125,5,125,32,110,43,49,0,0,0,0,0,0,0,0,0,0
|
||||
2048199,Runetotem's Raiments of Triumph,358,85,4,20,4,2,38,316,3,212,7,237,32,148,36,142,0,0,0,0,0,0,0,0,0,0
|
||||
2048551,Koltira's Legguards of Triumph,358,85,4,7,4,4,4,179,7,319,12,114,14,108,13,124,0,0,0,0,0,0,0,0,0,0
|
||||
2048084,Velen's Pants of Triumph,358,85,4,7,4,1,45,248,7,179,5,179,36,133,31,158,0,0,0,0,0,0,0,0,0,0
|
||||
2050242,Dark Coven Leggings,351,85,4,7,4,1,45,230,7,168,5,168,32,148,31,124,0,0,0,0,0,0,0,0,0,0
|
||||
2050095,Scourgelord Gauntlets,351,85,4,10,4,4,4,176,7,189,32,110,31,97,0,0,0,0,0,0,0,0,0,0,0,0
|
||||
2048085,Velen's Circlet of Triumph,358,85,4,1,4,1,45,234,7,179,5,179,6,133,31,145,0,0,0,0,0,0,0,0,0,0
|
||||
2050396,Crimson Acolyte Mantle,351,85,4,3,4,1,45,179,7,125,5,125,32,110,36,97,0,0,0,0,0,0,0,0,0,0
|
||||
2050275,Bloodmage Gloves,351,85,4,10,4,1,45,179,7,125,5,125,32,110,31,97,0,0,0,0,0,0,0,0,0,0
|
||||
2048580,Turalyon's Spaulders of Triumph,358,85,4,3,4,4,45,192,7,133,5,133,32,117,36,105,0,0,0,0,0,0,0,0,0,0
|
||||
2050850,Ymirjar Lord's Breastplate,351,85,4,5,4,4,4,223,7,296,13,93,14,117,0,0,0,0,0,0,0,0,0,0,0,0
|
||||
2048058,Zabra's Cowl of Triumph,358,85,4,1,4,1,45,234,7,179,5,179,6,145,32,133,0,0,0,0,0,0,0,0,0,0
|
||||
2048061,Zabra's Shoulderpads of Triumph,358,85,4,3,4,1,45,192,7,133,5,133,6,117,32,105,0,0,0,0,0,0,0,0,0,0
|
||||
2048613,Turalyon's Legplates of Triumph,358,85,4,7,4,4,4,244,7,269,32,145,37,145,0,0,0,0,0,0,0,0,0,0,0,0
|
||||
2048647,Liadrin's Shoulderguards of Triumph,358,85,4,3,4,4,4,133,7,244,12,117,13,117,37,77,0,0,0,0,0,0,0,0,0,0
|
||||
2047795,Gul'dan's Leggings of Triumph,358,85,4,7,4,1,45,248,7,179,5,179,32,158,36,133,0,0,0,0,0,0,0,0,0,0
|
||||
2050327,Lightsworn Gauntlets,351,85,4,10,4,4,4,176,7,189,32,110,31,97,0,0,0,0,0,0,0,0,0,0,0,0
|
||||
2051558,Runed Loop of the Kirin Tor,351,85,4,11,4,0,45,145,7,120,5,83,6,83,43,41,0,0,0,0,0,0,0,0,0,0
|
||||
2050244,Dark Coven Shoulderpads,351,85,4,3,4,1,45,179,7,125,5,125,32,110,36,97,0,0,0,0,0,0,0,0,0,0
|
||||
2050766,Crimson Acolyte Gloves,351,85,4,10,4,1,45,179,7,125,5,125,6,110,36,97,0,0,0,0,0,0,0,0,0,0
|
||||
2048455,Wrynn's Pauldrons of Triumph,358,85,4,3,4,4,4,133,7,244,12,117,13,117,37,77,0,0,0,0,0,0,0,0,0,0
|
||||
2047790,Kel'Thuzad's Leggings of Triumph,358,85,4,7,4,1,45,248,7,179,5,179,32,158,36,133,0,0,0,0,0,0,0,0,0,0
|
||||
2048060,Zabra's Robe of Triumph,358,85,4,20,4,1,45,248,7,179,5,179,6,145,32,145,0,0,0,0,0,0,0,0,0,0
|
||||
2048381,Wrynn's Shoulderplates of Triumph,358,85,4,3,4,4,4,189,7,201,32,117,44,105,0,0,0,0,0,0,0,0,0,0,0,0
|
||||
2050848,Ymirjar Lord's Greathelm,351,85,4,1,4,4,4,223,7,277,12,117,13,93,14,105,0,0,0,0,0,0,0,0,0,0
|
||||
2050328,Lightsworn Battleplate,351,85,4,5,4,4,4,229,7,254,32,148,36,124,0,0,0,0,0,0,0,0,0,0,0,0
|
||||
2048082,Velen's Mantle of Triumph,358,85,4,3,4,1,45,192,7,133,5,133,6,117,32,105,0,0,0,0,0,0,0,0,0,0
|
||||
2048321,Nobundo's Shoulderpads of Triumph,358,85,4,3,4,3,45,192,7,133,5,133,36,117,32,105,0,0,0,0,0,0,0,0,0,0
|
||||
2048612,Turalyon's Shoulderplates of Triumph,358,85,4,3,4,4,4,189,7,201,32,117,31,105,0,0,0,0,0,0,0,0,0,0,0,0
|
||||
2048468,Hellscream's Greathelm of Triumph,358,85,4,1,4,4,4,237,7,300,12,111,13,99,0,0,0,0,0,0,0,0,0,0,0,0
|
||||
2048233,Garona's Breastplate of Triumph,358,85,4,5,4,2,38,291,3,212,7,237,32,158,31,145,0,0,0,0,0,0,0,0,0,0
|
||||
2048550,Koltira's Faceguard of Triumph,358,85,4,1,4,4,4,179,7,300,12,145,31,96,13,158,0,0,0,0,0,0,0,0,0,0
|
||||
2050854,Scourgelord Legguards,351,85,4,7,4,4,4,168,7,296,12,148,13,124,37,113,0,0,0,0,0,0,0,0,0,0
|
||||
2048322,Nobundo's Kilt of Triumph,358,85,4,7,4,3,45,248,7,179,5,179,32,133,31,158,0,0,0,0,0,0,0,0,0,0
|
||||
2048642,Turalyon's Breastplate of Triumph,358,85,4,5,4,4,4,237,7,319,12,124,14,111,13,111,0,0,0,0,0,0,0,0,0,0
|
||||
2048263,Windrunner's Handguards of Triumph,358,85,4,10,4,3,38,234,3,164,7,139,5,93,32,105,36,93,0,0,0,0,0,0,0,0
|
||||
2048305,Thrall's Tunic of Triumph,358,85,4,5,4,3,45,248,7,179,5,179,36,145,32,145,0,0,0,0,0,0,0,0,0,0
|
||||
2050391,Crimson Acolyte Handwraps,351,85,4,10,4,1,45,179,7,125,5,125,32,110,31,97,0,0,0,0,0,0,0,0,0,0
|
||||
2050827,Lasherweave Handgrips,351,85,4,10,4,2,38,195,3,165,7,165,44,110,36,97,0,0,0,0,0,0,0,0,0,0
|
||||
2048581,Turalyon's Greaves of Triumph,358,85,4,7,4,4,45,248,7,179,5,179,32,133,43,79,0,0,0,0,0,0,0,0,0,0
|
||||
2050089,Shadowblade Helmet,351,85,4,1,4,2,38,221,3,223,7,223,32,136,44,124,0,0,0,0,0,0,0,0,0,0
|
||||
2048491,Koltira's Battleplate of Triumph,358,85,4,5,4,4,4,244,7,269,32,145,36,145,0,0,0,0,0,0,0,0,0,0,0,0
|
||||
2050836,Frost Witch's Handguards,351,85,4,10,4,3,45,179,7,125,5,125,32,110,43,49,0,0,0,0,0,0,0,0,0,0
|
||||
2048621,Liadrin's Shoulderplates of Triumph,358,85,4,3,4,4,4,189,7,201,32,117,31,105,0,0,0,0,0,0,0,0,0,0,0,0
|
||||
2048398,Hellscream's Helmet of Triumph,358,85,4,1,4,4,4,232,7,269,32,133,31,145,0,0,0,0,0,0,0,0,0,0,0,0
|
||||
2048587,Liadrin's Headpiece of Triumph,358,85,4,1,4,4,45,234,7,179,5,179,32,133,36,145,0,0,0,0,0,0,0,0,0,0
|
||||
2048326,Thrall's Hauberk of Triumph,358,85,4,5,4,3,45,248,7,179,5,179,36,145,31,145,0,0,0,0,0,0,0,0,0,0
|
||||
2050107,Lasherweave Gauntlets,351,85,4,10,4,2,45,179,7,125,5,125,6,110,36,97,0,0,0,0,0,0,0,0,0,0
|
||||
2048399,Hellscream's Legplates of Triumph,358,85,4,7,4,4,4,244,7,269,32,145,37,145,0,0,0,0,0,0,0,0,0,0,0,0
|
||||
2048083,Velen's Raiments of Triumph,358,85,4,20,4,1,45,248,7,179,5,179,6,145,36,145,0,0,0,0,0,0,0,0,0,0
|
||||
2048325,Nobundo's Hauberk of Triumph,358,85,4,5,4,3,45,248,7,179,5,179,36,145,31,145,0,0,0,0,0,0,0,0,0,0
|
||||
2048203,Malfurion's Handgrips of Triumph,358,85,4,10,4,2,38,234,3,164,7,176,32,117,31,105,0,0,0,0,0,0,0,0,0,0
|
||||
2051577,Titan-Forged Shoulders of Triumph,351,85,4,3,4,3,38,195,3,110,7,189,5,83,31,97,35,110,0,0,0,0,0,0,0,0
|
||||
2048552,Koltira's Pauldrons of Triumph,358,85,4,3,4,4,4,133,7,244,12,117,14,117,31,77,0,0,0,0,0,0,0,0,0,0
|
||||
2050841,Frost Witch's Hauberk,351,85,4,5,4,3,45,230,7,168,5,168,32,148,36,124,0,0,0,0,0,0,0,0,0,0
|
||||
2048237,Garona's Pauldrons of Triumph,358,85,4,3,4,2,38,209,3,176,7,176,44,117,37,105,0,0,0,0,0,0,0,0,0,0
|
||||
2050278,Bloodmage Robe,351,85,4,20,4,1,45,230,7,168,5,168,32,124,36,148,0,0,0,0,0,0,0,0,0,0
|
||||
2048396,Hellscream's Battleplate of Triumph,358,85,4,5,4,4,4,244,7,269,32,145,44,145,0,0,0,0,0,0,0,0,0,0,0,0
|
||||
2050769,Crimson Acolyte Leggings,351,85,4,7,4,1,45,230,7,168,5,168,6,148,36,124,0,0,0,0,0,0,0,0,0,0
|
||||
2050839,Frost Witch's Spaulders,351,85,4,3,4,3,45,179,7,125,5,125,32,110,36,97,0,0,0,0,0,0,0,0,0,0
|
||||
2050767,Crimson Acolyte Shoulderpads,351,85,4,3,4,1,45,179,7,125,5,125,6,110,32,97,0,0,0,0,0,0,0,0,0,0
|
||||
2048235,Garona's Helmet of Triumph,358,85,4,1,4,2,38,266,3,212,7,237,32,158,37,133,0,0,0,0,0,0,0,0,0,0
|
||||
2048201,Runetotem's Headguard of Triumph,358,85,4,1,4,2,38,266,3,212,7,237,32,158,37,133,0,0,0,0,0,0,0,0,0,0
|
||||
2048546,Thassarian's Handguards of Triumph,358,85,4,10,4,4,4,176,7,244,12,93,13,93,14,80,0,0,0,0,0,0,0,0,0,0
|
||||
2050864,Lightsworn Chestguard,351,85,4,5,4,4,4,223,7,296,13,93,14,117,0,0,0,0,0,0,0,0,0,0,0,0
|
||||
2048234,Garona's Gauntlets of Triumph,358,85,4,10,4,2,38,209,3,176,7,176,32,117,31,105,0,0,0,0,0,0,0,0,0,0
|
||||
2048490,Thassarian's Battleplate of Triumph,358,85,4,5,4,4,4,244,7,269,32,145,36,145,0,0,0,0,0,0,0,0,0,0,0,0
|
||||
2050835,Frost Witch's Tunic,351,85,4,5,4,3,45,230,7,168,5,168,32,148,36,124,0,0,0,0,0,0,0,0,0,0
|
||||
2050831,Frost Witch's Grips,351,85,4,10,4,3,38,195,3,165,7,130,5,86,32,110,31,74,0,0,0,0,0,0,0,0
|
||||
2048138,Malfurion's Spaulders of Triumph,358,85,4,3,4,2,45,192,7,133,5,133,6,105,36,117,0,0,0,0,0,0,0,0,0,0
|
||||
2048385,Wrynn's Battleplate of Triumph,358,85,4,5,4,4,4,244,7,269,32,145,44,145,0,0,0,0,0,0,0,0,0,0,0,0
|
||||
2048545,Thassarian's Faceguard of Triumph,358,85,4,1,4,4,4,179,7,300,12,145,31,96,13,158,0,0,0,0,0,0,0,0,0,0
|
||||
2050096,Scourgelord Helmet,351,85,4,1,4,4,4,217,7,254,32,136,44,124,0,0,0,0,0,0,0,0,0,0,0,0
|
||||
2048643,Turalyon's Handguards of Triumph,358,85,4,10,4,4,4,176,7,244,12,93,13,80,14,93,0,0,0,0,0,0,0,0,0,0
|
||||
2048033,Velen's Leggings of Triumph,358,85,4,7,4,1,45,248,7,179,5,179,6,145,36,145,0,0,0,0,0,0,0,0,0,0
|
||||
2048198,Runetotem's Shoulderpads of Triumph,358,85,4,3,4,2,38,234,3,164,7,176,36,117,44,105,0,0,0,0,0,0,0,0,0,0
|
||||
2047762,Khadgar's Gauntlets of Triumph,358,85,4,10,4,1,45,192,7,133,5,133,32,117,36,105,0,0,0,0,0,0,0,0,0,0
|
||||
2050279,Bloodmage Shoulderpads,351,85,4,3,4,1,45,179,7,125,5,125,32,110,36,97,0,0,0,0,0,0,0,0,0,0
|
||||
2048645,Turalyon's Legguards of Triumph,358,85,4,7,4,4,4,179,7,319,12,158,31,96,0,0,0,0,0,0,0,0,0,0,0,0
|
||||
2050860,Lightsworn Shoulderguards,351,85,4,3,4,4,4,165,7,229,12,86,13,74,14,86,0,0,0,0,0,0,0,0,0,0
|
||||
2048202,Runetotem's Handgrips of Triumph,358,85,4,10,4,2,38,234,3,164,7,176,32,117,31,105,0,0,0,0,0,0,0,0,0,0
|
||||
2048328,Thrall's Helm of Triumph,358,85,4,1,4,3,45,234,7,179,5,179,32,142,36,148,0,0,0,0,0,0,0,0,0,0
|
||||
2048619,Liadrin's Helm of Triumph,358,85,4,1,4,4,4,232,7,269,32,145,36,133,0,0,0,0,0,0,0,0,0,0,0,0
|
||||
2050844,Frost Witch's Kilt,351,85,4,7,4,3,45,230,7,168,5,168,32,148,31,124,0,0,0,0,0,0,0,0,0,0
|
||||
2048492,Koltira's Gauntlets of Triumph,358,85,4,10,4,4,4,189,7,201,32,117,31,105,0,0,0,0,0,0,0,0,0,0,0,0
|
||||
2047758,Khadgar's Shoulderpads of Triumph,358,85,4,3,4,1,45,192,7,133,5,133,32,105,36,117,0,0,0,0,0,0,0,0,0,0
|
||||
2047796,Gul'dan's Hood of Triumph,358,85,4,1,4,1,45,234,7,179,5,179,6,133,32,145,0,0,0,0,0,0,0,0,0,0
|
||||
2050768,Crimson Acolyte Robe,351,85,4,20,4,1,45,230,7,168,5,168,6,136,32,136,0,0,0,0,0,0,0,0,0,0
|
||||
2050081,Ymirjar Lord's Legplates,351,85,4,7,4,4,4,229,7,252,32,148,37,124,0,0,0,0,0,0,0,0,0,0,0,0
|
||||
2050867,Lightsworn Headpiece,351,85,4,1,4,4,45,217,7,168,5,168,32,136,36,124,0,0,0,0,0,0,0,0,0,0
|
||||
2050862,Lightsworn Faceguard,351,85,4,1,4,4,4,223,7,277,12,117,13,93,14,105,0,0,0,0,0,0,0,0,0,0
|
||||
2048260,Windrunner's Spaulders of Triumph,358,85,4,3,4,3,38,209,3,164,7,139,5,93,32,117,31,93,0,0,0,0,0,0,0,0
|
||||
2048142,Malfurion's Handguards of Triumph,358,85,4,10,4,2,45,192,7,133,5,133,6,117,32,105,0,0,0,0,0,0,0,0,0,0
|
||||
2048170,Malfurion's Trousers of Triumph,358,85,4,7,4,2,45,248,7,179,5,179,6,133,31,158,0,0,0,0,0,0,0,0,0,0
|
||||
2047761,Khadgar's Hood of Triumph,358,85,4,1,4,1,45,234,7,179,5,179,36,145,31,133,0,0,0,0,0,0,0,0,0,0
|
||||
2047792,Kel'Thuzad's Shoulderpads of Triumph,358,85,4,3,4,1,45,192,7,133,5,133,6,105,32,117,0,0,0,0,0,0,0,0,0,0
|
||||
2050845,Frost Witch's Shoulderpads,351,85,4,3,4,3,45,179,7,125,5,125,32,110,36,97,0,0,0,0,0,0,0,0,0,0
|
||||
2048584,Turalyon's Tunic of Triumph,358,85,4,5,4,4,45,248,7,179,5,179,32,133,43,79,0,0,0,0,0,0,0,0,0,0
|
||||
2048644,Turalyon's Faceguard of Triumph,358,85,4,1,4,4,4,237,7,300,12,111,13,99,0,0,0,0,0,0,0,0,0,0,0,0
|
||||
2050392,Crimson Acolyte Cowl,351,85,4,1,4,1,45,215,7,168,5,168,32,148,36,111,0,0,0,0,0,0,0,0,0,0
|
||||
2050861,Lightsworn Legguards,351,85,4,7,4,4,4,168,7,296,12,148,13,124,37,113,0,0,0,0,0,0,0,0,0,0
|
||||
2048384,Wrynn's Gauntlets of Triumph,358,85,4,10,4,4,4,189,7,201,32,117,31,105,0,0,0,0,0,0,0,0,0,0,0,0
|
||||
2048355,Nobundo's Chestguard of Triumph,358,85,4,5,4,3,38,474,3,133,7,187,5,124,32,145,36,111,0,0,0,0,0,0,0,0
|
||||
2048648,Liadrin's Legguards of Triumph,358,85,4,7,4,4,4,179,7,319,12,158,31,96,0,0,0,0,0,0,0,0,0,0,0,0
|
||||
2050113,Lasherweave Pauldrons,351,85,4,3,4,2,45,179,7,125,5,125,6,110,32,97,0,0,0,0,0,0,0,0,0,0
|
||||
2050830,Frost Witch's Chestguard,351,85,4,5,4,3,38,246,3,223,7,175,5,117,32,136,36,105,0,0,0,0,0,0,0,0
|
||||
2050115,Ahn'Kahar Blood Hunter's Headpiece,351,85,4,1,4,3,38,246,3,210,7,175,5,117,32,124,44,105,0,0,0,0,0,0,0,0
|
||||
2048358,Thrall's Faceguard of Triumph,358,85,4,1,4,3,38,266,3,212,7,187,5,124,31,133,32,124,0,0,0,0,0,0,0,0
|
||||
2048207,Malfurion's Shoulderpads of Triumph,358,85,4,3,4,2,38,234,3,164,7,176,36,117,44,105,0,0,0,0,0,0,0,0,0,0
|
||||
2048615,Turalyon's Gauntlets of Triumph,358,85,4,10,4,4,4,189,7,201,32,117,31,105,0,0,0,0,0,0,0,0,0,0,0,0
|
||||
2048466,Hellscream's Breastplate of Triumph,358,85,4,5,4,4,4,237,7,319,12,124,14,111,13,111,0,0,0,0,0,0,0,0,0,0
|
||||
2048264,Windrunner's Tunic of Triumph,358,85,4,5,4,3,38,474,3,133,7,187,5,124,32,145,31,111,0,0,0,0,0,0,0,0
|
||||
2048089,Zabra's Pants of Triumph,358,85,4,7,4,1,45,248,7,179,5,179,36,133,31,158,0,0,0,0,0,0,0,0,0,0
|
||||
2048469,Hellscream's Legguards of Triumph,358,85,4,7,4,4,4,179,7,319,12,158,31,96,0,0,0,0,0,0,0,0,0,0,0,0
|
||||
2048353,Nobundo's Faceguard of Triumph,358,85,4,1,4,3,38,266,3,212,7,187,5,124,31,133,32,124,0,0,0,0,0,0,0,0
|
||||
2048306,Thrall's Handguards of Triumph,358,85,4,10,4,3,45,192,7,133,5,133,36,105,43,58,0,0,0,0,0,0,0,0,0,0
|
||||
2048173,Runetotem's Gloves of Triumph,358,85,4,10,4,2,45,192,7,133,5,133,6,105,36,117,0,0,0,0,0,0,0,0,0,0
|
||||
2048585,Liadrin's Spaulders of Triumph,358,85,4,3,4,4,45,192,7,133,5,133,32,117,36,105,0,0,0,0,0,0,0,0,0,0
|
||||
2050240,Dark Coven Gloves,351,85,4,10,4,1,45,179,7,125,5,125,32,110,31,97,0,0,0,0,0,0,0,0,0,0
|
||||
2050105,Shadowblade Pauldrons,351,85,4,3,4,2,38,195,3,165,7,165,32,110,31,97,0,0,0,0,0,0,0,0,0,0
|
||||
2050114,Ahn'Kahar Blood Hunter's Handguards,351,85,4,10,4,3,38,195,3,165,7,130,5,86,32,97,31,86,0,0,0,0,0,0,0,0
|
||||
2050277,Bloodmage Leggings,351,85,4,7,4,1,45,230,7,168,5,168,32,148,31,124,0,0,0,0,0,0,0,0,0,0
|
||||
2048261,Windrunner's Legguards of Triumph,358,85,4,7,4,3,38,266,3,212,7,124,5,187,32,158,44,124,0,0,0,0,0,0,0,0
|
||||
2048543,Thassarian's Pauldrons of Triumph,358,85,4,3,4,4,4,133,7,244,12,117,14,117,31,77,0,0,0,0,0,0,0,0,0,0
|
||||
2050098,Scourgelord Shoulderplates,351,85,4,3,4,4,4,176,7,189,32,110,44,97,0,0,0,0,0,0,0,0,0,0,0,0
|
||||
2048614,Turalyon's Helm of Triumph,358,85,4,1,4,4,4,232,7,269,32,145,36,133,0,0,0,0,0,0,0,0,0,0,0,0
|
||||
2050276,Bloodmage Hood,351,85,4,1,4,1,45,217,7,168,5,168,32,148,36,111,0,0,0,0,0,0,0,0,0,0
|
||||
2048589,Liadrin's Tunic of Triumph,358,85,4,5,4,4,45,248,7,179,5,179,32,133,43,79,0,0,0,0,0,0,0,0,0,0
|
||||
2047791,Kel'Thuzad's Robe of Triumph,358,85,4,20,4,1,45,248,7,179,5,179,6,145,31,145,0,0,0,0,0,0,0,0,0,0
|
||||
2048493,Koltira's Helmet of Triumph,358,85,4,1,4,4,4,232,7,269,32,145,37,133,0,0,0,0,0,0,0,0,0,0,0,0
|
||||
2048267,Windrunner's Headpiece of Triumph,358,85,4,1,4,3,38,266,3,212,7,187,5,124,32,158,44,99,0,0,0,0,0,0,0,0
|
||||
2048087,Zabra's Handwraps of Triumph,358,85,4,10,4,1,45,192,7,133,5,133,31,105,32,117,0,0,0,0,0,0,0,0,0,0
|
||||
2048088,Zabra's Circlet of Triumph,358,85,4,1,4,1,45,234,7,179,5,179,6,133,31,145,0,0,0,0,0,0,0,0,0,0
|
||||
2048359,Thrall's War-Kilt of Triumph,358,85,4,7,4,3,38,266,3,212,7,124,5,187,32,158,31,124,0,0,0,0,0,0,0,0
|
||||
2050117,Ahn'Kahar Blood Hunter's Spaulders,351,85,4,3,4,3,38,195,3,165,7,130,5,86,32,110,44,74,0,0,0,0,0,0,0,0
|
||||
2050838,Frost Witch's Legguards,351,85,4,7,4,3,45,230,7,168,5,168,32,148,43,62,0,0,0,0,0,0,0,0,0,0
|
||||
2050094,Scourgelord Battleplate,351,85,4,5,4,4,4,229,7,254,32,148,44,124,0,0,0,0,0,0,0,0,0,0,0,0
|
||||
2050826,Lasherweave Headguard,351,85,4,1,4,2,38,221,3,223,7,223,32,136,44,124,0,0,0,0,0,0,0,0,0,0
|
||||
2048143,Runetotem's Handguards of Triumph,358,85,4,10,4,2,45,192,7,133,5,133,6,117,32,105,0,0,0,0,0,0,0,0,0,0
|
||||
2050857,Scourgelord Chestguard,351,85,4,5,4,4,4,223,7,296,13,93,14,117,0,0,0,0,0,0,0,0,0,0,0,0
|
||||
2050834,Frost Witch's Shoulderguards,351,85,4,3,4,3,38,195,3,165,7,130,5,86,32,110,36,74,0,0,0,0,0,0,0,0
|
||||
2048293,Nobundo's Handguards of Triumph,358,85,4,10,4,3,45,192,7,133,5,133,36,105,43,58,0,0,0,0,0,0,0,0,0,0
|
||||
2050837,Frost Witch's Headpiece,351,85,4,1,4,3,45,215,7,168,5,168,32,136,36,124,0,0,0,0,0,0,0,0,0,0
|
||||
2048232,VanCleef's Breastplate of Triumph,358,85,4,5,4,2,38,291,3,212,7,237,32,158,31,145,0,0,0,0,0,0,0,0,0,0
|
||||
2048228,VanCleef's Pauldrons of Triumph,358,85,4,3,4,2,38,209,3,176,7,176,44,117,37,105,0,0,0,0,0,0,0,0,0,0
|
||||
2047793,Gul'dan's Shoulderpads of Triumph,358,85,4,3,4,1,45,192,7,133,5,133,6,105,32,117,0,0,0,0,0,0,0,0,0,0
|
||||
2048205,Malfurion's Legguards of Triumph,358,85,4,7,4,2,38,266,3,212,7,237,32,158,31,133,0,0,0,0,0,0,0,0,0,0
|
||||
2048309,Thrall's Spaulders of Triumph,358,85,4,3,4,3,45,192,7,133,5,133,36,105,43,58,0,0,0,0,0,0,0,0,0,0
|
||||
2048486,Thassarian's Shoulderplates of Triumph,358,85,4,3,4,4,4,189,7,201,32,117,31,105,0,0,0,0,0,0,0,0,0,0,0,0
|
||||
2047764,Sunstrider's Hood of Triumph,358,85,4,1,4,1,45,234,7,179,5,179,36,145,31,133,0,0,0,0,0,0,0,0,0,0
|
||||
2050097,Scourgelord Legplates,351,85,4,7,4,4,4,229,7,254,32,148,37,124,0,0,0,0,0,0,0,0,0,0,0,0
|
||||
2050833,Frost Witch's War-Kilt,351,85,4,7,4,3,38,246,3,223,7,175,5,117,32,136,31,105,0,0,0,0,0,0,0,0
|
||||
2048174,Runetotem's Cover of Triumph,358,85,4,1,4,2,45,234,7,179,5,179,31,145,32,133,0,0,0,0,0,0,0,0,0,0
|
||||
2050821,Lasherweave Cover,351,85,4,1,4,2,45,217,7,168,5,168,32,136,36,124,0,0,0,0,0,0,0,0,0,0
|
||||
2048467,Hellscream's Handguards of Triumph,358,85,4,10,4,4,4,176,7,244,12,93,13,80,14,93,0,0,0,0,0,0,0,0,0,0
|
||||
2048172,Malfurion's Gloves of Triumph,358,85,4,10,4,2,45,192,7,133,5,133,6,105,36,117,0,0,0,0,0,0,0,0,0,0
|
||||
2050241,Dark Coven Hood,351,85,4,1,4,1,45,217,7,168,5,168,32,136,36,124,0,0,0,0,0,0,0,0,0,0
|
||||
|
235
cmd/create_emblem_items/void-items.csv
Normal file
235
cmd/create_emblem_items/void-items.csv
Normal file
@@ -0,0 +1,235 @@
|
||||
entry,name,ItemLevel,RequiredLevel,Quality,InventoryType,class,subclass,stat_type1,stat_value1,stat_type2,stat_value2,stat_type3,stat_value3,stat_type4,stat_value4,stat_type5,stat_value5,stat_type6,stat_value6,stat_type7,stat_value7,stat_type8,stat_value8,stat_type9,stat_value9,stat_type10,stat_value10
|
||||
2046190,Conqueror's Shoulderpads of Sanctification,326,83,4,3,4,1,7,100,5,100,6,63,36,96,45,139,0,0,0,0,0,0,0,0,0,0
|
||||
2046188,Conqueror's Gloves of Sanctification,326,83,4,10,4,1,7,93,5,86,6,93,36,75,45,155,0,0,0,0,0,0,0,0,0,0
|
||||
2045363,Valorous Scourgestalker Spaulders,319,83,4,3,4,3,3,93,7,72,5,63,36,74,31,62,38,195,0,0,0,0,0,0,0,0
|
||||
2046133,Conqueror's Kirin Tor Leggings,326,83,4,7,4,1,7,117,5,127,32,114,31,102,45,190,0,0,0,0,0,0,0,0,0,0
|
||||
2045367,Valorous Kirin Tor Leggings,319,83,4,7,4,1,7,106,5,117,32,105,31,96,45,178,0,0,0,0,0,0,0,0,0,0
|
||||
2045833,Bladebreaker Gauntlets,326,83,4,10,4,4,4,134,7,192,32,93,44,75,0,0,0,0,0,0,0,0,0,0,0,0
|
||||
2045429,Valorous Siegebreaker Battleplate,319,83,4,5,4,4,4,162,7,186,32,83,44,105,0,0,0,0,0,0,0,0,0,0,0,0
|
||||
2045405,Valorous Worldbreaker Tunic,319,83,4,20,4,3,45,162,7,122,5,125,32,85,43,54,0,0,0,0,0,0,0,0,0,0
|
||||
2046199,Conqueror's Worldbreaker Handguards,326,83,4,10,4,3,45,139,7,97,5,99,32,74,36,88,0,0,0,0,0,0,0,0,0,0
|
||||
2046165,Conqueror's Mantle of Sanctification,326,83,4,3,4,1,7,82,5,100,32,96,6,75,45,139,0,0,0,0,0,0,0,0,0,0
|
||||
2046137,Conqueror's Deathbringer Robe,326,83,4,20,4,1,7,128,5,117,32,102,31,113,45,192,0,0,0,0,0,0,0,0,0,0
|
||||
2045411,Valorous Worldbreaker Hauberk,319,83,4,20,4,3,45,162,7,122,5,125,31,85,36,108,0,0,0,0,0,0,0,0,0,0
|
||||
2045839,Grips of the Secret Grove,326,83,4,10,4,2,45,155,7,113,5,93,6,93,32,75,0,0,0,0,0,0,0,0,0,0
|
||||
2045361,Valorous Scourgestalker Headpiece,319,83,4,1,4,3,3,117,7,116,5,69,44,71,32,86,38,279,0,0,0,0,0,0,0,0
|
||||
2046119,Conqueror's Darkruned Handguards,326,83,4,10,4,4,4,96,7,198,12,77,14,86,37,60,0,0,0,0,0,0,0,0,0,0
|
||||
2046146,Conqueror's Siegebreaker Battleplate,326,83,4,5,4,4,4,175,7,199,32,89,44,114,0,0,0,0,0,0,0,0,0,0,0,0
|
||||
2045422,Valorous Deathbringer Shoulderpads,319,83,4,3,4,1,7,97,5,88,36,58,32,82,45,142,0,0,0,0,0,0,0,0,0,0
|
||||
2046202,Conqueror's Worldbreaker Legguards,326,83,4,7,4,3,45,178,7,131,5,133,32,93,43,58,0,0,0,0,0,0,0,0,0,0
|
||||
2045393,Valorous Mantle of Sanctification,319,83,4,3,4,1,7,74,5,93,32,88,6,71,45,128,0,0,0,0,0,0,0,0,0,0
|
||||
2045404,Valorous Worldbreaker Spaulders,319,83,4,3,4,3,45,128,7,89,5,93,36,82,43,35,0,0,0,0,0,0,0,0,0,0
|
||||
2046126,Conqueror's Terrorblade Legplates,326,83,4,7,4,2,3,156,7,139,36,111,32,102,38,251,0,0,0,0,0,0,0,0,0,0
|
||||
2046158,Conqueror's Nightsong Handgrips,326,83,4,10,4,2,3,131,7,144,44,66,36,51,38,201,0,0,0,0,0,0,0,0,0,0
|
||||
2046143,Conqueror's Scourgestalker Headpiece,326,83,4,1,4,3,3,127,7,125,5,75,44,77,32,91,38,303,0,0,0,0,0,0,0,0
|
||||
2046189,Conqueror's Nightsong Gloves,326,83,4,10,4,2,45,139,7,97,5,99,6,74,31,88,0,0,0,0,0,0,0,0,0,0
|
||||
2046162,Conqueror's Siegebreaker Breastplate,326,83,4,5,4,4,4,175,7,227,12,79,14,93,0,0,0,0,0,0,0,0,0,0,0,0
|
||||
2045399,Valorous Terrorblade Legplates,319,83,4,7,4,2,3,145,7,128,36,102,32,96,38,235,0,0,0,0,0,0,0,0,0,0
|
||||
2045823,Frozen Tear of Elune,326,83,4,2,4,0,45,114,7,97,5,66,32,63,43,32,0,0,0,0,0,0,0,0,0,0
|
||||
2045353,Valorous Nightsong Trousers,319,83,4,7,4,2,45,162,7,122,5,125,32,110,31,83,0,0,0,0,0,0,0,0,0,0
|
||||
2045410,Valorous Worldbreaker Shoulderpads,319,83,4,3,4,3,45,128,7,89,5,93,32,82,36,69,0,0,0,0,0,0,0,0,0,0
|
||||
2045821,Shard of the Crystal Forest,326,83,4,2,4,0,4,65,7,145,12,63,13,66,31,65,0,0,0,0,0,0,0,0,0,0
|
||||
2045831,Sash of Potent Incantations,326,83,4,6,4,1,45,155,7,113,5,93,6,93,32,62,0,0,0,0,0,0,0,0,0,0
|
||||
2046191,Conqueror's Nightsong Cover,326,83,4,1,4,2,45,178,7,131,5,133,6,91,31,93,0,0,0,0,0,0,0,0,0,0
|
||||
2046205,Conqueror's Worldbreaker Chestguard,326,83,4,20,4,3,3,102,7,86,5,93,31,102,32,105,38,328,0,0,0,0,0,0,0,0
|
||||
2046129,Conqueror's Kirin Tor Hood,326,83,4,1,4,1,7,96,5,134,31,106,6,102,45,175,0,0,0,0,0,0,0,0,0,0
|
||||
2045336,Valorous Darkruned Faceguard,319,83,4,1,4,4,4,125,7,209,12,100,31,57,13,82,0,0,0,0,0,0,0,0,0,0
|
||||
2046132,Conqueror's Kirin Tor Gauntlets,326,83,4,10,4,1,7,86,5,96,31,93,36,72,45,155,0,0,0,0,0,0,0,0,0,0
|
||||
2046187,Conqueror's Nightsong Spaulders,326,83,4,3,4,2,45,139,7,97,5,99,6,88,36,74,0,0,0,0,0,0,0,0,0,0
|
||||
2045403,Valorous Worldbreaker Legguards,319,83,4,7,4,3,45,162,7,122,5,125,32,85,43,54,0,0,0,0,0,0,0,0,0,0
|
||||
2045337,Valorous Darkruned Handguards,319,83,4,10,4,4,4,88,7,184,12,72,14,80,37,55,0,0,0,0,0,0,0,0,0,0
|
||||
2045847,Wildstrider Legguards,326,83,4,7,4,2,45,178,7,131,5,133,6,105,32,103,0,0,0,0,0,0,0,0,0,0
|
||||
2045335,Valorous Darkruned Chestguard,319,83,4,5,4,4,4,139,7,209,12,93,14,75,13,85,0,0,0,0,0,0,0,0,0,0
|
||||
2046198,Conqueror's Worldbreaker Tunic,326,83,4,20,4,3,45,178,7,131,5,133,32,93,43,58,0,0,0,0,0,0,0,0,0,0
|
||||
2046209,Conqueror's Worldbreaker Helm,326,83,4,1,4,3,45,178,7,131,5,133,31,93,32,93,0,0,0,0,0,0,0,0,0,0
|
||||
2045409,Valorous Worldbreaker Kilt,319,83,4,7,4,3,45,162,7,122,5,125,32,110,31,85,0,0,0,0,0,0,0,0,0,0
|
||||
2045254,Sigil of the Vengeful Heart,326,83,4,28,4,10,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0
|
||||
2046164,Conqueror's Siegebreaker Handguards,326,83,4,10,4,4,4,93,7,178,12,74,13,88,31,75,0,0,0,0,0,0,0,0,0,0
|
||||
2045436,Libram of the Resolute,326,83,4,28,4,7,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0
|
||||
2046131,Valorous Kirin Tor Gauntlets,319,83,4,10,4,1,7,79,5,88,31,85,36,68,45,144,0,0,0,0,0,0,0,0,0,0
|
||||
2046179,Conqueror's Aegis Gloves,326,83,4,10,4,4,45,139,7,97,5,99,36,88,43,37,0,0,0,0,0,0,0,0,0,0
|
||||
2045356,Valorous Nightsong Headguard,319,83,4,1,4,2,3,114,7,176,32,108,44,71,38,220,0,0,0,0,0,0,0,0,0,0
|
||||
2046211,Conqueror's Worldbreaker Shoulderpads,326,83,4,3,4,3,45,139,7,97,5,99,32,88,36,74,0,0,0,0,0,0,0,0,0,0
|
||||
2046154,Conqueror's Aegis Battleplate,326,83,4,5,4,4,4,175,7,199,31,122,32,75,0,0,0,0,0,0,0,0,0,0,0,0
|
||||
2046196,Conqueror's Nightsong Mantle,326,83,4,3,4,2,45,139,7,97,5,99,6,75,32,86,0,0,0,0,0,0,0,0,0,0
|
||||
2046151,Conqueror's Siegebreaker Helmet,326,83,4,1,4,4,4,162,7,199,32,93,44,105,0,0,0,0,0,0,0,0,0,0,0,0
|
||||
2045255,Thunderfall Totem,326,83,4,28,4,9,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0
|
||||
2045381,Valorous Aegis Breastplate,319,83,4,5,4,4,4,164,7,209,12,85,13,74,14,74,0,0,0,0,0,0,0,0,0,0
|
||||
2045395,Valorous Raiments of Sanctification,319,83,4,20,4,1,7,125,5,110,36,83,31,105,45,192,0,0,0,0,0,0,0,0,0,0
|
||||
2046194,Conqueror's Nightsong Vestments,326,83,4,20,4,2,45,178,7,131,5,133,6,93,36,116,0,0,0,0,0,0,0,0,0,0
|
||||
2046170,Conqueror's Pants of Sanctification,326,83,4,7,4,1,7,153,5,127,6,80,36,117,45,175,0,0,0,0,0,0,0,0,0,0
|
||||
2045829,Belt of the Twilight Assassin,326,83,4,6,4,2,38,192,3,130,7,130,31,75,37,88,0,0,0,0,0,0,0,0,0,0
|
||||
2045169,Totem of the Dancing Flame,326,83,4,28,4,9,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0
|
||||
2046212,Conqueror's Worldbreaker Faceguard,326,83,4,1,4,3,3,83,7,114,5,93,32,113,36,83,38,316,0,0,0,0,0,0,0,0
|
||||
2045371,Valorous Aegis Greaves,319,83,4,7,4,4,45,162,7,122,5,125,36,83,43,54,0,0,0,0,0,0,0,0,0,0
|
||||
2045830,Belt of the Living Thicket,326,83,4,6,4,2,45,155,7,113,5,93,6,86,36,86,0,0,0,0,0,0,0,0,0,0
|
||||
2045357,Valorous Nightsong Legguards,319,83,4,7,4,2,3,164,7,176,32,100,36,71,38,164,0,0,0,0,0,0,0,0,0,0
|
||||
2048955,Etched Loop of the Kirin Tor,326,83,4,11,4,0,45,114,7,96,5,66,6,66,43,32,0,0,0,0,0,0,0,0,0,0
|
||||
2045345,Valorous Nightsong Handguards,319,83,4,10,4,2,45,128,7,89,5,93,6,82,32,68,0,0,0,0,0,0,0,0,0,0
|
||||
2046153,Conqueror's Aegis Legplates,326,83,4,7,4,4,4,175,7,199,31,89,32,114,0,0,0,0,0,0,0,0,0,0,0,0
|
||||
2045355,Valorous Nightsong Handgrips,319,83,4,10,4,2,3,122,7,133,44,62,36,46,38,186,0,0,0,0,0,0,0,0,0,0
|
||||
2045509,Idol of the Corruptor,326,83,4,28,4,8,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0
|
||||
2045380,Valorous Aegis Shoulderplates,319,83,4,3,4,4,4,128,7,139,32,80,36,63,0,0,0,0,0,0,0,0,0,0,0,0
|
||||
2045417,Valorous Deathbringer Hood,319,83,4,1,4,1,7,125,5,110,6,57,32,125,45,162,0,0,0,0,0,0,0,0,0,0
|
||||
2045341,Valorous Darkruned Gauntlets,319,83,4,10,4,4,4,128,7,139,32,60,31,80,0,0,0,0,0,0,0,0,0,0,0,0
|
||||
2045834,Gauntlets of the Royal Watch,326,83,4,10,4,4,4,93,7,196,12,85,13,86,31,75,0,0,0,0,0,0,0,0,0,0
|
||||
2046168,Conqueror's Raiments of Sanctification,326,83,4,20,4,1,7,139,5,117,36,89,31,114,45,204,0,0,0,0,0,0,0,0,0,0
|
||||
2045826,Girdle of Unyielding Trust,326,83,4,6,4,4,45,155,7,130,5,88,32,75,43,46,0,0,0,0,0,0,0,0,0,0
|
||||
2045384,Valorous Aegis Legguards,319,83,4,7,4,4,4,164,7,209,12,86,13,62,14,85,0,0,0,0,0,0,0,0,0,0
|
||||
2046155,Conqueror's Aegis Gauntlets,326,83,4,10,4,4,4,139,7,158,32,93,37,58,0,0,0,0,0,0,0,0,0,0,0,0
|
||||
2045352,Valorous Nightsong Mantle,319,83,4,3,4,2,45,128,7,89,5,93,6,69,32,80,0,0,0,0,0,0,0,0,0,0
|
||||
2045394,Valorous Pants of Sanctification,319,83,4,7,4,1,7,144,5,117,6,80,36,108,45,162,0,0,0,0,0,0,0,0,0,0
|
||||
2045382,Valorous Aegis Faceguard,319,83,4,1,4,4,4,139,7,209,12,86,13,85,15,62,0,0,0,0,0,0,0,0,0,0
|
||||
2045400,Valorous Terrorblade Pauldrons,319,83,4,3,4,2,3,122,7,106,32,55,31,80,38,176,0,0,0,0,0,0,0,0,0,0
|
||||
2046130,Conqueror's Kirin Tor Tunic,326,83,4,5,4,1,7,116,5,125,6,77,32,127,45,204,0,0,0,0,0,0,0,0,0,0
|
||||
2046135,Conqueror's Deathbringer Gloves,326,83,4,10,4,1,7,114,5,96,6,41,31,100,45,153,0,0,0,0,0,0,0,0,0,0
|
||||
2046192,Conqueror's Nightsong Trousers,326,83,4,7,4,2,45,178,7,131,5,133,32,117,31,91,0,0,0,0,0,0,0,0,0,0
|
||||
2045415,Valorous Worldbreaker Shoulderguards,319,83,4,3,4,3,3,88,7,97,5,74,32,71,37,48,38,195,0,0,0,0,0,0,0,0
|
||||
2045430,Valorous Siegebreaker Gauntlets,319,83,4,10,4,4,4,128,7,139,31,54,37,86,0,0,0,0,0,0,0,0,0,0,0,0
|
||||
2046169,Conqueror's Siegebreaker Legguards,326,83,4,7,4,4,4,175,7,227,12,79,13,80,0,0,0,0,0,0,0,0,0,0,0,0
|
||||
2045372,Valorous Aegis Headpiece,319,83,4,1,4,4,45,162,7,122,5,125,32,83,36,85,0,0,0,0,0,0,0,0,0,0
|
||||
2046172,Conqueror's Circlet of Sanctification,326,83,4,1,4,1,7,130,5,117,36,102,32,108,45,175,0,0,0,0,0,0,0,0,0,0
|
||||
2045145,Libram of the Sacred Shield,326,83,4,28,4,7,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0
|
||||
2045835,Gauntlets of Serene Blessing,326,83,4,10,4,4,45,155,7,111,5,93,36,86,43,43,0,0,0,0,0,0,0,0,0,0
|
||||
2045342,Valorous Darkruned Helmet,319,83,4,1,4,4,4,150,7,186,32,100,44,69,0,0,0,0,0,0,0,0,0,0,0,0
|
||||
2045340,Valorous Darkruned Battleplate,319,83,4,5,4,4,4,162,7,186,32,110,37,79,0,0,0,0,0,0,0,0,0,0,0,0
|
||||
2045840,Touch of the Occult,326,83,4,10,4,1,45,155,7,113,5,93,6,93,36,75,0,0,0,0,0,0,0,0,0,0
|
||||
2046152,Conqueror's Aegis Shoulderplates,326,83,4,3,4,4,4,139,7,158,32,86,36,69,0,0,0,0,0,0,0,0,0,0,0,0
|
||||
2045338,Valorous Darkruned Legguards,319,83,4,7,4,4,4,110,7,209,12,96,14,117,37,83,0,0,0,0,0,0,0,0,0,0
|
||||
2045379,Valorous Aegis Legplates,319,83,4,7,4,4,4,162,7,186,31,83,32,105,0,0,0,0,0,0,0,0,0,0,0,0
|
||||
2046160,Conqueror's Nightsong Legguards,326,83,4,7,4,2,3,176,7,189,32,108,36,77,38,176,0,0,0,0,0,0,0,0,0,0
|
||||
2046313,Valorous Nightsong Cover,319,83,4,1,4,2,45,162,7,122,5,125,6,83,31,85,0,0,0,0,0,0,0,0,0,0
|
||||
2045369,Valorous Kirin Tor Shoulderpads,319,83,4,3,4,1,7,93,5,93,6,46,36,88,45,141,0,0,0,0,0,0,0,0,0,0
|
||||
2045388,Valorous Leggings of Sanctification,319,83,4,7,4,1,7,106,5,117,6,83,36,102,45,192,0,0,0,0,0,0,0,0,0,0
|
||||
2045398,Valorous Terrorblade Helmet,319,83,4,1,4,2,3,155,7,96,32,110,36,82,38,186,0,0,0,0,0,0,0,0,0,0
|
||||
2045425,Valorous Siegebreaker Greathelm,319,83,4,1,4,4,4,139,7,209,12,86,13,74,15,72,0,0,0,0,0,0,0,0,0,0
|
||||
2046203,Conqueror's Worldbreaker Shoulderguards,326,83,4,3,4,3,3,96,7,102,5,80,32,75,37,52,38,213,0,0,0,0,0,0,0,0
|
||||
2046120,Conqueror's Darkruned Faceguard,326,83,4,1,4,4,4,133,7,227,12,108,31,63,13,88,0,0,0,0,0,0,0,0,0,0
|
||||
2045848,Legwraps of the Master Conjurer,326,83,4,7,4,1,45,178,7,153,5,125,6,105,32,103,0,0,0,0,0,0,0,0,0,0
|
||||
2045362,Valorous Scourgestalker Legguards,319,83,4,7,4,3,3,83,7,97,5,97,36,65,32,105,38,328,0,0,0,0,0,0,0,0
|
||||
2045421,Valorous Deathbringer Robe,319,83,4,20,4,1,7,119,5,110,32,96,31,105,45,178,0,0,0,0,0,0,0,0,0,0
|
||||
2046124,Conqueror's Terrorblade Gauntlets,326,83,4,10,4,2,3,131,7,91,32,66,31,83,38,201,0,0,0,0,0,0,0,0,0,0
|
||||
2046141,Conqueror's Scourgestalker Tunic,326,83,4,5,4,3,3,133,7,100,5,93,32,91,31,88,38,300,0,0,0,0,0,0,0,0
|
||||
2046140,Conqueror's Deathbringer Hood,326,83,4,1,4,1,7,137,5,117,6,63,32,133,45,175,0,0,0,0,0,0,0,0,0,0
|
||||
2045837,Gloves of Augury,326,83,4,10,4,3,45,155,7,130,5,86,32,93,43,38,0,0,0,0,0,0,0,0,0,0
|
||||
2045825,Shieldwarder Girdle,326,83,4,6,4,4,4,88,7,196,12,75,13,93,31,86,0,0,0,0,0,0,0,0,0,0
|
||||
2045376,Valorous Aegis Gauntlets,319,83,4,10,4,4,4,128,7,139,32,86,37,54,0,0,0,0,0,0,0,0,0,0,0,0
|
||||
2045842,Wyrmguard Legplates,326,83,4,7,4,4,4,175,7,227,12,91,15,93,0,0,0,0,0,0,0,0,0,0,0,0
|
||||
2045144,Sigil of Deflection,326,83,4,28,4,10,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0
|
||||
2045368,Valorous Kirin Tor Tunic,319,83,4,5,4,1,7,106,5,117,6,71,32,117,45,192,0,0,0,0,0,0,0,0,0,0
|
||||
2045390,Valorous Shoulderpads of Sanctification,319,83,4,3,4,1,7,93,5,93,6,57,36,86,45,128,0,0,0,0,0,0,0,0,0,0
|
||||
2045339,Valorous Darkruned Pauldrons,319,83,4,3,4,4,4,96,7,184,12,63,14,55,13,69,0,0,0,0,0,0,0,0,0,0
|
||||
2045836,Gloves of Unerring Aim,326,83,4,10,4,3,38,263,3,88,7,102,5,68,32,68,36,86,0,0,0,0,0,0,0,0
|
||||
2046197,Conqueror's Cowl of Sanctification,326,83,4,1,4,1,7,120,5,116,6,117,32,103,45,178,0,0,0,0,0,0,0,0,0,0
|
||||
2045416,Valorous Worldbreaker War-Kilt,319,83,4,7,4,3,3,96,7,110,5,74,36,117,31,86,38,279,0,0,0,0,0,0,0,0
|
||||
2045359,Valorous Nightsong Shoulderpads,319,83,4,3,4,2,3,110,7,103,32,86,38,161,37,68,0,0,0,0,0,0,0,0,0,0
|
||||
2046186,Conqueror's Nightsong Robe,326,83,4,20,4,2,45,178,7,131,5,133,6,105,32,103,0,0,0,0,0,0,0,0,0,0
|
||||
2046139,Conqueror's Deathbringer Leggings,326,83,4,7,4,1,7,133,5,133,6,75,36,102,45,204,0,0,0,0,0,0,0,0,0,0
|
||||
2045401,Valorous Worldbreaker Handguards,319,83,4,10,4,3,45,128,7,89,5,93,32,69,36,80,0,0,0,0,0,0,0,0,0,0
|
||||
2045365,Valorous Kirin Tor Hood,319,83,4,1,4,1,7,86,5,125,31,99,6,94,45,162,0,0,0,0,0,0,0,0,0,0
|
||||
2045344,Valorous Darkruned Shoulderplates,319,83,4,3,4,4,4,128,7,139,36,80,31,63,0,0,0,0,0,0,0,0,0,0,0,0
|
||||
2045402,Valorous Worldbreaker Headpiece,319,83,4,1,4,3,45,162,7,122,5,125,32,85,36,83,0,0,0,0,0,0,0,0,0,0
|
||||
2046115,Conqueror's Darkruned Helmet,326,83,4,1,4,4,4,162,7,199,32,110,44,75,0,0,0,0,0,0,0,0,0,0,0,0
|
||||
2045389,Valorous Robe of Sanctification,319,83,4,20,4,1,7,124,5,125,6,117,32,71,45,162,0,0,0,0,0,0,0,0,0,0
|
||||
2045348,Valorous Nightsong Robe,319,83,4,20,4,2,45,162,7,122,5,125,6,97,32,96,0,0,0,0,0,0,0,0,0,0
|
||||
2045838,Gloves of the Blind Stalker,326,83,4,10,4,2,38,186,3,131,7,130,32,75,36,88,0,0,0,0,0,0,0,0,0,0
|
||||
2045377,Valorous Aegis Helm,319,83,4,1,4,4,4,150,7,186,36,83,32,93,0,0,0,0,0,0,0,0,0,0,0,0
|
||||
2045270,Idol of the Crying Wind,326,83,4,28,4,8,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0
|
||||
2046150,Conqueror's Siegebreaker Legplates,326,83,4,7,4,4,4,175,7,199,31,114,37,89,0,0,0,0,0,0,0,0,0,0,0,0
|
||||
2045431,Valorous Siegebreaker Helmet,319,83,4,1,4,4,4,150,7,186,32,85,44,96,0,0,0,0,0,0,0,0,0,0,0,0
|
||||
2046182,Conqueror's Aegis Spaulders,326,83,4,3,4,4,45,139,7,97,5,99,32,74,36,88,0,0,0,0,0,0,0,0,0,0
|
||||
2045426,Valorous Siegebreaker Handguards,319,83,4,10,4,4,4,86,7,164,12,68,13,82,31,69,0,0,0,0,0,0,0,0,0,0
|
||||
2046207,Conqueror's Worldbreaker Gloves,326,83,4,10,4,3,45,139,7,97,5,99,32,74,36,88,0,0,0,0,0,0,0,0,0,0
|
||||
2045408,Valorous Worldbreaker Helm,319,83,4,1,4,3,45,162,7,122,5,125,31,85,32,85,0,0,0,0,0,0,0,0,0,0
|
||||
2046136,Conqueror's Deathbringer Shoulderpads,326,83,4,3,4,1,7,105,5,96,36,63,32,89,45,153,0,0,0,0,0,0,0,0,0,0
|
||||
2046122,Conqueror's Darkruned Pauldrons,326,83,4,3,4,4,4,106,7,198,12,68,14,58,13,74,0,0,0,0,0,0,0,0,0,0
|
||||
2045428,Valorous Siegebreaker Pauldrons,319,83,4,3,4,4,4,86,7,164,12,68,13,82,37,69,0,0,0,0,0,0,0,0,0,0
|
||||
2045386,Valorous Cowl of Sanctification,319,83,4,1,4,1,7,110,5,108,6,110,32,96,45,162,0,0,0,0,0,0,0,0,0,0
|
||||
2048957,Etched Signet of the Kirin Tor,326,83,4,11,4,0,45,114,7,96,5,66,32,63,36,66,0,0,0,0,0,0,0,0,0,0
|
||||
2046174,Conqueror's Aegis Handguards,326,83,4,10,4,4,4,130,7,178,12,69,14,55,0,0,0,0,0,0,0,0,0,0,0,0
|
||||
2046148,Conqueror's Siegebreaker Gauntlets,326,83,4,10,4,4,4,139,7,158,31,58,37,93,0,0,0,0,0,0,0,0,0,0,0,0
|
||||
2045820,Broach of the Wailing Night,326,83,4,2,4,0,38,130,3,97,7,106,32,55,44,71,0,0,0,0,0,0,0,0,0,0
|
||||
2045396,Valorous Terrorblade Breastplate,319,83,4,5,4,2,3,139,7,125,32,96,37,110,38,235,0,0,0,0,0,0,0,0,0,0
|
||||
2046166,Conqueror's Siegebreaker Greathelm,326,83,4,1,4,4,4,150,7,227,12,91,13,79,15,79,0,0,0,0,0,0,0,0,0,0
|
||||
2045827,Belt of the Ardent Marksman,326,83,4,6,4,3,38,186,3,131,7,103,5,68,36,75,31,68,0,0,0,0,0,0,0,0
|
||||
2046167,Conqueror's Siegebreaker Pauldrons,326,83,4,3,4,4,4,93,7,178,12,74,13,88,37,75,0,0,0,0,0,0,0,0,0,0
|
||||
2045358,Valorous Nightsong Raiments,319,83,4,20,4,2,3,139,7,170,31,69,32,96,38,235,0,0,0,0,0,0,0,0,0,0
|
||||
2046134,Conqueror's Kirin Tor Shoulderpads,326,83,4,3,4,1,7,100,5,100,6,51,36,96,45,151,0,0,0,0,0,0,0,0,0,0
|
||||
2045397,Valorous Terrorblade Gauntlets,319,83,4,10,4,2,3,122,7,82,32,62,31,77,38,186,0,0,0,0,0,0,0,0,0,0
|
||||
2046180,Conqueror's Aegis Headpiece,326,83,4,1,4,4,45,178,7,131,5,133,32,91,36,93,0,0,0,0,0,0,0,0,0,0
|
||||
2045427,Valorous Siegebreaker Legguards,319,83,4,7,4,4,4,164,7,209,12,72,13,74,0,0,0,0,0,0,0,0,0,0,0,0
|
||||
2045846,Leggings of Wavering Shadow,326,83,4,7,4,2,38,210,3,151,7,173,36,116,31,105,0,0,0,0,0,0,0,0,0,0
|
||||
2046201,Conqueror's Worldbreaker Headpiece,326,83,4,1,4,3,45,178,7,131,5,133,32,93,36,91,0,0,0,0,0,0,0,0,0,0
|
||||
2048956,Etched Ring of the Kirin Tor,326,83,4,11,4,0,4,97,7,145,32,66,37,63,0,0,0,0,0,0,0,0,0,0,0,0
|
||||
2046163,Conqueror's Handwraps of Sanctification,326,83,4,10,4,1,7,96,5,68,32,99,6,83,45,153,0,0,0,0,0,0,0,0,0,0
|
||||
2045828,Windchill Binding,326,83,4,6,4,3,45,155,7,130,5,86,36,93,43,38,0,0,0,0,0,0,0,0,0,0
|
||||
2045824,Belt of the Singing Blade,326,83,4,6,4,4,4,134,7,192,32,93,31,75,0,0,0,0,0,0,0,0,0,0,0,0
|
||||
2045822,Evoker's Charm,326,83,4,2,4,0,45,114,7,97,5,66,6,63,36,65,0,0,0,0,0,0,0,0,0,0
|
||||
2045819,Spiked Battleguard Choker,326,83,4,2,4,0,4,100,7,144,32,55,31,69,0,0,0,0,0,0,0,0,0,0,0,0
|
||||
2045414,Valorous Worldbreaker Grips,319,83,4,10,4,3,3,82,7,72,5,63,37,55,36,74,38,244,0,0,0,0,0,0,0,0
|
||||
2045364,Valorous Scourgestalker Tunic,319,83,4,5,4,3,3,125,7,93,5,85,32,86,31,82,38,279,0,0,0,0,0,0,0,0
|
||||
2045419,Valorous Deathbringer Gloves,319,83,4,10,4,1,7,106,5,88,6,38,31,91,45,142,0,0,0,0,0,0,0,0,0,0
|
||||
2045114,Steamcaller's Totem,326,83,4,28,4,9,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0
|
||||
2045420,Valorous Deathbringer Leggings,319,83,4,7,4,1,7,124,5,125,6,68,36,96,45,192,0,0,0,0,0,0,0,0,0,0
|
||||
2046181,Conqueror's Aegis Greaves,326,83,4,7,4,4,45,178,7,131,5,133,36,116,43,58,0,0,0,0,0,0,0,0,0,0
|
||||
2045392,Valorous Handwraps of Sanctification,319,83,4,10,4,1,7,88,5,63,32,91,6,75,45,142,0,0,0,0,0,0,0,0,0,0
|
||||
2046173,Conqueror's Aegis Breastplate,326,83,4,5,4,4,4,175,7,227,12,93,13,79,14,79,0,0,0,0,0,0,0,0,0,0
|
||||
2045354,Valorous Nightsong Vestments,319,83,4,20,4,2,45,162,7,122,5,125,6,85,36,108,0,0,0,0,0,0,0,0,0,0
|
||||
2046111,Conqueror's Darkruned Battleplate,326,83,4,5,4,4,4,175,7,199,32,119,37,85,0,0,0,0,0,0,0,0,0,0,0,0
|
||||
2045413,Valorous Worldbreaker Chestguard,319,83,4,20,4,3,3,96,7,79,5,86,31,93,32,99,38,303,0,0,0,0,0,0,0,0
|
||||
2045843,Legguards of the Peaceful Covenant,326,83,4,7,4,4,45,178,7,173,5,117,36,89,43,55,0,0,0,0,0,0,0,0,0,0
|
||||
2046159,Conqueror's Nightsong Raiments,326,83,4,20,4,2,3,150,7,184,31,75,32,102,38,251,0,0,0,0,0,0,0,0,0,0
|
||||
2045346,Valorous Nightsong Headpiece,319,83,4,1,4,2,45,162,7,122,5,125,6,85,36,83,0,0,0,0,0,0,0,0,0,0
|
||||
2045374,Valorous Aegis Tunic,319,83,4,5,4,4,45,162,7,122,5,125,32,83,43,54,0,0,0,0,0,0,0,0,0,0
|
||||
2046200,Conqueror's Worldbreaker Grips,326,83,4,10,4,3,3,88,7,79,5,69,37,62,36,80,38,263,0,0,0,0,0,0,0,0
|
||||
2046123,Conqueror's Terrorblade Breastplate,326,83,4,5,4,2,3,150,7,139,32,102,37,117,38,251,0,0,0,0,0,0,0,0,0,0
|
||||
2045351,Valorous Nightsong Gloves,319,83,4,10,4,2,45,128,7,89,5,93,6,69,31,80,0,0,0,0,0,0,0,0,0,0
|
||||
2045845,Leggings of the Weary Mystic,326,83,4,7,4,3,45,178,7,176,5,116,36,93,43,58,0,0,0,0,0,0,0,0,0,0
|
||||
2046156,Conqueror's Aegis Helm,326,83,4,1,4,4,4,162,7,199,36,89,32,102,0,0,0,0,0,0,0,0,0,0,0,0
|
||||
2046178,Conqueror's Aegis Tunic,326,83,4,5,4,4,45,178,7,131,5,133,32,93,43,58,0,0,0,0,0,0,0,0,0,0
|
||||
2045510,Libram of Discord,326,83,4,28,4,7,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0
|
||||
2046161,Conqueror's Nightsong Headguard,326,83,4,1,4,2,3,127,7,189,32,116,44,77,38,235,0,0,0,0,0,0,0,0,0,0
|
||||
2046185,Conqueror's Nightsong Leggings,326,83,4,7,4,2,45,178,7,131,5,133,6,117,32,91,0,0,0,0,0,0,0,0,0,0
|
||||
2045383,Valorous Aegis Handguards,319,83,4,10,4,4,4,120,7,164,12,63,14,49,0,0,0,0,0,0,0,0,0,0,0,0
|
||||
2045844,Leggings of the Tireless Sentry,326,83,4,7,4,3,38,303,3,93,7,139,5,91,32,116,31,91,0,0,0,0,0,0,0,0
|
||||
2045391,Valorous Circlet of Sanctification,319,83,4,1,4,1,7,120,5,108,36,93,32,100,45,162,0,0,0,0,0,0,0,0,0,0
|
||||
2046127,Conqueror's Terrorblade Pauldrons,326,83,4,3,4,2,3,131,7,114,32,62,31,86,38,192,0,0,0,0,0,0,0,0,0,0
|
||||
2046144,Conqueror's Scourgestalker Legguards,326,83,4,7,4,3,3,89,7,102,5,105,36,69,32,113,38,353,0,0,0,0,0,0,0,0
|
||||
2045424,Valorous Siegebreaker Breastplate,319,83,4,5,4,4,4,164,7,209,12,72,14,86,0,0,0,0,0,0,0,0,0,0,0,0
|
||||
2045387,Valorous Gloves of Sanctification,319,83,4,10,4,1,7,83,5,82,6,88,36,71,45,144,0,0,0,0,0,0,0,0,0,0
|
||||
2046183,Conqueror's Nightsong Handguards,326,83,4,10,4,2,45,139,7,97,5,99,6,88,32,74,0,0,0,0,0,0,0,0,0,0
|
||||
2046204,Conqueror's Worldbreaker Spaulders,326,83,4,3,4,3,45,139,7,97,5,99,36,88,43,37,0,0,0,0,0,0,0,0,0,0
|
||||
2046184,Conqueror's Nightsong Headpiece,326,83,4,1,4,2,45,178,7,131,5,133,6,93,36,91,0,0,0,0,0,0,0,0,0,0
|
||||
2048954,Etched Band of the Kirin Tor,326,83,4,11,4,0,38,195,3,63,7,99,32,66,36,63,0,0,0,0,0,0,0,0,0,0
|
||||
2046195,Conqueror's Leggings of Sanctification,326,83,4,7,4,1,7,116,5,127,6,93,36,111,45,204,0,0,0,0,0,0,0,0,0,0
|
||||
2046125,Conqueror's Terrorblade Helmet,326,83,4,1,4,2,3,165,7,116,32,119,36,91,38,201,0,0,0,0,0,0,0,0,0,0
|
||||
2045349,Valorous Nightsong Spaulders,319,83,4,3,4,2,45,127,7,89,5,93,6,82,36,68,0,0,0,0,0,0,0,0,0,0
|
||||
2046142,Conqueror's Scourgestalker Handguards,326,83,4,10,4,3,3,75,7,102,5,68,36,68,31,66,38,263,0,0,0,0,0,0,0,0
|
||||
2046149,Conqueror's Siegebreaker Shoulderplates,326,83,4,3,4,4,4,139,7,158,32,83,31,71,0,0,0,0,0,0,0,0,0,0,0,0
|
||||
2045433,Valorous Siegebreaker Shoulderplates,319,83,4,3,4,4,4,128,7,139,32,77,31,66,0,0,0,0,0,0,0,0,0,0,0,0
|
||||
2045841,Legplates of the Violet Champion,326,83,4,7,4,4,4,178,7,201,32,105,36,103,0,0,0,0,0,0,0,0,0,0,0,0
|
||||
2046116,Conqueror's Darkruned Legplates,326,83,4,7,4,4,4,175,7,199,32,108,36,102,0,0,0,0,0,0,0,0,0,0,0,0
|
||||
2045343,Valorous Darkruned Legplates,319,83,4,7,4,4,4,162,7,186,32,100,36,93,0,0,0,0,0,0,0,0,0,0,0,0
|
||||
2046157,Conqueror's Nightsong Shoulderpads,326,83,4,3,4,2,3,119,7,114,32,96,38,173,37,74,0,0,0,0,0,0,0,0,0,0
|
||||
2045432,Valorous Siegebreaker Legplates,319,83,4,7,4,4,4,162,7,186,31,105,37,86,0,0,0,0,0,0,0,0,0,0,0,0
|
||||
2046177,Conqueror's Aegis Shoulderguards,326,83,4,3,4,4,4,130,7,178,12,68,15,57,0,0,0,0,0,0,0,0,0,0,0,0
|
||||
2045385,Valorous Aegis Shoulderguards,319,83,4,3,4,4,4,120,7,164,12,63,15,52,0,0,0,0,0,0,0,0,0,0,0,0
|
||||
2046145,Conqueror's Scourgestalker Spaulders,326,83,4,3,4,3,3,100,7,77,5,68,36,79,31,66,38,213,0,0,0,0,0,0,0,0
|
||||
2046117,Conqueror's Darkruned Shoulderplates,326,83,4,3,4,4,4,139,7,158,36,86,31,63,0,0,0,0,0,0,0,0,0,0,0,0
|
||||
2046113,Conqueror's Darkruned Gauntlets,326,83,4,10,4,4,4,139,7,158,32,65,31,86,0,0,0,0,0,0,0,0,0,0,0,0
|
||||
2045406,Valorous Worldbreaker Gloves,319,83,4,10,4,3,45,128,7,89,5,93,32,69,36,80,0,0,0,0,0,0,0,0,0,0
|
||||
2046210,Conqueror's Worldbreaker Kilt,326,83,4,7,4,3,45,178,7,131,5,133,32,117,31,93,0,0,0,0,0,0,0,0,0,0
|
||||
2045375,Valorous Aegis Battleplate,319,83,4,5,4,4,4,162,7,186,31,113,32,69,0,0,0,0,0,0,0,0,0,0,0,0
|
||||
2045373,Valorous Aegis Spaulders,319,83,4,3,4,4,45,128,7,89,5,93,32,69,36,80,0,0,0,0,0,0,0,0,0,0
|
||||
2045347,Valorous Nightsong Leggings,319,83,4,7,4,2,45,162,7,122,5,125,6,110,32,83,0,0,0,0,0,0,0,0,0,0
|
||||
2046138,Idol of the Flourishing Life,326,83,4,28,4,8,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0
|
||||
2046176,Conqueror's Aegis Legguards,326,83,4,7,4,4,4,175,7,227,12,91,13,66,14,93,0,0,0,0,0,0,0,0,0,0
|
||||
2046175,Conqueror's Aegis Faceguard,326,83,4,1,4,4,4,150,7,227,12,93,13,91,15,66,0,0,0,0,0,0,0,0,0,0
|
||||
2046193,Conqueror's Robe of Sanctification,326,83,4,20,4,1,7,133,5,133,6,125,32,77,45,178,0,0,0,0,0,0,0,0,0,0
|
||||
2045370,Valorous Aegis Gloves,319,83,4,10,4,4,45,128,7,89,5,93,36,82,43,35,0,0,0,0,0,0,0,0,0,0
|
||||
2045360,Valorous Scourgestalker Handguards,319,83,4,10,4,3,3,68,7,96,5,63,36,63,31,62,38,244,0,0,0,0,0,0,0,0
|
||||
2046118,Conqueror's Darkruned Chestguard,326,83,4,5,4,4,4,150,7,227,12,99,14,80,13,93,0,0,0,0,0,0,0,0,0,0
|
||||
2046121,Conqueror's Darkruned Legguards,326,83,4,7,4,4,4,117,7,227,12,102,14,125,37,91,0,0,0,0,0,0,0,0,0,0
|
||||
2045412,Valorous Worldbreaker Faceguard,319,83,4,1,4,3,3,77,7,106,5,86,32,105,36,75,38,291,0,0,0,0,0,0,0,0
|
||||
2046208,Conqueror's Worldbreaker War-Kilt,326,83,4,7,4,3,3,102,7,119,5,79,36,125,31,93,38,303,0,0,0,0,0,0,0,0
|
||||
2046206,Conqueror's Worldbreaker Hauberk,326,83,4,20,4,3,45,178,7,131,5,133,31,93,36,116,0,0,0,0,0,0,0,0,0,0
|
||||
|
BIN
cmd/dungeon-items/items.db
Normal file
BIN
cmd/dungeon-items/items.db
Normal file
Binary file not shown.
136
cmd/dungeon-items/main.go
Normal file
136
cmd/dungeon-items/main.go
Normal file
@@ -0,0 +1,136 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"database/sql"
|
||||
|
||||
"log"
|
||||
"os"
|
||||
"strconv"
|
||||
"strings"
|
||||
|
||||
"github.com/araxiaonline/endgame-item-generator/internal/db/mysql"
|
||||
"github.com/araxiaonline/endgame-item-generator/internal/db/sqlite"
|
||||
"github.com/joho/godotenv"
|
||||
_ "github.com/mattn/go-sqlite3"
|
||||
)
|
||||
|
||||
func createTable(db *sql.DB) {
|
||||
|
||||
droptable := `DROP TABLE IF EXISTS dungeon_items`
|
||||
_, err := db.Exec(droptable)
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
|
||||
createTable := `CREATE TABLE IF NOT EXISTS dungeon_items (
|
||||
entry int unsigned NOT NULL DEFAULT '0',
|
||||
mapId tinyint unsigned NOT NULL DEFAULT '0',
|
||||
expansion tinyint unsigned NOT NULL DEFAULT '0',
|
||||
dungeonLevel tinyint unsigned NOT NULL DEFAULT '0',
|
||||
creatureId unsigned NULL DEFAULT NULL,
|
||||
Quality int unsigned NOT NULL DEFAULT '0',
|
||||
PRIMARY KEY (entry)
|
||||
)`
|
||||
|
||||
_, err = db.Exec(createTable)
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
}
|
||||
|
||||
func ConvertIntSliceToString(slice []int) string {
|
||||
sliceStr := make([]string, len(slice))
|
||||
for i, v := range slice {
|
||||
sliceStr[i] = strconv.Itoa(v)
|
||||
}
|
||||
|
||||
return strings.Join(sliceStr, ",")
|
||||
}
|
||||
|
||||
func main() {
|
||||
godotenv.Load("../../.env")
|
||||
liteDb, err := sql.Open("sqlite3", "../../data/items.db")
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
mysqlDb, err := mysql.Connect(&mysql.MySqlConfig{
|
||||
Host: os.Getenv("DB_HOST"),
|
||||
User: os.Getenv("DB_USER"),
|
||||
Password: os.Getenv("DB_PASSWORD"),
|
||||
Database: os.Getenv("DB_NAME"),
|
||||
})
|
||||
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
os.Exit(1)
|
||||
}
|
||||
|
||||
defer liteDb.Close()
|
||||
defer mysqlDb.Close()
|
||||
|
||||
// create the items table if it doesnt exist
|
||||
createTable(liteDb)
|
||||
|
||||
// Get all the dungeons and crawl to get all loot and add to sqlite
|
||||
dungeons, err := mysql.MySql.GetDungeons(-1)
|
||||
if err != nil {
|
||||
log.Panicf("failed to get dungeons for expansion %v error: %v", 0, err)
|
||||
}
|
||||
|
||||
for _, dungeon := range dungeons {
|
||||
|
||||
log.Printf("+++++Dungeon: %s ID: %v level %v \n", dungeon.Name, dungeon.Id, dungeon.Level)
|
||||
|
||||
bosses, err := mysql.MySql.GetBosses(dungeon.Id)
|
||||
if err != nil {
|
||||
log.Fatal("failed to get bosses")
|
||||
}
|
||||
|
||||
for _, boss := range bosses {
|
||||
dbItems, err := mysql.MySql.GetBossLoot(boss.Entry)
|
||||
|
||||
if err != nil {
|
||||
log.Fatalf("failed to get boss loot: %v error:", boss.Name, err)
|
||||
}
|
||||
|
||||
for _, dungItem := range dbItems {
|
||||
|
||||
insertItem := sqlite.DungeonItem{
|
||||
Entry: dungItem.Entry,
|
||||
MapId: dungeon.Id,
|
||||
Quality: *dungItem.Quality,
|
||||
CreatureId: boss.Entry,
|
||||
Expansion: dungeon.ExpansionId,
|
||||
DungeonLevel: dungeon.Level,
|
||||
}
|
||||
liteDb.Exec("INSERT OR IGNORE INTO dungeon_items (entry, mapId, expansion, dungeonLevel, creatureId, Quality) VALUES (?, ?, ?, ?, ?, ?)", insertItem.Entry, insertItem.MapId, insertItem.Expansion, insertItem.DungeonLevel, insertItem.CreatureId, insertItem.Quality)
|
||||
if err != nil {
|
||||
log.Printf("Failed to insert item %v: %v", insertItem.Entry, err)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
dbItems, err := mysql.MySql.GetAddlDungeonDrops(dungeon.Id)
|
||||
if err != nil {
|
||||
log.Fatalf("failed to get additional dungeon drops: %v error: %v", dungeon.Name, err)
|
||||
}
|
||||
|
||||
for _, dungItem := range dbItems {
|
||||
insertItem := sqlite.DungeonItem{
|
||||
Entry: dungItem.Entry,
|
||||
MapId: dungeon.Id,
|
||||
Quality: *dungItem.Quality,
|
||||
CreatureId: 0,
|
||||
Expansion: dungeon.ExpansionId,
|
||||
DungeonLevel: dungeon.Level,
|
||||
}
|
||||
liteDb.Exec("INSERT OR IGNORE INTO dungeon_items (entry, mapId, expansion, dungeonLevel, creatureId, Quality) VALUES (?, ?, ?, ?, ?, ?)", insertItem.Entry, insertItem.MapId, insertItem.Expansion, insertItem.DungeonLevel, insertItem.CreatureId, insertItem.Quality)
|
||||
if err != nil {
|
||||
log.Printf("Failed to insert item %v: %v", insertItem.Entry, err)
|
||||
}
|
||||
|
||||
log.Printf("+++++Dungeon Item: %s ID: %v level %v \n", dungItem.Name, dungItem.Entry, dungeon.Level)
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
BIN
cmd/durability-costs/DurabilityCosts.dbc
Normal file
BIN
cmd/durability-costs/DurabilityCosts.dbc
Normal file
Binary file not shown.
298
cmd/durability-costs/main.go
Normal file
298
cmd/durability-costs/main.go
Normal file
@@ -0,0 +1,298 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"encoding/binary"
|
||||
"fmt"
|
||||
"io"
|
||||
"log"
|
||||
"os"
|
||||
)
|
||||
|
||||
type DurabilityCost struct {
|
||||
ID uint32
|
||||
WeaponSubClassCost [21]uint32
|
||||
ArmorSubClassCost [8]uint32
|
||||
}
|
||||
|
||||
type DBCHeader struct {
|
||||
Magic [4]byte
|
||||
RecordCount uint32
|
||||
FieldCount uint32
|
||||
RecordSize uint32
|
||||
StringBlockSize uint32
|
||||
}
|
||||
|
||||
// read a dbc file and return the header information
|
||||
func ReadDBCHeader(filepath string) (DBCHeader, error) {
|
||||
file, err := os.Open(filepath)
|
||||
if err != nil {
|
||||
return DBCHeader{}, fmt.Errorf("failed to open file: %v", err)
|
||||
}
|
||||
defer file.Close()
|
||||
|
||||
var header DBCHeader
|
||||
if err := binary.Read(file, binary.LittleEndian, &header); err != nil {
|
||||
return DBCHeader{}, fmt.Errorf("failed to read DBC header: %v", err)
|
||||
}
|
||||
|
||||
if string(header.Magic[:]) != "WDBC" {
|
||||
return DBCHeader{}, fmt.Errorf("invalid DBC file: wrong magic identifier")
|
||||
}
|
||||
|
||||
return header, nil
|
||||
}
|
||||
|
||||
func GetStringOffset(filepath string, header DBCHeader) (int64, error) {
|
||||
file, err := os.OpenFile(filepath, os.O_RDWR, 0644)
|
||||
if err != nil {
|
||||
return 0, fmt.Errorf("failed to open file for header update: %v", err)
|
||||
}
|
||||
defer file.Close()
|
||||
|
||||
stringBlocks, err := file.Seek(-int64(header.StringBlockSize), io.SeekEnd)
|
||||
if err != nil {
|
||||
return 0, fmt.Errorf("failed to seek to string block: %v", err)
|
||||
}
|
||||
|
||||
return stringBlocks, nil
|
||||
}
|
||||
|
||||
func GetStringBlock(filepath string, header DBCHeader) ([]byte, error) {
|
||||
file, err := os.OpenFile(filepath, os.O_RDWR, 0644)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to open file for header update: %v", err)
|
||||
}
|
||||
defer file.Close()
|
||||
|
||||
stringBlocks, err := file.Seek(-int64(header.StringBlockSize), io.SeekEnd)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to seek to string block: %v", err)
|
||||
}
|
||||
|
||||
StringBytes := make([]byte, header.StringBlockSize)
|
||||
_, err = file.ReadAt(StringBytes, stringBlocks)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to read string block: %v", err)
|
||||
}
|
||||
|
||||
return StringBytes, nil
|
||||
}
|
||||
|
||||
// Reader for durability costs costs from a DBC file
|
||||
func ReadDurabilityCosts(filepath string) ([]DurabilityCost, error) {
|
||||
file, err := os.Open(filepath)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to open file: %v", err)
|
||||
}
|
||||
defer file.Close()
|
||||
|
||||
var durabilityCosts []DurabilityCost
|
||||
|
||||
// Skip header (20 bytes)
|
||||
header := make([]byte, 20)
|
||||
if _, err := file.Read(header); err != nil {
|
||||
return nil, fmt.Errorf("failed to read header: %v", err)
|
||||
}
|
||||
|
||||
recordCount := binary.LittleEndian.Uint32(header[4:8])
|
||||
fmt.Printf("Record count: %d\n", recordCount)
|
||||
|
||||
for i := 0; i < int(recordCount); i++ {
|
||||
var cost DurabilityCost
|
||||
if err := binary.Read(file, binary.LittleEndian, &cost.ID); err != nil {
|
||||
return nil, fmt.Errorf("failed to read ID at record %d: %v", i, err)
|
||||
}
|
||||
fmt.Printf("Read ID: %d\n", cost.ID)
|
||||
|
||||
for j := 0; j < len(cost.WeaponSubClassCost); j++ {
|
||||
if err := binary.Read(file, binary.LittleEndian, &cost.WeaponSubClassCost[j]); err != nil {
|
||||
return nil, fmt.Errorf("failed to read WeaponSubClassCost[%d] at record %d: %v", j, i, err)
|
||||
}
|
||||
fmt.Printf("Read WeaponSubClassCost[%d]: %d\n", j, cost.WeaponSubClassCost[j])
|
||||
}
|
||||
|
||||
// Read ArmorSubClassCost
|
||||
for j := 0; j < len(cost.ArmorSubClassCost); j++ {
|
||||
if err := binary.Read(file, binary.LittleEndian, &cost.ArmorSubClassCost[j]); err != nil {
|
||||
return nil, fmt.Errorf("failed to read ArmorSubClassCost[%d] at record %d: %v", j, i, err)
|
||||
}
|
||||
fmt.Printf("Read ArmorSubClassCost[%d]: %d\n", j, cost.ArmorSubClassCost[j])
|
||||
}
|
||||
|
||||
durabilityCosts = append(durabilityCosts, cost)
|
||||
}
|
||||
|
||||
remainingBytes := make([]byte, 1024) // Read up to 1024 bytes beyond the expected records
|
||||
n, _ := file.Read(remainingBytes)
|
||||
if n > 0 {
|
||||
fmt.Printf("Extra data at the end of file (%d bytes): %X\n", n, remainingBytes[:n])
|
||||
}
|
||||
|
||||
return durabilityCosts, nil
|
||||
}
|
||||
|
||||
func WriteDurabilityCost(filepath string, cost DurabilityCost) error {
|
||||
file, err := os.OpenFile(filepath, os.O_RDWR, 0644)
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to open file: %v", err)
|
||||
}
|
||||
defer file.Close()
|
||||
|
||||
// Read the header
|
||||
header := make([]byte, 20)
|
||||
if _, err := file.Read(header); err != nil {
|
||||
return fmt.Errorf("failed to read header: %v", err)
|
||||
}
|
||||
|
||||
// Update the record count in the header
|
||||
recordCount := binary.LittleEndian.Uint32(header[4:8])
|
||||
recordCount++
|
||||
binary.LittleEndian.PutUint32(header[4:8], recordCount)
|
||||
|
||||
// Write the updated header back to the file
|
||||
if _, err := file.Seek(0, 0); err != nil {
|
||||
return fmt.Errorf("failed to seek to the beginning: %v", err)
|
||||
}
|
||||
if _, err := file.Write(header); err != nil {
|
||||
return fmt.Errorf("failed to write updated header: %v", err)
|
||||
}
|
||||
|
||||
// Move to the end of the file to append the new record
|
||||
if _, err := file.Seek(0, io.SeekEnd); err != nil {
|
||||
return fmt.Errorf("failed to seek to the end: %v", err)
|
||||
}
|
||||
|
||||
buffer := new(bytes.Buffer)
|
||||
if err := binary.Write(buffer, binary.LittleEndian, cost.ID); err != nil {
|
||||
return fmt.Errorf("failed to write ID: %v", err)
|
||||
}
|
||||
|
||||
// Write WeaponSubClassCost in little-endian format (uint32)
|
||||
for _, value := range cost.WeaponSubClassCost {
|
||||
if err := binary.Write(buffer, binary.LittleEndian, value); err != nil {
|
||||
return fmt.Errorf("failed to write WeaponSubClassCost: %v", err)
|
||||
}
|
||||
}
|
||||
|
||||
// Write ArmorSubClassCost in little-endian format (uint32)
|
||||
for _, value := range cost.ArmorSubClassCost {
|
||||
if err := binary.Write(buffer, binary.LittleEndian, value); err != nil {
|
||||
return fmt.Errorf("failed to write ArmorSubClassCost: %v", err)
|
||||
}
|
||||
}
|
||||
|
||||
// Align the record size to the expected size in the DBC file
|
||||
// If the record size is less than the expected size, pad with zeros
|
||||
expectedRecordSize := 116
|
||||
actualRecordSize := buffer.Len()
|
||||
|
||||
if actualRecordSize < expectedRecordSize {
|
||||
padding := make([]byte, expectedRecordSize-actualRecordSize)
|
||||
buffer.Write(padding)
|
||||
}
|
||||
|
||||
// Write the new record to the file
|
||||
if _, err := file.Write(buffer.Bytes()); err != nil {
|
||||
return fmt.Errorf("failed to write to file: %v", err)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func AppendDurabilityCostsToFile(filepath string, durabilityCosts []DurabilityCost) error {
|
||||
// Step 1: Open the file without O_APPEND to update the header
|
||||
file, err := os.OpenFile(filepath, os.O_RDWR, 0644)
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to open file for header update: %v", err)
|
||||
}
|
||||
defer file.Close()
|
||||
|
||||
header, err := ReadDBCHeader(filepath)
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to read DBC header: %v", err)
|
||||
}
|
||||
|
||||
header.RecordCount += uint32(len(durabilityCosts))
|
||||
|
||||
if _, err := file.Seek(0, 0); err != nil {
|
||||
return fmt.Errorf("failed to find beginning of the file: %v", err)
|
||||
}
|
||||
|
||||
err = binary.Write(file, binary.LittleEndian, &header)
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to write updated header: %v", err)
|
||||
}
|
||||
|
||||
// get the string block offset to write
|
||||
offset, err := GetStringOffset(filepath, header)
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to get string block offset: %v", err)
|
||||
}
|
||||
|
||||
savedStrBlock, err := GetStringBlock(filepath, header)
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to get string block: %v", err)
|
||||
}
|
||||
|
||||
_, err = file.Seek(offset, 0)
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to seek to string block: %v", err)
|
||||
}
|
||||
|
||||
for _, cost := range durabilityCosts {
|
||||
if err := binary.Write(file, binary.LittleEndian, cost.ID); err != nil {
|
||||
return fmt.Errorf("failed to write ID: %v", err)
|
||||
}
|
||||
|
||||
for _, weaponCost := range cost.WeaponSubClassCost {
|
||||
if err := binary.Write(file, binary.LittleEndian, weaponCost); err != nil {
|
||||
return fmt.Errorf("failed to write WeaponSubClassCost: %v", err)
|
||||
}
|
||||
}
|
||||
|
||||
for _, armorCost := range cost.ArmorSubClassCost {
|
||||
if err := binary.Write(file, binary.LittleEndian, armorCost); err != nil {
|
||||
return fmt.Errorf("failed to write ArmorSubClassCost: %v", err)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Write the string block back to the file
|
||||
_, err = file.Write(savedStrBlock)
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to write string block: %v", err)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func main() {
|
||||
|
||||
costs, err := ReadDurabilityCosts("DurabilityCosts.dbc")
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
|
||||
Row300 := costs[len(costs)-1]
|
||||
toAdd := 450 // Number of new durability to add
|
||||
|
||||
newRows := []DurabilityCost{}
|
||||
|
||||
for i := 301; i <= toAdd; i++ {
|
||||
newRow := Row300
|
||||
newRow.ID = uint32(i)
|
||||
|
||||
for j := 0; j < len(Row300.WeaponSubClassCost); j++ {
|
||||
newRow.WeaponSubClassCost[j] += uint32(20) * (uint32(i) - 300)
|
||||
}
|
||||
for j := 0; j < len(Row300.ArmorSubClassCost); j++ {
|
||||
newRow.ArmorSubClassCost[j] += uint32(10) * (uint32(i) - 300)
|
||||
}
|
||||
|
||||
newRows = append(newRows, newRow)
|
||||
}
|
||||
|
||||
AppendDurabilityCostsToFile("DurabilityCosts.dbc", newRows)
|
||||
ReadDurabilityCosts("DurabilityCosts.dbc")
|
||||
}
|
||||
115
cmd/fetch-highlevel-items/.add.go
Normal file
115
cmd/fetch-highlevel-items/.add.go
Normal file
@@ -0,0 +1,115 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"database/sql"
|
||||
"fmt"
|
||||
"slices"
|
||||
|
||||
"log"
|
||||
"os"
|
||||
"strconv"
|
||||
"strings"
|
||||
|
||||
"github.com/araxiaonline/endgame-item-generator/internal/db/mysql"
|
||||
"github.com/araxiaonline/endgame-item-generator/internal/items"
|
||||
"github.com/joho/godotenv"
|
||||
_ "github.com/mattn/go-sqlite3"
|
||||
)
|
||||
|
||||
type EndGameItem struct {
|
||||
Entry int `db:"entry"`
|
||||
Class int `db:"class"`
|
||||
Subclass int `db:"subclass"`
|
||||
StatsList string `db:"stats_list"`
|
||||
}
|
||||
|
||||
func createItemsTable(db *sql.DB) {
|
||||
createItems := `CREATE TABLE IF NOT EXISTS items (
|
||||
entry int unsigned NOT NULL DEFAULT '0',
|
||||
class tinyint unsigned NOT NULL DEFAULT '0',
|
||||
name varchar(250) NOT NULL DEFAULT '',
|
||||
Quality int unsigned NOT NULL DEFAULT '0',
|
||||
itemLevel int unsigned NOT NULL DEFAULT '0',
|
||||
subclass tinyint unsigned NOT NULL DEFAULT '0',
|
||||
stats_list varchar(250) NOT NULL DEFAULT '',
|
||||
PRIMARY KEY (entry)
|
||||
)`
|
||||
|
||||
_, err := db.Exec(createItems)
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
}
|
||||
|
||||
func ConvertIntSliceToString(slice []int) string {
|
||||
sliceStr := make([]string, len(slice))
|
||||
for i, v := range slice {
|
||||
sliceStr[i] = strconv.Itoa(v)
|
||||
}
|
||||
|
||||
return strings.Join(sliceStr, ",")
|
||||
}
|
||||
|
||||
func main() {
|
||||
godotenv.Load("../../.env")
|
||||
liteDb, err := sql.Open("sqlite3", "../../data/items.db")
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
mysqlDb, err := mysql.Connect(&mysql.MySqlConfig{
|
||||
Host: os.Getenv("DB_HOST"),
|
||||
User: os.Getenv("DB_USER"),
|
||||
Password: os.Getenv("DB_PASSWORD"),
|
||||
Database: os.Getenv("DB_NAME"),
|
||||
})
|
||||
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
os.Exit(1)
|
||||
}
|
||||
|
||||
defer liteDb.Close()
|
||||
defer mysqlDb.Close()
|
||||
|
||||
// create the items table if it doesnt exist
|
||||
createItemsTable(liteDb)
|
||||
|
||||
// create the endgames items lookup table locally for items 200 and above
|
||||
var dbItems []mysql.DbItem
|
||||
sql := `
|
||||
SELECT ` + mysql.GetItemFields("") + `
|
||||
from acore_world.item_template
|
||||
where ItemLevel >= 220 and Quality >= 3 and ItemLevel < 290
|
||||
AND name NOT LIKE 'NPC Equip%' and name NOT LIKE 'OLD%'
|
||||
AND name NOT LIKE '%(test)%' AND name NOT LIKE '%Deprecated%'
|
||||
AND name NOT LIKE '%Monster - %'
|
||||
AND ((class = 2 and subclass IN(0,1,2,3,4,5,6,7,8,10,11,12,13,15,16,17,18,19)) or ((class = 4 AND subclass IN (0,1,2,3,4,6))))
|
||||
AND stat_type1 != 32 AND stat_type2 != 32 AND stat_type3 != 32 AND stat_type4 != 32 AND stat_type5 != 32 AND stat_type6 != 32 AND stat_type7 != 32 AND stat_type8 != 32 AND stat_type9 != 32 AND stat_type10 != 32
|
||||
`
|
||||
err = mysqlDb.Select(&dbItems, sql)
|
||||
if err != nil {
|
||||
log.Printf("Failed to get items: %v", err)
|
||||
}
|
||||
|
||||
for _, dbItem := range dbItems {
|
||||
item := items.ItemFromDbItem(dbItem)
|
||||
var statsList []int
|
||||
for i := 1; i <= 10; i++ {
|
||||
val, _ := item.GetField(fmt.Sprintf("StatValue%v", i))
|
||||
statId, _ := item.GetField(fmt.Sprintf("StatType%v", i))
|
||||
if val != 0 {
|
||||
statsList = append(statsList, statId)
|
||||
}
|
||||
}
|
||||
slices.Sort(statsList)
|
||||
statsListStr := ConvertIntSliceToString(statsList)
|
||||
log.Printf("StatList %s for Item %v", statsListStr, item.Name)
|
||||
_, err = liteDb.Exec("INSERT OR IGNORE INTO items (entry, class, name, Quality, itemLevel, subclass, stats_list) VALUES (?, ?, ?, ?, ?,?,?)", item.Entry, *item.Class, item.Name, *item.Quality, *item.ItemLevel, *item.Subclass, statsListStr)
|
||||
if err != nil {
|
||||
log.Printf("Failed to insert item %v: %v", item.Entry, err)
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
log.Printf("Items: %v", len(dbItems))
|
||||
}
|
||||
39
cmd/raid-gear/gear.manual.sql
Normal file
39
cmd/raid-gear/gear.manual.sql
Normal file
@@ -0,0 +1,39 @@
|
||||
DELETE FROM `item_template` WHERE (`entry` = 20016852);
|
||||
INSERT INTO `item_template` (`entry`, `class`, `subclass`, `SoundOverrideSubclass`, `name`, `displayid`, `Quality`, `Flags`, `FlagsExtra`, `BuyCount`, `BuyPrice`, `SellPrice`, `InventoryType`, `AllowableClass`, `AllowableRace`, `ItemLevel`, `RequiredLevel`, `RequiredSkill`, `RequiredSkillRank`, `requiredspell`, `requiredhonorrank`, `RequiredCityRank`, `RequiredReputationFaction`, `RequiredReputationRank`, `maxcount`, `stackable`, `ContainerSlots`, `StatsCount`, `stat_type1`, `stat_value1`, `stat_type2`, `stat_value2`, `stat_type3`, `stat_value3`, `stat_type4`, `stat_value4`, `stat_type5`, `stat_value5`, `stat_type6`, `stat_value6`, `stat_type7`, `stat_value7`, `stat_type8`, `stat_value8`, `stat_type9`, `stat_value9`, `stat_type10`, `stat_value10`, `ScalingStatDistribution`, `ScalingStatValue`, `dmg_min1`, `dmg_max1`, `dmg_type1`, `dmg_min2`, `dmg_max2`, `dmg_type2`, `armor`, `holy_res`, `fire_res`, `nature_res`, `frost_res`, `shadow_res`, `arcane_res`, `delay`, `ammo_type`, `RangedModRange`, `spellid_1`, `spelltrigger_1`, `spellcharges_1`, `spellppmRate_1`, `spellcooldown_1`, `spellcategory_1`, `spellcategorycooldown_1`, `spellid_2`, `spelltrigger_2`, `spellcharges_2`, `spellppmRate_2`, `spellcooldown_2`, `spellcategory_2`, `spellcategorycooldown_2`, `spellid_3`, `spelltrigger_3`, `spellcharges_3`, `spellppmRate_3`, `spellcooldown_3`, `spellcategory_3`, `spellcategorycooldown_3`, `spellid_4`, `spelltrigger_4`, `spellcharges_4`, `spellppmRate_4`, `spellcooldown_4`, `spellcategory_4`, `spellcategorycooldown_4`, `spellid_5`, `spelltrigger_5`, `spellcharges_5`, `spellppmRate_5`, `spellcooldown_5`, `spellcategory_5`, `spellcategorycooldown_5`, `bonding`, `description`, `PageText`, `LanguageID`, `PageMaterial`, `startquest`, `lockid`, `Material`, `sheath`, `RandomProperty`, `RandomSuffix`, `block`, `itemset`, `MaxDurability`, `area`, `Map`, `BagFamily`, `TotemCategory`, `socketColor_1`, `socketContent_1`, `socketColor_2`, `socketContent_2`, `socketColor_3`, `socketContent_3`, `socketBonus`, `GemProperties`, `RequiredDisenchantSkill`, `ArmorDamageModifier`, `duration`, `ItemLimitCategory`, `HolidayId`, `ScriptName`, `DisenchantID`, `FoodType`, `minMoneyLoot`, `maxMoneyLoot`, `flagsCustom`, `VerifiedBuild`) VALUES
|
||||
(20016852, 4, 3, -1, 'Unyielding Giantstalker''s Gloves', 32024, 4, 0, 0, 1, 112268, 376014, 10, 4, -1, 325, 83, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 5, 44, 101, 31, 25, 5, 145, 3, 260, 7, 245, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2150, 0, 27, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -1, 0, -1, 0, 0, 0, 0, -1, 0, -1, 0, 0, 0, 0, -1, 0, -1, 0, 0, 0, 0, -1, 0, -1, 0, 0, 0, 0, -1, 0, -1, 1, '', 0, 0, 0, 0, 0, 5, 0, 0, 0, 0, 206, 50, 0, 0, 0, 0, 4, 0, 0, 0, 0, 0, 0, 0, 375, 0, 0, 0, 0, '', 68, 0, 0, 0, 0, 12340);
|
||||
|
||||
DELETE FROM `item_template` WHERE (`entry` = 20016821);
|
||||
INSERT INTO `item_template` (`entry`, `class`, `subclass`, `SoundOverrideSubclass`, `name`, `displayid`, `Quality`, `Flags`, `FlagsExtra`, `BuyCount`, `BuyPrice`, `SellPrice`, `InventoryType`, `AllowableClass`, `AllowableRace`, `ItemLevel`, `RequiredLevel`, `RequiredSkill`, `RequiredSkillRank`, `requiredspell`, `requiredhonorrank`, `RequiredCityRank`, `RequiredReputationFaction`, `RequiredReputationRank`, `maxcount`, `stackable`, `ContainerSlots`, `StatsCount`, `stat_type1`, `stat_value1`, `stat_type2`, `stat_value2`, `stat_type3`, `stat_value3`, `stat_type4`, `stat_value4`, `stat_type5`, `stat_value5`, `stat_type6`, `stat_value6`, `stat_type7`, `stat_value7`, `stat_type8`, `stat_value8`, `stat_type9`, `stat_value9`, `stat_type10`, `stat_value10`, `ScalingStatDistribution`, `ScalingStatValue`, `dmg_min1`, `dmg_max1`, `dmg_type1`, `dmg_min2`, `dmg_max2`, `dmg_type2`, `armor`, `holy_res`, `fire_res`, `nature_res`, `frost_res`, `shadow_res`, `arcane_res`, `delay`, `ammo_type`, `RangedModRange`, `spellid_1`, `spelltrigger_1`, `spellcharges_1`, `spellppmRate_1`, `spellcooldown_1`, `spellcategory_1`, `spellcategorycooldown_1`, `spellid_2`, `spelltrigger_2`, `spellcharges_2`, `spellppmRate_2`, `spellcooldown_2`, `spellcategory_2`, `spellcategorycooldown_2`, `spellid_3`, `spelltrigger_3`, `spellcharges_3`, `spellppmRate_3`, `spellcooldown_3`, `spellcategory_3`, `spellcategorycooldown_3`, `spellid_4`, `spelltrigger_4`, `spellcharges_4`, `spellppmRate_4`, `spellcooldown_4`, `spellcategory_4`, `spellcategorycooldown_4`, `spellid_5`, `spelltrigger_5`, `spellcharges_5`, `spellppmRate_5`, `spellcooldown_5`, `spellcategory_5`, `spellcategorycooldown_5`, `bonding`, `description`, `PageText`, `LanguageID`, `PageMaterial`, `startquest`, `lockid`, `Material`, `sheath`, `RandomProperty`, `RandomSuffix`, `block`, `itemset`, `MaxDurability`, `area`, `Map`, `BagFamily`, `TotemCategory`, `socketColor_1`, `socketContent_1`, `socketColor_2`, `socketContent_2`, `socketColor_3`, `socketContent_3`, `socketBonus`, `GemProperties`, `RequiredDisenchantSkill`, `ArmorDamageModifier`, `duration`, `ItemLimitCategory`, `HolidayId`, `ScriptName`, `DisenchantID`, `FoodType`, `minMoneyLoot`, `maxMoneyLoot`, `flagsCustom`, `VerifiedBuild`) VALUES
|
||||
(20016821, 4, 2, -1, 'Powerful Nightslayer Cover', 31514, 4, 0, 0, 1, 131332, 184768, 1, 8, -1, 325, 85, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 5, 7, 311, 31, 67, 3, 234, 32, 119, 38, 327, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 925, 0, 28, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -1, 0, -1, 0, 0, 0, 0, -1, 0, -1, 0, 0, 0, 0, -1, 0, -1, 0, 0, 0, 0, -1, 0, -1, 0, 0, 0, 0, -1, 0, -1, 1, '', 0, 0, 0, 0, 0, 8, 0, 0, 0, 0, 204, 70, 0, 0, 0, 0, 8, 0, 2, 0, 0, 0, 0, 0, 375, 0, 0, 0, 0, '', 68, 0, 0, 0, 0, 12340);
|
||||
|
||||
DELETE FROM `item_template` WHERE (`entry` = 20018823);
|
||||
INSERT INTO `item_template` (`entry`, `class`, `subclass`, `SoundOverrideSubclass`, `name`, `displayid`, `Quality`, `Flags`, `FlagsExtra`, `BuyCount`, `BuyPrice`, `SellPrice`, `InventoryType`, `AllowableClass`, `AllowableRace`, `ItemLevel`, `RequiredLevel`, `RequiredSkill`, `RequiredSkillRank`, `requiredspell`, `requiredhonorrank`, `RequiredCityRank`, `RequiredReputationFaction`, `RequiredReputationRank`, `maxcount`, `stackable`, `ContainerSlots`, `StatsCount`, `stat_type1`, `stat_value1`, `stat_type2`, `stat_value2`, `stat_type3`, `stat_value3`, `stat_type4`, `stat_value4`, `stat_type5`, `stat_value5`, `stat_type6`, `stat_value6`, `stat_type7`, `stat_value7`, `stat_type8`, `stat_value8`, `stat_type9`, `stat_value9`, `stat_type10`, `stat_value10`, `ScalingStatDistribution`, `ScalingStatValue`, `dmg_min1`, `dmg_max1`, `dmg_type1`, `dmg_min2`, `dmg_max2`, `dmg_type2`, `armor`, `holy_res`, `fire_res`, `nature_res`, `frost_res`, `shadow_res`, `arcane_res`, `delay`, `ammo_type`, `RangedModRange`, `spellid_1`, `spelltrigger_1`, `spellcharges_1`, `spellppmRate_1`, `spellcooldown_1`, `spellcategory_1`, `spellcategorycooldown_1`, `spellid_2`, `spelltrigger_2`, `spellcharges_2`, `spellppmRate_2`, `spellcooldown_2`, `spellcategory_2`, `spellcategorycooldown_2`, `spellid_3`, `spelltrigger_3`, `spellcharges_3`, `spellppmRate_3`, `spellcooldown_3`, `spellcategory_3`, `spellcategorycooldown_3`, `spellid_4`, `spelltrigger_4`, `spellcharges_4`, `spellppmRate_4`, `spellcooldown_4`, `spellcategory_4`, `spellcategorycooldown_4`, `spellid_5`, `spelltrigger_5`, `spellcharges_5`, `spellppmRate_5`, `spellcooldown_5`, `spellcategory_5`, `spellcategorycooldown_5`, `bonding`, `description`, `PageText`, `LanguageID`, `PageMaterial`, `startquest`, `lockid`, `Material`, `sheath`, `RandomProperty`, `RandomSuffix`, `block`, `itemset`, `MaxDurability`, `area`, `Map`, `BagFamily`, `TotemCategory`, `socketColor_1`, `socketContent_1`, `socketColor_2`, `socketContent_2`, `socketColor_3`, `socketContent_3`, `socketBonus`, `GemProperties`, `RequiredDisenchantSkill`, `ArmorDamageModifier`, `duration`, `ItemLimitCategory`, `HolidayId`, `ScriptName`, `DisenchantID`, `FoodType`, `minMoneyLoot`, `maxMoneyLoot`, `flagsCustom`, `VerifiedBuild`) VALUES
|
||||
(20018823, 4, 2, -1, 'Powerful Aged Core Leather Gloves', 31290, 4, 0, 0, 1, 96177, 243248, 10, -1, -1, 325, 80, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 5, 38, 314, 3, 290, 7, 241, 44, 141, 36, 116, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 925, 0, 28, 0, 0, 24, 0, 0, 0, 0, 0, 0, 0, 0, -1, 0, -1, 0, 1, 0, 0, -1, 0, -1, 0, 0, 0, 0, -1, 0, -1, 0, 0, 0, 0, -1, 0, -1, 0, 0, 0, 0, -1, 0, -1, 1, '', 0, 0, 0, 0, 0, 8, 0, 0, 0, 0, 0, 40, 0, 0, 0, 0, 4, 0, 2, 0, 0, 0, 0, 0, 375, 0, 0, 0, 0, '', 68, 0, 0, 0, 0, 12340);
|
||||
|
||||
DELETE FROM `item_template` WHERE (`entry` = 20018832);
|
||||
INSERT INTO `item_template` (`entry`, `class`, `subclass`, `SoundOverrideSubclass`, `name`, `displayid`, `Quality`, `Flags`, `FlagsExtra`, `BuyCount`, `BuyPrice`, `SellPrice`, `InventoryType`, `AllowableClass`, `AllowableRace`, `ItemLevel`, `RequiredLevel`, `RequiredSkill`, `RequiredSkillRank`, `requiredspell`, `requiredhonorrank`, `RequiredCityRank`, `RequiredReputationFaction`, `RequiredReputationRank`, `maxcount`, `stackable`, `ContainerSlots`, `StatsCount`, `stat_type1`, `stat_value1`, `stat_type2`, `stat_value2`, `stat_type3`, `stat_value3`, `stat_type4`, `stat_value4`, `stat_type5`, `stat_value5`, `stat_type6`, `stat_value6`, `stat_type7`, `stat_value7`, `stat_type8`, `stat_value8`, `stat_type9`, `stat_value9`, `stat_type10`, `stat_value10`, `ScalingStatDistribution`, `ScalingStatValue`, `dmg_min1`, `dmg_max1`, `dmg_type1`, `dmg_min2`, `dmg_max2`, `dmg_type2`, `armor`, `holy_res`, `fire_res`, `nature_res`, `frost_res`, `shadow_res`, `arcane_res`, `delay`, `ammo_type`, `RangedModRange`, `spellid_1`, `spelltrigger_1`, `spellcharges_1`, `spellppmRate_1`, `spellcooldown_1`, `spellcategory_1`, `spellcategorycooldown_1`, `spellid_2`, `spelltrigger_2`, `spellcharges_2`, `spellppmRate_2`, `spellcooldown_2`, `spellcategory_2`, `spellcategorycooldown_2`, `spellid_3`, `spelltrigger_3`, `spellcharges_3`, `spellppmRate_3`, `spellcooldown_3`, `spellcategory_3`, `spellcategorycooldown_3`, `spellid_4`, `spelltrigger_4`, `spellcharges_4`, `spellppmRate_4`, `spellcooldown_4`, `spellcategory_4`, `spellcategorycooldown_4`, `spellid_5`, `spelltrigger_5`, `spellcharges_5`, `spellppmRate_5`, `spellcooldown_5`, `spellcategory_5`, `spellcategorycooldown_5`, `bonding`, `description`, `PageText`, `LanguageID`, `PageMaterial`, `startquest`, `lockid`, `Material`, `sheath`, `RandomProperty`, `RandomSuffix`, `block`, `itemset`, `MaxDurability`, `area`, `Map`, `BagFamily`, `TotemCategory`, `socketColor_1`, `socketContent_1`, `socketColor_2`, `socketContent_2`, `socketColor_3`, `socketContent_3`, `socketBonus`, `GemProperties`, `RequiredDisenchantSkill`, `ArmorDamageModifier`, `duration`, `ItemLimitCategory`, `HolidayId`, `ScriptName`, `DisenchantID`, `FoodType`, `minMoneyLoot`, `maxMoneyLoot`, `flagsCustom`, `VerifiedBuild`) VALUES
|
||||
(20018832, 2, 7, -1, 'Stalwart Brutality Blade', 31309, 4, 524288, 0, 1, 364162, 154089, 13, -1, -1, 325, 85, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 4, 38, 301, 7, 218, 32, 54, 3, 101, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 589, 945, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2500, 0, 0, 0, 0, 0, 0, -1, 0, -1, 0, 0, 0, 0, -1, 0, -1, 0, 0, 0, 0, -1, 0, -1, 0, 0, 0, 0, -1, 0, -1, 0, 0, 0, 0, -1, 0, -1, 1, '', 0, 0, 0, 0, 0, 1, 3, 0, 0, 0, 0, 105, 0, 0, 0, 0, 8, 0, 0, 0, 0, 0, 0, 0, 375, 0, 0, 0, 0, '', 68, 0, 0, 0, 0, 12340);
|
||||
|
||||
DELETE FROM `item_template` WHERE (`entry` = 20019143);
|
||||
INSERT INTO `item_template` (`entry`, `class`, `subclass`, `SoundOverrideSubclass`, `name`, `displayid`, `Quality`, `Flags`, `FlagsExtra`, `BuyCount`, `BuyPrice`, `SellPrice`, `InventoryType`, `AllowableClass`, `AllowableRace`, `ItemLevel`, `RequiredLevel`, `RequiredSkill`, `RequiredSkillRank`, `requiredspell`, `requiredhonorrank`, `RequiredCityRank`, `RequiredReputationFaction`, `RequiredReputationRank`, `maxcount`, `stackable`, `ContainerSlots`, `StatsCount`, `stat_type1`, `stat_value1`, `stat_type2`, `stat_value2`, `stat_type3`, `stat_value3`, `stat_type4`, `stat_value4`, `stat_type5`, `stat_value5`, `stat_type6`, `stat_value6`, `stat_type7`, `stat_value7`, `stat_type8`, `stat_value8`, `stat_type9`, `stat_value9`, `stat_type10`, `stat_value10`, `ScalingStatDistribution`, `ScalingStatValue`, `dmg_min1`, `dmg_max1`, `dmg_type1`, `dmg_min2`, `dmg_max2`, `dmg_type2`, `armor`, `holy_res`, `fire_res`, `nature_res`, `frost_res`, `shadow_res`, `arcane_res`, `delay`, `ammo_type`, `RangedModRange`, `spellid_1`, `spelltrigger_1`, `spellcharges_1`, `spellppmRate_1`, `spellcooldown_1`, `spellcategory_1`, `spellcategorycooldown_1`, `spellid_2`, `spelltrigger_2`, `spellcharges_2`, `spellppmRate_2`, `spellcooldown_2`, `spellcategory_2`, `spellcategorycooldown_2`, `spellid_3`, `spelltrigger_3`, `spellcharges_3`, `spellppmRate_3`, `spellcooldown_3`, `spellcategory_3`, `spellcategorycooldown_3`, `spellid_4`, `spelltrigger_4`, `spellcharges_4`, `spellppmRate_4`, `spellcooldown_4`, `spellcategory_4`, `spellcategorycooldown_4`, `spellid_5`, `spelltrigger_5`, `spellcharges_5`, `spellppmRate_5`, `spellcooldown_5`, `spellcategory_5`, `spellcategorycooldown_5`, `bonding`, `description`, `PageText`, `LanguageID`, `PageMaterial`, `startquest`, `lockid`, `Material`, `sheath`, `RandomProperty`, `RandomSuffix`, `block`, `itemset`, `MaxDurability`, `area`, `Map`, `BagFamily`, `TotemCategory`, `socketColor_1`, `socketContent_1`, `socketColor_2`, `socketContent_2`, `socketColor_3`, `socketContent_3`, `socketBonus`, `GemProperties`, `RequiredDisenchantSkill`, `ArmorDamageModifier`, `duration`, `ItemLimitCategory`, `HolidayId`, `ScriptName`, `DisenchantID`, `FoodType`, `minMoneyLoot`, `maxMoneyLoot`, `flagsCustom`, `VerifiedBuild`) VALUES
|
||||
(20019143, 4, 4, -1, 'Unyielding Flameguard Gauntlets', 31660, 4, 0, 0, 1, 135917, 380457, 10, -1, -1, 325, 85, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 5, 4, 280, 7, 393, 12, 37, 16, 74, 38, 114, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3780, 0, 31, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -1, 0, -1, 0, 0, 0, 0, -1, 0, -1, 0, 0, 0, 0, -1, 0, -1, 0, 0, 0, 0, -1, 0, -1, 0, 0, 0, 0, -1, 0, -1, 1, '', 0, 0, 0, 0, 0, 6, 0, 0, 0, 0, 0, 55, 0, 0, 0, 0, 2, 0, 0, 0, 0, 0, 0, 0, 375, 0, 0, 0, 0, '', 68, 0, 0, 0, 0, 12340);
|
||||
|
||||
DELETE FROM `item_template` WHERE (`entry` = 20017074);
|
||||
INSERT INTO `item_template` (`entry`, `class`, `subclass`, `SoundOverrideSubclass`, `name`, `displayid`, `Quality`, `Flags`, `FlagsExtra`, `BuyCount`, `BuyPrice`, `SellPrice`, `InventoryType`, `AllowableClass`, `AllowableRace`, `ItemLevel`, `RequiredLevel`, `RequiredSkill`, `RequiredSkillRank`, `requiredspell`, `requiredhonorrank`, `RequiredCityRank`, `RequiredReputationFaction`, `RequiredReputationRank`, `maxcount`, `stackable`, `ContainerSlots`, `StatsCount`, `stat_type1`, `stat_value1`, `stat_type2`, `stat_value2`, `stat_type3`, `stat_value3`, `stat_type4`, `stat_value4`, `stat_type5`, `stat_value5`, `stat_type6`, `stat_value6`, `stat_type7`, `stat_value7`, `stat_type8`, `stat_value8`, `stat_type9`, `stat_value9`, `stat_type10`, `stat_value10`, `ScalingStatDistribution`, `ScalingStatValue`, `dmg_min1`, `dmg_max1`, `dmg_type1`, `dmg_min2`, `dmg_max2`, `dmg_type2`, `armor`, `holy_res`, `fire_res`, `nature_res`, `frost_res`, `shadow_res`, `arcane_res`, `delay`, `ammo_type`, `RangedModRange`, `spellid_1`, `spelltrigger_1`, `spellcharges_1`, `spellppmRate_1`, `spellcooldown_1`, `spellcategory_1`, `spellcategorycooldown_1`, `spellid_2`, `spelltrigger_2`, `spellcharges_2`, `spellppmRate_2`, `spellcooldown_2`, `spellcategory_2`, `spellcategorycooldown_2`, `spellid_3`, `spelltrigger_3`, `spellcharges_3`, `spellppmRate_3`, `spellcooldown_3`, `spellcategory_3`, `spellcategorycooldown_3`, `spellid_4`, `spelltrigger_4`, `spellcharges_4`, `spellppmRate_4`, `spellcooldown_4`, `spellcategory_4`, `spellcategorycooldown_4`, `spellid_5`, `spelltrigger_5`, `spellcharges_5`, `spellppmRate_5`, `spellcooldown_5`, `spellcategory_5`, `spellcategorycooldown_5`, `bonding`, `description`, `PageText`, `LanguageID`, `PageMaterial`, `startquest`, `lockid`, `Material`, `sheath`, `RandomProperty`, `RandomSuffix`, `block`, `itemset`, `MaxDurability`, `area`, `Map`, `BagFamily`, `TotemCategory`, `socketColor_1`, `socketContent_1`, `socketColor_2`, `socketContent_2`, `socketColor_3`, `socketContent_3`, `socketBonus`, `GemProperties`, `RequiredDisenchantSkill`, `ArmorDamageModifier`, `duration`, `ItemLimitCategory`, `HolidayId`, `ScriptName`, `DisenchantID`, `FoodType`, `minMoneyLoot`, `maxMoneyLoot`, `flagsCustom`, `VerifiedBuild`) VALUES
|
||||
(20017074, 2, 6, -1, 'Mighty Shadowstrike', 29176, 4, 1088, 0, 1, 443341, 151858, 17, -1, -1, 325, 85, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 4, 38, 678, 7, 240, 32, 162, 4, 398, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1112, 1975, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3100, 0, 0, 0, 0, 0, 0, -1, 0, -1, 0, 0, 0, 0, -1, 0, -1, 0, 0, 0, 0, -1, 0, -1, 0, 0, 0, 0, -1, 0, -1, 0, 0, 0, 0, -1, 0, -1, 1, '', 0, 0, 0, 0, 0, 1, 2, 0, 0, 0, 0, 120, 0, 0, 0, 0, 2, 0, 8, 0, 0, 0, 0, 0, 375, 0, 0, 0, 0, '', 68, 0, 0, 0, 0, 12340);
|
||||
|
||||
DELETE FROM `item_template` WHERE (`entry` = 20017073);
|
||||
INSERT INTO `item_template` (`entry`, `class`, `subclass`, `SoundOverrideSubclass`, `name`, `displayid`, `Quality`, `Flags`, `FlagsExtra`, `BuyCount`, `BuyPrice`, `SellPrice`, `InventoryType`, `AllowableClass`, `AllowableRace`, `ItemLevel`, `RequiredLevel`, `RequiredSkill`, `RequiredSkillRank`, `requiredspell`, `requiredhonorrank`, `RequiredCityRank`, `RequiredReputationFaction`, `RequiredReputationRank`, `maxcount`, `stackable`, `ContainerSlots`, `StatsCount`, `stat_type1`, `stat_value1`, `stat_type2`, `stat_value2`, `stat_type3`, `stat_value3`, `stat_type4`, `stat_value4`, `stat_type5`, `stat_value5`, `stat_type6`, `stat_value6`, `stat_type7`, `stat_value7`, `stat_type8`, `stat_value8`, `stat_type9`, `stat_value9`, `stat_type10`, `stat_value10`, `ScalingStatDistribution`, `ScalingStatValue`, `dmg_min1`, `dmg_max1`, `dmg_type1`, `dmg_min2`, `dmg_max2`, `dmg_type2`, `armor`, `holy_res`, `fire_res`, `nature_res`, `frost_res`, `shadow_res`, `arcane_res`, `delay`, `ammo_type`, `RangedModRange`, `spellid_1`, `spelltrigger_1`, `spellcharges_1`, `spellppmRate_1`, `spellcooldown_1`, `spellcategory_1`, `spellcategorycooldown_1`, `spellid_2`, `spelltrigger_2`, `spellcharges_2`, `spellppmRate_2`, `spellcooldown_2`, `spellcategory_2`, `spellcategorycooldown_2`, `spellid_3`, `spelltrigger_3`, `spellcharges_3`, `spellppmRate_3`, `spellcooldown_3`, `spellcategory_3`, `spellcategorycooldown_3`, `spellid_4`, `spelltrigger_4`, `spellcharges_4`, `spellppmRate_4`, `spellcooldown_4`, `spellcategory_4`, `spellcategorycooldown_4`, `spellid_5`, `spelltrigger_5`, `spellcharges_5`, `spellppmRate_5`, `spellcooldown_5`, `spellcategory_5`, `spellcategorycooldown_5`, `bonding`, `description`, `PageText`, `LanguageID`, `PageMaterial`, `startquest`, `lockid`, `Material`, `sheath`, `RandomProperty`, `RandomSuffix`, `block`, `itemset`, `MaxDurability`, `area`, `Map`, `BagFamily`, `TotemCategory`, `socketColor_1`, `socketContent_1`, `socketColor_2`, `socketContent_2`, `socketColor_3`, `socketContent_3`, `socketBonus`, `GemProperties`, `RequiredDisenchantSkill`, `ArmorDamageModifier`, `duration`, `ItemLimitCategory`, `HolidayId`, `ScriptName`, `DisenchantID`, `FoodType`, `minMoneyLoot`, `maxMoneyLoot`, `flagsCustom`, `VerifiedBuild`) VALUES
|
||||
(20017073, 2, 5, -1, 'Powerful Earthshaker', 32162, 4, 0, 0, 1, 459518, 196365, 17, -1, -1, 325, 85, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 4, 4, 428, 7, 102, 31, 45, 38, 598, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1642, 1867, 0, 0, 0, 0, 0, 0, 0, 15, 0, 0, 0, 3500, 0, 0, 21152, 2, 0, 1, -1, 0, -1, 0, 0, 0, 0, -1, 0, -1, 0, 0, 0, 0, -1, 0, -1, 0, 0, 0, 0, -1, 0, -1, 0, 0, 0, 0, -1, 0, -1, 1, '', 0, 0, 0, 0, 0, 2, 1, 0, 0, 0, 0, 120, 0, 0, 0, 0, 2, 0, 4, 0, 8, 0, 0, 0, 375, 0, 0, 0, 0, '', 68, 0, 0, 0, 0, 12340);
|
||||
|
||||
DELETE FROM `item_template` WHERE (`entry` = 20018842);
|
||||
INSERT INTO `item_template` (`entry`, `class`, `subclass`, `SoundOverrideSubclass`, `name`, `displayid`, `Quality`, `Flags`, `FlagsExtra`, `BuyCount`, `BuyPrice`, `SellPrice`, `InventoryType`, `AllowableClass`, `AllowableRace`, `ItemLevel`, `RequiredLevel`, `RequiredSkill`, `RequiredSkillRank`, `requiredspell`, `requiredhonorrank`, `RequiredCityRank`, `RequiredReputationFaction`, `RequiredReputationRank`, `maxcount`, `stackable`, `ContainerSlots`, `StatsCount`, `stat_type1`, `stat_value1`, `stat_type2`, `stat_value2`, `stat_type3`, `stat_value3`, `stat_type4`, `stat_value4`, `stat_type5`, `stat_value5`, `stat_type6`, `stat_value6`, `stat_type7`, `stat_value7`, `stat_type8`, `stat_value8`, `stat_type9`, `stat_value9`, `stat_type10`, `stat_value10`, `ScalingStatDistribution`, `ScalingStatValue`, `dmg_min1`, `dmg_max1`, `dmg_type1`, `dmg_min2`, `dmg_max2`, `dmg_type2`, `armor`, `holy_res`, `fire_res`, `nature_res`, `frost_res`, `shadow_res`, `arcane_res`, `delay`, `ammo_type`, `RangedModRange`, `spellid_1`, `spelltrigger_1`, `spellcharges_1`, `spellppmRate_1`, `spellcooldown_1`, `spellcategory_1`, `spellcategorycooldown_1`, `spellid_2`, `spelltrigger_2`, `spellcharges_2`, `spellppmRate_2`, `spellcooldown_2`, `spellcategory_2`, `spellcategorycooldown_2`, `spellid_3`, `spelltrigger_3`, `spellcharges_3`, `spellppmRate_3`, `spellcooldown_3`, `spellcategory_3`, `spellcategorycooldown_3`, `spellid_4`, `spelltrigger_4`, `spellcharges_4`, `spellppmRate_4`, `spellcooldown_4`, `spellcategory_4`, `spellcategorycooldown_4`, `spellid_5`, `spelltrigger_5`, `spellcharges_5`, `spellppmRate_5`, `spellcooldown_5`, `spellcategory_5`, `spellcategorycooldown_5`, `bonding`, `description`, `PageText`, `LanguageID`, `PageMaterial`, `startquest`, `lockid`, `Material`, `sheath`, `RandomProperty`, `RandomSuffix`, `block`, `itemset`, `MaxDurability`, `area`, `Map`, `BagFamily`, `TotemCategory`, `socketColor_1`, `socketContent_1`, `socketColor_2`, `socketContent_2`, `socketColor_3`, `socketContent_3`, `socketBonus`, `GemProperties`, `RequiredDisenchantSkill`, `ArmorDamageModifier`, `duration`, `ItemLimitCategory`, `HolidayId`, `ScriptName`, `DisenchantID`, `FoodType`, `minMoneyLoot`, `maxMoneyLoot`, `flagsCustom`, `VerifiedBuild`) VALUES
|
||||
(20018842, 2, 10, -1, 'Unyielding Staff of Dominance', 34114, 4, 0, 0, 1, 485061, 380470, 17, -1, -1, 325, 85, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 5, 31, 42, 45, 1689, 7, 247, 5, 340, 32, 145, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 520, 1145, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2900, 0, 0, 0, 0, 0, 0, -1, 0, -1, 0, 0, 0, 0, -1, 0, -1, 0, 0, 0, 0, -1, 0, -1, 0, 0, 0, 0, -1, 0, -1, 0, 0, 0, 0, -1, 0, -1, 1, '', 0, 0, 0, 0, 0, 2, 2, 0, 0, 0, 0, 120, 0, 0, 0, 0, 2, 0, 2, 0, 0, 0, 0, 0, 375, -10, 0, 0, 0, '', 68, 0, 0, 0, 0, 12340);
|
||||
|
||||
DELETE FROM `item_template` WHERE (`entry` = 20016826);
|
||||
INSERT INTO `item_template` (`entry`, `class`, `subclass`, `SoundOverrideSubclass`, `name`, `displayid`, `Quality`, `Flags`, `FlagsExtra`, `BuyCount`, `BuyPrice`, `SellPrice`, `InventoryType`, `AllowableClass`, `AllowableRace`, `ItemLevel`, `RequiredLevel`, `RequiredSkill`, `RequiredSkillRank`, `requiredspell`, `requiredhonorrank`, `RequiredCityRank`, `RequiredReputationFaction`, `RequiredReputationRank`, `maxcount`, `stackable`, `ContainerSlots`, `StatsCount`, `stat_type1`, `stat_value1`, `stat_type2`, `stat_value2`, `stat_type3`, `stat_value3`, `stat_type4`, `stat_value4`, `stat_type5`, `stat_value5`, `stat_type6`, `stat_value6`, `stat_type7`, `stat_value7`, `stat_type8`, `stat_value8`, `stat_type9`, `stat_value9`, `stat_type10`, `stat_value10`, `ScalingStatDistribution`, `ScalingStatValue`, `dmg_min1`, `dmg_max1`, `dmg_type1`, `dmg_min2`, `dmg_max2`, `dmg_type2`, `armor`, `holy_res`, `fire_res`, `nature_res`, `frost_res`, `shadow_res`, `arcane_res`, `delay`, `ammo_type`, `RangedModRange`, `spellid_1`, `spelltrigger_1`, `spellcharges_1`, `spellppmRate_1`, `spellcooldown_1`, `spellcategory_1`, `spellcategorycooldown_1`, `spellid_2`, `spelltrigger_2`, `spellcharges_2`, `spellppmRate_2`, `spellcooldown_2`, `spellcategory_2`, `spellcategorycooldown_2`, `spellid_3`, `spelltrigger_3`, `spellcharges_3`, `spellppmRate_3`, `spellcooldown_3`, `spellcategory_3`, `spellcategorycooldown_3`, `spellid_4`, `spelltrigger_4`, `spellcharges_4`, `spellppmRate_4`, `spellcooldown_4`, `spellcategory_4`, `spellcategorycooldown_4`, `spellid_5`, `spelltrigger_5`, `spellcharges_5`, `spellppmRate_5`, `spellcooldown_5`, `spellcategory_5`, `spellcategorycooldown_5`, `bonding`, `description`, `PageText`, `LanguageID`, `PageMaterial`, `startquest`, `lockid`, `Material`, `sheath`, `RandomProperty`, `RandomSuffix`, `block`, `itemset`, `MaxDurability`, `area`, `Map`, `BagFamily`, `TotemCategory`, `socketColor_1`, `socketContent_1`, `socketColor_2`, `socketContent_2`, `socketColor_3`, `socketContent_3`, `socketBonus`, `GemProperties`, `RequiredDisenchantSkill`, `ArmorDamageModifier`, `duration`, `ItemLimitCategory`, `HolidayId`, `ScriptName`, `DisenchantID`, `FoodType`, `minMoneyLoot`, `maxMoneyLoot`, `flagsCustom`, `VerifiedBuild`) VALUES
|
||||
(20016826, 4, 2, -1, 'Powerful Nightslayer Gloves', 31503, 4, 0, 0, 1, 89199, 285885, 10, 8, -1, 325, 85, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 5, 13, 89, 31, 32, 38, 268, 7, 215, 3, 312, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1350, 0, 21, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -1, 0, -1, 0, 0, 0, 0, -1, 0, -1, 0, 0, 0, 0, -1, 0, -1, 0, 0, 0, 0, -1, 0, -1, 0, 0, 0, 0, -1, 0, -1, 1, '', 0, 0, 0, 0, 0, 8, 0, 0, 0, 0, 204, 65, 0, 0, 0, 0, 8, 0, 4, 0, 0, 0, 0, 0, 375, 0, 0, 0, 0, '', 68, 0, 0, 0, 0, 12340);
|
||||
|
||||
DELETE FROM `item_template` WHERE (`entry` = 20017077);
|
||||
INSERT INTO `item_template` (`entry`, `class`, `subclass`, `SoundOverrideSubclass`, `name`, `displayid`, `Quality`, `Flags`, `FlagsExtra`, `BuyCount`, `BuyPrice`, `SellPrice`, `InventoryType`, `AllowableClass`, `AllowableRace`, `ItemLevel`, `RequiredLevel`, `RequiredSkill`, `RequiredSkillRank`, `requiredspell`, `requiredhonorrank`, `RequiredCityRank`, `RequiredReputationFaction`, `RequiredReputationRank`, `maxcount`, `stackable`, `ContainerSlots`, `StatsCount`, `stat_type1`, `stat_value1`, `stat_type2`, `stat_value2`, `stat_type3`, `stat_value3`, `stat_type4`, `stat_value4`, `stat_type5`, `stat_value5`, `stat_type6`, `stat_value6`, `stat_type7`, `stat_value7`, `stat_type8`, `stat_value8`, `stat_type9`, `stat_value9`, `stat_type10`, `stat_value10`, `ScalingStatDistribution`, `ScalingStatValue`, `dmg_min1`, `dmg_max1`, `dmg_type1`, `dmg_min2`, `dmg_max2`, `dmg_type2`, `armor`, `holy_res`, `fire_res`, `nature_res`, `frost_res`, `shadow_res`, `arcane_res`, `delay`, `ammo_type`, `RangedModRange`, `spellid_1`, `spelltrigger_1`, `spellcharges_1`, `spellppmRate_1`, `spellcooldown_1`, `spellcategory_1`, `spellcategorycooldown_1`, `spellid_2`, `spelltrigger_2`, `spellcharges_2`, `spellppmRate_2`, `spellcooldown_2`, `spellcategory_2`, `spellcategorycooldown_2`, `spellid_3`, `spelltrigger_3`, `spellcharges_3`, `spellppmRate_3`, `spellcooldown_3`, `spellcategory_3`, `spellcategorycooldown_3`, `spellid_4`, `spelltrigger_4`, `spellcharges_4`, `spellppmRate_4`, `spellcooldown_4`, `spellcategory_4`, `spellcategorycooldown_4`, `spellid_5`, `spelltrigger_5`, `spellcharges_5`, `spellppmRate_5`, `spellcooldown_5`, `spellcategory_5`, `spellcategorycooldown_5`, `bonding`, `description`, `PageText`, `LanguageID`, `PageMaterial`, `startquest`, `lockid`, `Material`, `sheath`, `RandomProperty`, `RandomSuffix`, `block`, `itemset`, `MaxDurability`, `area`, `Map`, `BagFamily`, `TotemCategory`, `socketColor_1`, `socketContent_1`, `socketColor_2`, `socketContent_2`, `socketColor_3`, `socketContent_3`, `socketBonus`, `GemProperties`, `RequiredDisenchantSkill`, `ArmorDamageModifier`, `duration`, `ItemLimitCategory`, `HolidayId`, `ScriptName`, `DisenchantID`, `FoodType`, `minMoneyLoot`, `maxMoneyLoot`, `flagsCustom`, `VerifiedBuild`) VALUES
|
||||
(20017077, 2, 19, -1, 'Mythic Crimson Shocker', 29195, 4, 0, 0, 1, 268855, 266465, 26, -1, -1, 325, 85, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 4, 5, 179, 7, 256, 6, 145, 36, 62, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 415, 814, 2, 0, 0, 0, 0, 0, 15, 0, 0, 0, 0, 2000, 0, 100, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -1, 0, -1, 0, 0, 0, 0, -1, 0, -1, 0, 0, 0, 0, -1, 0, -1, 0, 0, 0, 0, -1, 0, -1, 1, '', 0, 0, 0, 0, 0, 2, 0, 0, 0, 0, 0, 75, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 375, 0, 0, 0, 0, '', 68, 0, 0, 0, 0, 12340);
|
||||
981
cmd/raid-gear/gear.output
Normal file
981
cmd/raid-gear/gear.output
Normal file
@@ -0,0 +1,981 @@
|
||||
<<<< Items to Process: 88 >>>>>
|
||||
Item: Felheart Gloves Entry: 16805 lookup up Class: 4 Subclass: 1
|
||||
<<<< High Level Items that match class Type: Healer 18 >>>>>
|
||||
New Item: Felheart Gloves Entry: 16805
|
||||
ItemStat1: Type: 5 (INTELLECT) Value: 321
|
||||
ItemStat2: Type: 6 (SPIRIT) Value: 174
|
||||
ItemStat3: Type: 7 (STAMINA) Value: 422
|
||||
ItemStat4: Type: 32 (CRIT_RATING) Value: 172
|
||||
ItemStat5: Type: 45 (SPELL_POWER) Value: 155
|
||||
ItemStat6: Type: 0 (MANA) Value: 0
|
||||
ItemStat7: Type: 0 (MANA) Value: 0
|
||||
ItemStat8: Type: 0 (MANA) Value: 0
|
||||
Item: Gauntlets of Might Entry: 16863 lookup up Class: 4 Subclass: 4
|
||||
<<<< High Level Items that match class Type: Tank 5 >>>>>
|
||||
New Item: Gauntlets of Might Entry: 16863
|
||||
ItemStat1: Type: 7 (STAMINA) Value: 407
|
||||
ItemStat2: Type: 4 (STRENGTH) Value: 481
|
||||
ItemStat3: Type: 31 (HIT_RATING) Value: 62
|
||||
ItemStat4: Type: 12 (DEFENSE_SKILL_RATING) Value: 63
|
||||
ItemStat5: Type: 0 (MANA) Value: 0
|
||||
ItemStat6: Type: 0 (MANA) Value: 0
|
||||
ItemStat7: Type: 0 (MANA) Value: 0
|
||||
ItemStat8: Type: 0 (MANA) Value: 0
|
||||
Item: Crimson Shocker Entry: 17077 lookup up Class: 2 Subclass: 19
|
||||
<<<< High Level Items that match class Type: Mage 1 >>>>>
|
||||
New Item: Crimson Shocker Entry: 17077
|
||||
ItemStat1: Type: 5 (INTELLECT) Value: 228
|
||||
ItemStat2: Type: 0 (MANA) Value: 0
|
||||
ItemStat3: Type: 0 (MANA) Value: 0
|
||||
ItemStat4: Type: 0 (MANA) Value: 0
|
||||
ItemStat5: Type: 0 (MANA) Value: 0
|
||||
ItemStat6: Type: 0 (MANA) Value: 0
|
||||
ItemStat7: Type: 0 (MANA) Value: 0
|
||||
ItemStat8: Type: 0 (MANA) Value: 0
|
||||
[32mFire Resistance Applied: Crimson Shocker gets 10 fire resistance (modifier: 0.32)[0m
|
||||
Item: Flamewaker Legplates Entry: 18861 lookup up Class: 4 Subclass: 4
|
||||
<<<< High Level Items that match class Type: Strength Melee 6 >>>>>
|
||||
New Item: Flamewaker Legplates Entry: 18861
|
||||
ItemStat1: Type: 7 (STAMINA) Value: 584
|
||||
ItemStat2: Type: 4 (STRENGTH) Value: 431
|
||||
ItemStat3: Type: 13 (DODGE_RATING) Value: 95
|
||||
ItemStat4: Type: 0 (MANA) Value: 0
|
||||
ItemStat5: Type: 0 (MANA) Value: 0
|
||||
ItemStat6: Type: 0 (MANA) Value: 0
|
||||
ItemStat7: Type: 0 (MANA) Value: 0
|
||||
ItemStat8: Type: 0 (MANA) Value: 0
|
||||
[32mFire Resistance Applied: Flamewaker Legplates gets 22 fire resistance (modifier: 0.88)[0m
|
||||
Item: Helm of the Lifegiver Entry: 18870 lookup up Class: 4 Subclass: 3
|
||||
<<<< High Level Items that match class Type: Healer 7 >>>>>
|
||||
New Item: Helm of the Lifegiver Entry: 18870
|
||||
ItemStat1: Type: 5 (INTELLECT) Value: 713
|
||||
ItemStat2: Type: 7 (STAMINA) Value: 365
|
||||
ItemStat3: Type: 6 (SPIRIT) Value: 204
|
||||
ItemStat4: Type: 45 (SPELL_POWER) Value: 415
|
||||
ItemStat5: Type: 0 (MANA) Value: 0
|
||||
ItemStat6: Type: 0 (MANA) Value: 0
|
||||
ItemStat7: Type: 0 (MANA) Value: 0
|
||||
ItemStat8: Type: 0 (MANA) Value: 0
|
||||
Item: Manastorm Leggings Entry: 18872 lookup up Class: 4 Subclass: 1
|
||||
<<<< High Level Items that match class Type: Healer 18 >>>>>
|
||||
New Item: Manastorm Leggings Entry: 18872
|
||||
ItemStat1: Type: 43 (MANA_REGENERATION) Value: 200
|
||||
ItemStat2: Type: 7 (STAMINA) Value: 481
|
||||
ItemStat3: Type: 5 (INTELLECT) Value: 328
|
||||
ItemStat4: Type: 0 (MANA) Value: 0
|
||||
ItemStat5: Type: 0 (MANA) Value: 0
|
||||
ItemStat6: Type: 0 (MANA) Value: 0
|
||||
ItemStat7: Type: 0 (MANA) Value: 0
|
||||
ItemStat8: Type: 0 (MANA) Value: 0
|
||||
Item: Salamander Scale Pants Entry: 18875 lookup up Class: 4 Subclass: 2
|
||||
<<<< High Level Items that match class Type: Healer 8 >>>>>
|
||||
New Item: Salamander Scale Pants Entry: 18875
|
||||
ItemStat1: Type: 5 (INTELLECT) Value: 321
|
||||
ItemStat2: Type: 7 (STAMINA) Value: 349
|
||||
ItemStat3: Type: 45 (SPELL_POWER) Value: 486
|
||||
ItemStat4: Type: 43 (MANA_REGENERATION) Value: 120
|
||||
ItemStat5: Type: 0 (MANA) Value: 0
|
||||
ItemStat6: Type: 0 (MANA) Value: 0
|
||||
ItemStat7: Type: 0 (MANA) Value: 0
|
||||
ItemStat8: Type: 0 (MANA) Value: 0
|
||||
Item: Sorcerous Dagger Entry: 18878 lookup up Class: 2 Subclass: 15
|
||||
<<<< High Level Items that match class Type: Mage 1 >>>>>
|
||||
New Item: Sorcerous Dagger Entry: 18878
|
||||
ItemStat1: Type: 5 (INTELLECT) Value: 382
|
||||
ItemStat2: Type: 7 (STAMINA) Value: 193
|
||||
ItemStat3: Type: 45 (SPELL_POWER) Value: 352
|
||||
ItemStat4: Type: 0 (MANA) Value: 0
|
||||
ItemStat5: Type: 0 (MANA) Value: 0
|
||||
ItemStat6: Type: 0 (MANA) Value: 0
|
||||
ItemStat7: Type: 0 (MANA) Value: 0
|
||||
ItemStat8: Type: 0 (MANA) Value: 0
|
||||
Item: Heavy Dark Iron Ring Entry: 18879 lookup up Class: 4 Subclass: 0
|
||||
<<<< High Level Items that match class Type: Tank 3 >>>>>
|
||||
New Item: Heavy Dark Iron Ring Entry: 18879
|
||||
ItemStat1: Type: 7 (STAMINA) Value: 480
|
||||
ItemStat2: Type: 12 (DEFENSE_SKILL_RATING) Value: 63
|
||||
ItemStat3: Type: 0 (MANA) Value: 0
|
||||
ItemStat4: Type: 0 (MANA) Value: 0
|
||||
ItemStat5: Type: 0 (MANA) Value: 0
|
||||
ItemStat6: Type: 0 (MANA) Value: 0
|
||||
ItemStat7: Type: 0 (MANA) Value: 0
|
||||
ItemStat8: Type: 0 (MANA) Value: 0
|
||||
Item: Robe of Volatile Power Entry: 19145 lookup up Class: 4 Subclass: 1
|
||||
<<<< High Level Items that match class Type: Healer 18 >>>>>
|
||||
New Item: Robe of Volatile Power Entry: 19145
|
||||
ItemStat1: Type: 5 (INTELLECT) Value: 321
|
||||
ItemStat2: Type: 7 (STAMINA) Value: 233
|
||||
ItemStat3: Type: 6 (SPIRIT) Value: 214
|
||||
ItemStat4: Type: 32 (CRIT_RATING) Value: 566
|
||||
ItemStat5: Type: 45 (SPELL_POWER) Value: 395
|
||||
ItemStat6: Type: 0 (MANA) Value: 0
|
||||
ItemStat7: Type: 0 (MANA) Value: 0
|
||||
ItemStat8: Type: 0 (MANA) Value: 0
|
||||
Item: Wristguards of Stability Entry: 19146 lookup up Class: 4 Subclass: 2
|
||||
<<<< High Level Items that match class Type: Strength Melee 0 >>>>>
|
||||
[31mItem: Wristguards of Stability Entry: 19146 has no high level items HAS TO BE SCALED MANUALLY[0m
|
||||
ItemStat1: Type: 4 (STRENGTH) Value: 532
|
||||
ItemStat2: Type: 7 (STAMINA) Value: 193
|
||||
ItemStat3: Type: 0 (MANA) Value: 0
|
||||
ItemStat4: Type: 0 (MANA) Value: 0
|
||||
ItemStat5: Type: 0 (MANA) Value: 0
|
||||
ItemStat6: Type: 0 (MANA) Value: 0
|
||||
ItemStat7: Type: 0 (MANA) Value: 0
|
||||
ItemStat8: Type: 0 (MANA) Value: 0
|
||||
Item: Ring of Spell Power Entry: 19147 lookup up Class: 4 Subclass: 0
|
||||
<<<< High Level Items that match class Type: Mage 7 >>>>>
|
||||
New Item: Ring of Spell Power Entry: 19147
|
||||
ItemStat1: Type: 45 (SPELL_POWER) Value: 567
|
||||
ItemStat2: Type: 0 (MANA) Value: 0
|
||||
ItemStat3: Type: 0 (MANA) Value: 0
|
||||
ItemStat4: Type: 0 (MANA) Value: 0
|
||||
ItemStat5: Type: 0 (MANA) Value: 0
|
||||
ItemStat6: Type: 0 (MANA) Value: 0
|
||||
ItemStat7: Type: 0 (MANA) Value: 0
|
||||
ItemStat8: Type: 0 (MANA) Value: 0
|
||||
Item: Arcanist Boots Entry: 16800 lookup up Class: 4 Subclass: 1
|
||||
<<<< High Level Items that match class Type: Healer 18 >>>>>
|
||||
New Item: Arcanist Boots Entry: 16800
|
||||
ItemStat1: Type: 7 (STAMINA) Value: 305
|
||||
ItemStat2: Type: 5 (INTELLECT) Value: 308
|
||||
ItemStat3: Type: 6 (SPIRIT) Value: 241
|
||||
ItemStat4: Type: 32 (CRIT_RATING) Value: 172
|
||||
ItemStat5: Type: 45 (SPELL_POWER) Value: 189
|
||||
ItemStat6: Type: 0 (MANA) Value: 0
|
||||
ItemStat7: Type: 0 (MANA) Value: 0
|
||||
ItemStat8: Type: 0 (MANA) Value: 0
|
||||
Item: Cenarion Boots Entry: 16829 lookup up Class: 4 Subclass: 2
|
||||
<<<< High Level Items that match class Type: Healer 8 >>>>>
|
||||
New Item: Cenarion Boots Entry: 16829
|
||||
ItemStat1: Type: 6 (SPIRIT) Value: 321
|
||||
ItemStat2: Type: 7 (STAMINA) Value: 378
|
||||
ItemStat3: Type: 43 (MANA_REGENERATION) Value: 43
|
||||
ItemStat4: Type: 45 (SPELL_POWER) Value: 155
|
||||
ItemStat5: Type: 5 (INTELLECT) Value: 281
|
||||
ItemStat6: Type: 0 (MANA) Value: 0
|
||||
ItemStat7: Type: 0 (MANA) Value: 0
|
||||
ItemStat8: Type: 0 (MANA) Value: 0
|
||||
Item: Earthfury Boots Entry: 16837 lookup up Class: 4 Subclass: 3
|
||||
<<<< High Level Items that match class Type: Healer 7 >>>>>
|
||||
New Item: Earthfury Boots Entry: 16837
|
||||
ItemStat1: Type: 5 (INTELLECT) Value: 214
|
||||
ItemStat2: Type: 6 (SPIRIT) Value: 481
|
||||
ItemStat3: Type: 7 (STAMINA) Value: 349
|
||||
ItemStat4: Type: 45 (SPELL_POWER) Value: 155
|
||||
ItemStat5: Type: 0 (MANA) Value: 0
|
||||
ItemStat6: Type: 0 (MANA) Value: 0
|
||||
ItemStat7: Type: 0 (MANA) Value: 0
|
||||
ItemStat8: Type: 0 (MANA) Value: 0
|
||||
Item: Lawbringer Boots Entry: 16859 lookup up Class: 4 Subclass: 4
|
||||
<<<< High Level Items that match class Type: Healer 7 >>>>>
|
||||
New Item: Lawbringer Boots Entry: 16859
|
||||
ItemStat1: Type: 45 (SPELL_POWER) Value: 155
|
||||
ItemStat2: Type: 5 (INTELLECT) Value: 281
|
||||
ItemStat3: Type: 6 (SPIRIT) Value: 214
|
||||
ItemStat4: Type: 7 (STAMINA) Value: 480
|
||||
ItemStat5: Type: 4 (STRENGTH) Value: 147
|
||||
ItemStat6: Type: 43 (MANA_REGENERATION) Value: 31
|
||||
ItemStat7: Type: 0 (MANA) Value: 0
|
||||
ItemStat8: Type: 0 (MANA) Value: 0
|
||||
Item: Choker of Enlightenment Entry: 17109 lookup up Class: 4 Subclass: 0
|
||||
<<<< High Level Items that match class Type: Healer 5 >>>>>
|
||||
New Item: Choker of Enlightenment Entry: 17109
|
||||
ItemStat1: Type: 5 (INTELLECT) Value: 219
|
||||
ItemStat2: Type: 6 (SPIRIT) Value: 219
|
||||
ItemStat3: Type: 7 (STAMINA) Value: 208
|
||||
ItemStat4: Type: 45 (SPELL_POWER) Value: 317
|
||||
ItemStat5: Type: 0 (MANA) Value: 0
|
||||
ItemStat6: Type: 0 (MANA) Value: 0
|
||||
ItemStat7: Type: 0 (MANA) Value: 0
|
||||
ItemStat8: Type: 0 (MANA) Value: 0
|
||||
Item: Felheart Slippers Entry: 16803 lookup up Class: 4 Subclass: 1
|
||||
<<<< High Level Items that match class Type: Mage 1 >>>>>
|
||||
New Item: Felheart Slippers Entry: 16803
|
||||
ItemStat1: Type: 7 (STAMINA) Value: 538
|
||||
ItemStat2: Type: 45 (SPELL_POWER) Value: 309
|
||||
ItemStat3: Type: 5 (INTELLECT) Value: 241
|
||||
ItemStat4: Type: 0 (MANA) Value: 0
|
||||
ItemStat5: Type: 0 (MANA) Value: 0
|
||||
ItemStat6: Type: 0 (MANA) Value: 0
|
||||
ItemStat7: Type: 0 (MANA) Value: 0
|
||||
ItemStat8: Type: 0 (MANA) Value: 0
|
||||
Item: Boots of Prophecy Entry: 16811 lookup up Class: 4 Subclass: 1
|
||||
<<<< High Level Items that match class Type: Healer 18 >>>>>
|
||||
New Item: Boots of Prophecy Entry: 16811
|
||||
ItemStat1: Type: 5 (INTELLECT) Value: 388
|
||||
ItemStat2: Type: 6 (SPIRIT) Value: 321
|
||||
ItemStat3: Type: 7 (STAMINA) Value: 407
|
||||
ItemStat4: Type: 45 (SPELL_POWER) Value: 155
|
||||
ItemStat5: Type: 0 (MANA) Value: 0
|
||||
ItemStat6: Type: 0 (MANA) Value: 0
|
||||
ItemStat7: Type: 0 (MANA) Value: 0
|
||||
ItemStat8: Type: 0 (MANA) Value: 0
|
||||
Item: Nightslayer Boots Entry: 16824 lookup up Class: 4 Subclass: 2
|
||||
<<<< High Level Items that match class Type: Agility Melee 9 >>>>>
|
||||
New Item: Nightslayer Boots Entry: 16824
|
||||
ItemStat1: Type: 3 (AGILITY) Value: 561
|
||||
ItemStat2: Type: 7 (STAMINA) Value: 422
|
||||
ItemStat3: Type: 0 (MANA) Value: 0
|
||||
ItemStat4: Type: 0 (MANA) Value: 0
|
||||
ItemStat5: Type: 0 (MANA) Value: 0
|
||||
ItemStat6: Type: 0 (MANA) Value: 0
|
||||
ItemStat7: Type: 0 (MANA) Value: 0
|
||||
ItemStat8: Type: 0 (MANA) Value: 0
|
||||
Item: Arcanist Gloves Entry: 16801 lookup up Class: 4 Subclass: 1
|
||||
<<<< High Level Items that match class Type: Healer 18 >>>>>
|
||||
New Item: Arcanist Gloves Entry: 16801
|
||||
ItemStat1: Type: 5 (INTELLECT) Value: 321
|
||||
ItemStat2: Type: 6 (SPIRIT) Value: 214
|
||||
ItemStat3: Type: 7 (STAMINA) Value: 334
|
||||
ItemStat4: Type: 43 (MANA_REGENERATION) Value: 53
|
||||
ItemStat5: Type: 45 (SPELL_POWER) Value: 241
|
||||
ItemStat6: Type: 0 (MANA) Value: 0
|
||||
ItemStat7: Type: 0 (MANA) Value: 0
|
||||
ItemStat8: Type: 0 (MANA) Value: 0
|
||||
Item: Cenarion Gloves Entry: 16831 lookup up Class: 4 Subclass: 2
|
||||
<<<< High Level Items that match class Type: Healer 8 >>>>>
|
||||
New Item: Cenarion Gloves Entry: 16831
|
||||
ItemStat1: Type: 5 (INTELLECT) Value: 388
|
||||
ItemStat2: Type: 6 (SPIRIT) Value: 321
|
||||
ItemStat3: Type: 7 (STAMINA) Value: 407
|
||||
ItemStat4: Type: 45 (SPELL_POWER) Value: 155
|
||||
ItemStat5: Type: 0 (MANA) Value: 0
|
||||
ItemStat6: Type: 0 (MANA) Value: 0
|
||||
ItemStat7: Type: 0 (MANA) Value: 0
|
||||
ItemStat8: Type: 0 (MANA) Value: 0
|
||||
Item: Giantstalker's Gloves Entry: 16852 lookup up Class: 4 Subclass: 3
|
||||
<<<< High Level Items that match class Type: Agility Melee 0 >>>>>
|
||||
[31mItem: Giantstalker's Gloves Entry: 16852 has no high level items HAS TO BE SCALED MANUALLY[0m
|
||||
ItemStat1: Type: 3 (AGILITY) Value: 254
|
||||
ItemStat2: Type: 7 (STAMINA) Value: 276
|
||||
ItemStat3: Type: 31 (HIT_RATING) Value: 125
|
||||
ItemStat4: Type: 38 (ATTACK_POWER) Value: 412
|
||||
ItemStat5: Type: 0 (MANA) Value: 0
|
||||
ItemStat6: Type: 0 (MANA) Value: 0
|
||||
ItemStat7: Type: 0 (MANA) Value: 0
|
||||
ItemStat8: Type: 0 (MANA) Value: 0
|
||||
Item: Cenarion Helm Entry: 16834 lookup up Class: 4 Subclass: 2
|
||||
<<<< High Level Items that match class Type: Healer 8 >>>>>
|
||||
New Item: Cenarion Helm Entry: 16834
|
||||
ItemStat1: Type: 5 (INTELLECT) Value: 615
|
||||
ItemStat2: Type: 6 (SPIRIT) Value: 281
|
||||
ItemStat3: Type: 7 (STAMINA) Value: 610
|
||||
ItemStat4: Type: 45 (SPELL_POWER) Value: 206
|
||||
ItemStat5: Type: 0 (MANA) Value: 0
|
||||
ItemStat6: Type: 0 (MANA) Value: 0
|
||||
ItemStat7: Type: 0 (MANA) Value: 0
|
||||
ItemStat8: Type: 0 (MANA) Value: 0
|
||||
Item: Earthfury Helmet Entry: 16842 lookup up Class: 4 Subclass: 3
|
||||
<<<< High Level Items that match class Type: Healer 7 >>>>>
|
||||
New Item: Earthfury Helmet Entry: 16842
|
||||
ItemStat1: Type: 5 (INTELLECT) Value: 495
|
||||
ItemStat2: Type: 6 (SPIRIT) Value: 281
|
||||
ItemStat3: Type: 7 (STAMINA) Value: 567
|
||||
ItemStat4: Type: 43 (MANA_REGENERATION) Value: 84
|
||||
ItemStat5: Type: 45 (SPELL_POWER) Value: 206
|
||||
ItemStat6: Type: 0 (MANA) Value: 0
|
||||
ItemStat7: Type: 0 (MANA) Value: 0
|
||||
ItemStat8: Type: 0 (MANA) Value: 0
|
||||
Item: Giantstalker's Helmet Entry: 16846 lookup up Class: 4 Subclass: 3
|
||||
<<<< High Level Items that match class Type: Healer 7 >>>>>
|
||||
New Item: Giantstalker's Helmet Entry: 16846
|
||||
ItemStat1: Type: 3 (AGILITY) Value: 348
|
||||
ItemStat2: Type: 5 (INTELLECT) Value: 321
|
||||
ItemStat3: Type: 6 (SPIRIT) Value: 174
|
||||
ItemStat4: Type: 7 (STAMINA) Value: 538
|
||||
ItemStat5: Type: 32 (CRIT_RATING) Value: 172
|
||||
ItemStat6: Type: 38 (ATTACK_POWER) Value: 515
|
||||
ItemStat7: Type: 0 (MANA) Value: 0
|
||||
ItemStat8: Type: 0 (MANA) Value: 0
|
||||
Item: Lawbringer Helm Entry: 16854 lookup up Class: 4 Subclass: 4
|
||||
<<<< High Level Items that match class Type: Healer 7 >>>>>
|
||||
New Item: Lawbringer Helm Entry: 16854
|
||||
ItemStat1: Type: 45 (SPELL_POWER) Value: 206
|
||||
ItemStat2: Type: 5 (INTELLECT) Value: 521
|
||||
ItemStat3: Type: 6 (SPIRIT) Value: 214
|
||||
ItemStat4: Type: 7 (STAMINA) Value: 480
|
||||
ItemStat5: Type: 4 (STRENGTH) Value: 187
|
||||
ItemStat6: Type: 43 (MANA_REGENERATION) Value: 53
|
||||
ItemStat7: Type: 0 (MANA) Value: 0
|
||||
ItemStat8: Type: 0 (MANA) Value: 0
|
||||
Item: Helm of Might Entry: 16866 lookup up Class: 4 Subclass: 4
|
||||
<<<< High Level Items that match class Type: Tank 5 >>>>>
|
||||
New Item: Helm of Might Entry: 16866
|
||||
ItemStat1: Type: 7 (STAMINA) Value: 828
|
||||
ItemStat2: Type: 4 (STRENGTH) Value: 321
|
||||
ItemStat3: Type: 13 (DODGE_RATING) Value: 86
|
||||
ItemStat4: Type: 12 (DEFENSE_SKILL_RATING) Value: 79
|
||||
ItemStat5: Type: 0 (MANA) Value: 0
|
||||
ItemStat6: Type: 0 (MANA) Value: 0
|
||||
ItemStat7: Type: 0 (MANA) Value: 0
|
||||
ItemStat8: Type: 0 (MANA) Value: 0
|
||||
Item: Drillborer Disk Entry: 17066 lookup up Class: 4 Subclass: 6
|
||||
<<<< High Level Items that match class Type: Tank 1 >>>>>
|
||||
New Item: Drillborer Disk Entry: 17066
|
||||
ItemStat1: Type: 7 (STAMINA) Value: 228
|
||||
ItemStat2: Type: 15 (BLOCK_RATING) Value: 103
|
||||
ItemStat3: Type: 0 (MANA) Value: 0
|
||||
ItemStat4: Type: 0 (MANA) Value: 0
|
||||
ItemStat5: Type: 0 (MANA) Value: 0
|
||||
ItemStat6: Type: 0 (MANA) Value: 0
|
||||
ItemStat7: Type: 0 (MANA) Value: 0
|
||||
ItemStat8: Type: 0 (MANA) Value: 0
|
||||
Item: Arcanist Crown Entry: 16795 lookup up Class: 4 Subclass: 1
|
||||
<<<< High Level Items that match class Type: Healer 18 >>>>>
|
||||
New Item: Arcanist Crown Entry: 16795
|
||||
ItemStat1: Type: 6 (SPIRIT) Value: 214
|
||||
ItemStat2: Type: 45 (SPELL_POWER) Value: 344
|
||||
ItemStat3: Type: 31 (HIT_RATING) Value: 50
|
||||
ItemStat4: Type: 7 (STAMINA) Value: 378
|
||||
ItemStat5: Type: 5 (INTELLECT) Value: 588
|
||||
ItemStat6: Type: 0 (MANA) Value: 0
|
||||
ItemStat7: Type: 0 (MANA) Value: 0
|
||||
ItemStat8: Type: 0 (MANA) Value: 0
|
||||
Item: Felheart Horns Entry: 16808 lookup up Class: 4 Subclass: 1
|
||||
<<<< High Level Items that match class Type: Healer 18 >>>>>
|
||||
New Item: Felheart Horns Entry: 16808
|
||||
ItemStat1: Type: 5 (INTELLECT) Value: 441
|
||||
ItemStat2: Type: 6 (SPIRIT) Value: 214
|
||||
ItemStat3: Type: 7 (STAMINA) Value: 639
|
||||
ItemStat4: Type: 45 (SPELL_POWER) Value: 344
|
||||
ItemStat5: Type: 0 (MANA) Value: 0
|
||||
ItemStat6: Type: 0 (MANA) Value: 0
|
||||
ItemStat7: Type: 0 (MANA) Value: 0
|
||||
ItemStat8: Type: 0 (MANA) Value: 0
|
||||
[33mMana Regen Capped: Felheart Horns mana regen reduced to 60[0m
|
||||
Item: Circlet of Prophecy Entry: 16813 lookup up Class: 4 Subclass: 1
|
||||
<<<< High Level Items that match class Type: Healer 18 >>>>>
|
||||
New Item: Circlet of Prophecy Entry: 16813
|
||||
ItemStat1: Type: 5 (INTELLECT) Value: 588
|
||||
ItemStat2: Type: 6 (SPIRIT) Value: 441
|
||||
ItemStat3: Type: 7 (STAMINA) Value: 407
|
||||
ItemStat4: Type: 45 (SPELL_POWER) Value: 206
|
||||
ItemStat5: Type: 0 (MANA) Value: 0
|
||||
ItemStat6: Type: 0 (MANA) Value: 0
|
||||
ItemStat7: Type: 0 (MANA) Value: 0
|
||||
ItemStat8: Type: 0 (MANA) Value: 0
|
||||
Item: Nightslayer Cover Entry: 16821 lookup up Class: 4 Subclass: 2
|
||||
<<<< High Level Items that match class Type: Strength Melee 0 >>>>>
|
||||
[31mItem: Nightslayer Cover Entry: 16821 has no high level items HAS TO BE SCALED MANUALLY[0m
|
||||
ItemStat1: Type: 3 (AGILITY) Value: 441
|
||||
ItemStat2: Type: 7 (STAMINA) Value: 451
|
||||
ItemStat3: Type: 4 (STRENGTH) Value: 121
|
||||
ItemStat4: Type: 32 (CRIT_RATING) Value: 344
|
||||
ItemStat5: Type: 0 (MANA) Value: 0
|
||||
ItemStat6: Type: 0 (MANA) Value: 0
|
||||
ItemStat7: Type: 0 (MANA) Value: 0
|
||||
ItemStat8: Type: 0 (MANA) Value: 0
|
||||
Item: Gutgore Ripper Entry: 17071 lookup up Class: 2 Subclass: 15
|
||||
<<<< High Level Items that match class Type: Strength Melee 0 >>>>>
|
||||
[31mItem: Gutgore Ripper Entry: 17071 has no high level items HAS TO BE SCALED MANUALLY[0m
|
||||
ItemStat1: Type: 4 (STRENGTH) Value: -339
|
||||
ItemStat2: Type: 0 (MANA) Value: 0
|
||||
ItemStat3: Type: 0 (MANA) Value: 0
|
||||
ItemStat4: Type: 0 (MANA) Value: 0
|
||||
ItemStat5: Type: 0 (MANA) Value: 0
|
||||
ItemStat6: Type: 0 (MANA) Value: 0
|
||||
ItemStat7: Type: 0 (MANA) Value: 0
|
||||
ItemStat8: Type: 0 (MANA) Value: 0
|
||||
[35mStats Added: Gutgore Ripper now has 4 stats (minimum 4 enforced)[0m
|
||||
Item: Aurastone Hammer Entry: 17105 lookup up Class: 2 Subclass: 4
|
||||
<<<< High Level Items that match class Type: Healer 1 >>>>>
|
||||
New Item: Aurastone Hammer Entry: 17105
|
||||
ItemStat1: Type: 45 (SPELL_POWER) Value: 402
|
||||
ItemStat2: Type: 5 (INTELLECT) Value: 202
|
||||
ItemStat3: Type: 7 (STAMINA) Value: 219
|
||||
ItemStat4: Type: 43 (MANA_REGENERATION) Value: 60
|
||||
ItemStat5: Type: 0 (MANA) Value: 0
|
||||
ItemStat6: Type: 0 (MANA) Value: 0
|
||||
ItemStat7: Type: 0 (MANA) Value: 0
|
||||
ItemStat8: Type: 0 (MANA) Value: 0
|
||||
Item: Talisman of Ephemeral Power Entry: 18820 lookup up Class: 4 Subclass: 0
|
||||
<<<< High Level Items that match class Type: Mage 7 >>>>>
|
||||
New Item: Talisman of Ephemeral Power Entry: 18820
|
||||
ItemStat1: Type: 45 (SPELL_POWER) Value: 3003
|
||||
ItemStat2: Type: 0 (MANA) Value: 0
|
||||
ItemStat3: Type: 0 (MANA) Value: 0
|
||||
ItemStat4: Type: 0 (MANA) Value: 0
|
||||
ItemStat5: Type: 0 (MANA) Value: 0
|
||||
ItemStat6: Type: 0 (MANA) Value: 0
|
||||
ItemStat7: Type: 0 (MANA) Value: 0
|
||||
ItemStat8: Type: 0 (MANA) Value: 0
|
||||
Item: Quick Strike Ring Entry: 18821 lookup up Class: 4 Subclass: 0
|
||||
<<<< High Level Items that match class Type: Agility Melee 4 >>>>>
|
||||
New Item: Quick Strike Ring Entry: 18821
|
||||
ItemStat1: Type: 7 (STAMINA) Value: 185
|
||||
ItemStat2: Type: 4 (STRENGTH) Value: 105
|
||||
ItemStat3: Type: 32 (CRIT_RATING) Value: 169
|
||||
ItemStat4: Type: 38 (ATTACK_POWER) Value: 504
|
||||
ItemStat5: Type: 0 (MANA) Value: 0
|
||||
ItemStat6: Type: 0 (MANA) Value: 0
|
||||
ItemStat7: Type: 0 (MANA) Value: 0
|
||||
ItemStat8: Type: 0 (MANA) Value: 0
|
||||
Item: Obsidian Edged Blade Entry: 18822 lookup up Class: 2 Subclass: 8
|
||||
<<<< High Level Items that match class Type: Strength Melee 1 >>>>>
|
||||
New Item: Obsidian Edged Blade Entry: 18822
|
||||
ItemStat1: Type: 4 (STRENGTH) Value: 886
|
||||
ItemStat2: Type: 37 (EXPERTISE_RATING) Value: 162
|
||||
ItemStat3: Type: 0 (MANA) Value: 0
|
||||
ItemStat4: Type: 0 (MANA) Value: 0
|
||||
ItemStat5: Type: 0 (MANA) Value: 0
|
||||
ItemStat6: Type: 0 (MANA) Value: 0
|
||||
ItemStat7: Type: 0 (MANA) Value: 0
|
||||
ItemStat8: Type: 0 (MANA) Value: 0
|
||||
Item: Aged Core Leather Gloves Entry: 18823 lookup up Class: 4 Subclass: 2
|
||||
<<<< High Level Items that match class Type: Strength Melee 0 >>>>>
|
||||
[31mItem: Aged Core Leather Gloves Entry: 18823 has no high level items HAS TO BE SCALED MANUALLY[0m
|
||||
ItemStat1: Type: 37 (EXPERTISE_RATING) Value: 98
|
||||
ItemStat2: Type: 32 (CRIT_RATING) Value: 163
|
||||
ItemStat3: Type: 4 (STRENGTH) Value: 302
|
||||
ItemStat4: Type: 7 (STAMINA) Value: 328
|
||||
ItemStat5: Type: 0 (MANA) Value: 0
|
||||
ItemStat6: Type: 0 (MANA) Value: 0
|
||||
ItemStat7: Type: 0 (MANA) Value: 0
|
||||
ItemStat8: Type: 0 (MANA) Value: 0
|
||||
Item: Magma Tempered Boots Entry: 18824 lookup up Class: 4 Subclass: 4
|
||||
<<<< High Level Items that match class Type: Healer 7 >>>>>
|
||||
New Item: Magma Tempered Boots Entry: 18824
|
||||
ItemStat1: Type: 6 (SPIRIT) Value: 235
|
||||
ItemStat2: Type: 45 (SPELL_POWER) Value: 142
|
||||
ItemStat3: Type: 7 (STAMINA) Value: 415
|
||||
ItemStat4: Type: 5 (INTELLECT) Value: 358
|
||||
ItemStat5: Type: 0 (MANA) Value: 0
|
||||
ItemStat6: Type: 0 (MANA) Value: 0
|
||||
ItemStat7: Type: 0 (MANA) Value: 0
|
||||
ItemStat8: Type: 0 (MANA) Value: 0
|
||||
Item: Deep Earth Spaulders Entry: 18829 lookup up Class: 4 Subclass: 3
|
||||
<<<< High Level Items that match class Type: Healer 7 >>>>>
|
||||
New Item: Deep Earth Spaulders Entry: 18829
|
||||
ItemStat1: Type: 6 (SPIRIT) Value: 134
|
||||
ItemStat2: Type: 45 (SPELL_POWER) Value: 508
|
||||
ItemStat3: Type: 5 (INTELLECT) Value: 230
|
||||
ItemStat4: Type: 7 (STAMINA) Value: 236
|
||||
ItemStat5: Type: 0 (MANA) Value: 0
|
||||
ItemStat6: Type: 0 (MANA) Value: 0
|
||||
ItemStat7: Type: 0 (MANA) Value: 0
|
||||
ItemStat8: Type: 0 (MANA) Value: 0
|
||||
Item: Brutality Blade Entry: 18832 lookup up Class: 2 Subclass: 7
|
||||
<<<< High Level Items that match class Type: Strength Melee 0 >>>>>
|
||||
[31mItem: Brutality Blade Entry: 18832 has no high level items HAS TO BE SCALED MANUALLY[0m
|
||||
ItemStat1: Type: 4 (STRENGTH) Value: 173
|
||||
ItemStat2: Type: 3 (AGILITY) Value: 173
|
||||
ItemStat3: Type: 32 (CRIT_RATING) Value: 160
|
||||
ItemStat4: Type: 0 (MANA) Value: 0
|
||||
ItemStat5: Type: 0 (MANA) Value: 0
|
||||
ItemStat6: Type: 0 (MANA) Value: 0
|
||||
ItemStat7: Type: 0 (MANA) Value: 0
|
||||
ItemStat8: Type: 0 (MANA) Value: 0
|
||||
[35mStats Added: Brutality Blade now has 4 stats (minimum 4 enforced)[0m
|
||||
Item: Mana Igniting Cord Entry: 19136 lookup up Class: 4 Subclass: 1
|
||||
<<<< High Level Items that match class Type: Mage 1 >>>>>
|
||||
New Item: Mana Igniting Cord Entry: 19136
|
||||
ItemStat1: Type: 5 (INTELLECT) Value: 315
|
||||
ItemStat2: Type: 7 (STAMINA) Value: 250
|
||||
ItemStat3: Type: 45 (SPELL_POWER) Value: 385
|
||||
ItemStat4: Type: 32 (CRIT_RATING) Value: 157
|
||||
ItemStat5: Type: 0 (MANA) Value: 0
|
||||
ItemStat6: Type: 0 (MANA) Value: 0
|
||||
ItemStat7: Type: 0 (MANA) Value: 0
|
||||
ItemStat8: Type: 0 (MANA) Value: 0
|
||||
[32mFire Resistance Applied: Mana Igniting Cord gets 15 fire resistance (modifier: 0.56)[0m
|
||||
Item: Fire Runed Grimoire Entry: 19142 lookup up Class: 4 Subclass: 0
|
||||
<<<< High Level Items that match class Type: Mage 7 >>>>>
|
||||
New Item: Fire Runed Grimoire Entry: 19142
|
||||
ItemStat1: Type: 5 (INTELLECT) Value: 420
|
||||
ItemStat2: Type: 7 (STAMINA) Value: 255
|
||||
ItemStat3: Type: 45 (SPELL_POWER) Value: 173
|
||||
ItemStat4: Type: 0 (MANA) Value: 0
|
||||
ItemStat5: Type: 0 (MANA) Value: 0
|
||||
ItemStat6: Type: 0 (MANA) Value: 0
|
||||
ItemStat7: Type: 0 (MANA) Value: 0
|
||||
ItemStat8: Type: 0 (MANA) Value: 0
|
||||
[32mFire Resistance Applied: Fire Runed Grimoire gets 15 fire resistance (modifier: 0.56)[0m
|
||||
Item: Flameguard Gauntlets Entry: 19143 lookup up Class: 4 Subclass: 4
|
||||
<<<< High Level Items that match class Type: Unknown 0 >>>>>
|
||||
[31mItem: Flameguard Gauntlets Entry: 19143 has no high level items HAS TO BE SCALED MANUALLY[0m
|
||||
ItemStat1: Type: 7 (STAMINA) Value: 287
|
||||
ItemStat2: Type: 32 (CRIT_RATING) Value: 163
|
||||
ItemStat3: Type: 38 (ATTACK_POWER) Value: 867
|
||||
ItemStat4: Type: 0 (MANA) Value: 0
|
||||
ItemStat5: Type: 0 (MANA) Value: 0
|
||||
ItemStat6: Type: 0 (MANA) Value: 0
|
||||
ItemStat7: Type: 0 (MANA) Value: 0
|
||||
ItemStat8: Type: 0 (MANA) Value: 0
|
||||
[32mFire Resistance Applied: Flameguard Gauntlets gets 16 fire resistance (modifier: 0.62)[0m
|
||||
Item: Sabatons of the Flamewalker Entry: 19144 lookup up Class: 4 Subclass: 3
|
||||
<<<< High Level Items that match class Type: Mage 8 >>>>>
|
||||
New Item: Sabatons of the Flamewalker Entry: 19144
|
||||
ItemStat1: Type: 7 (STAMINA) Value: 613
|
||||
ItemStat2: Type: 5 (INTELLECT) Value: 231
|
||||
ItemStat3: Type: 38 (ATTACK_POWER) Value: 493
|
||||
ItemStat4: Type: 0 (MANA) Value: 0
|
||||
ItemStat5: Type: 0 (MANA) Value: 0
|
||||
ItemStat6: Type: 0 (MANA) Value: 0
|
||||
ItemStat7: Type: 0 (MANA) Value: 0
|
||||
ItemStat8: Type: 0 (MANA) Value: 0
|
||||
[32mFire Resistance Applied: Sabatons of the Flamewalker gets 18 fire resistance (modifier: 0.69)[0m
|
||||
Item: Cenarion Spaulders Entry: 16836 lookup up Class: 4 Subclass: 2
|
||||
<<<< High Level Items that match class Type: Healer 8 >>>>>
|
||||
New Item: Cenarion Spaulders Entry: 16836
|
||||
ItemStat1: Type: 45 (SPELL_POWER) Value: 155
|
||||
ItemStat2: Type: 5 (INTELLECT) Value: 441
|
||||
ItemStat3: Type: 6 (SPIRIT) Value: 214
|
||||
ItemStat4: Type: 7 (STAMINA) Value: 305
|
||||
ItemStat5: Type: 43 (MANA_REGENERATION) Value: 53
|
||||
ItemStat6: Type: 0 (MANA) Value: 0
|
||||
ItemStat7: Type: 0 (MANA) Value: 0
|
||||
ItemStat8: Type: 0 (MANA) Value: 0
|
||||
Item: Earthfury Epaulets Entry: 16844 lookup up Class: 4 Subclass: 3
|
||||
<<<< High Level Items that match class Type: Healer 7 >>>>>
|
||||
New Item: Earthfury Epaulets Entry: 16844
|
||||
ItemStat1: Type: 5 (INTELLECT) Value: 388
|
||||
ItemStat2: Type: 6 (SPIRIT) Value: 214
|
||||
ItemStat3: Type: 7 (STAMINA) Value: 407
|
||||
ItemStat4: Type: 43 (MANA_REGENERATION) Value: 53
|
||||
ItemStat5: Type: 45 (SPELL_POWER) Value: 155
|
||||
ItemStat6: Type: 0 (MANA) Value: 0
|
||||
ItemStat7: Type: 0 (MANA) Value: 0
|
||||
ItemStat8: Type: 0 (MANA) Value: 0
|
||||
Item: Lawbringer Spaulders Entry: 16856 lookup up Class: 4 Subclass: 4
|
||||
<<<< High Level Items that match class Type: Healer 7 >>>>>
|
||||
New Item: Lawbringer Spaulders Entry: 16856
|
||||
ItemStat1: Type: 5 (INTELLECT) Value: 321
|
||||
ItemStat2: Type: 6 (SPIRIT) Value: 174
|
||||
ItemStat3: Type: 7 (STAMINA) Value: 523
|
||||
ItemStat4: Type: 4 (STRENGTH) Value: 214
|
||||
ItemStat5: Type: 45 (SPELL_POWER) Value: 155
|
||||
ItemStat6: Type: 0 (MANA) Value: 0
|
||||
ItemStat7: Type: 0 (MANA) Value: 0
|
||||
ItemStat8: Type: 0 (MANA) Value: 0
|
||||
Item: Arcanist Mantle Entry: 16797 lookup up Class: 4 Subclass: 1
|
||||
<<<< High Level Items that match class Type: Healer 18 >>>>>
|
||||
New Item: Arcanist Mantle Entry: 16797
|
||||
ItemStat1: Type: 6 (SPIRIT) Value: 107
|
||||
ItemStat2: Type: 7 (STAMINA) Value: 233
|
||||
ItemStat3: Type: 43 (MANA_REGENERATION) Value: 53
|
||||
ItemStat4: Type: 45 (SPELL_POWER) Value: 241
|
||||
ItemStat5: Type: 5 (INTELLECT) Value: 455
|
||||
ItemStat6: Type: 0 (MANA) Value: 0
|
||||
ItemStat7: Type: 0 (MANA) Value: 0
|
||||
ItemStat8: Type: 0 (MANA) Value: 0
|
||||
Item: Felheart Shoulder Pads Entry: 16807 lookup up Class: 4 Subclass: 1
|
||||
<<<< High Level Items that match class Type: Healer 18 >>>>>
|
||||
New Item: Felheart Shoulder Pads Entry: 16807
|
||||
ItemStat1: Type: 5 (INTELLECT) Value: 374
|
||||
ItemStat2: Type: 6 (SPIRIT) Value: 147
|
||||
ItemStat3: Type: 7 (STAMINA) Value: 596
|
||||
ItemStat4: Type: 45 (SPELL_POWER) Value: 155
|
||||
ItemStat5: Type: 0 (MANA) Value: 0
|
||||
ItemStat6: Type: 0 (MANA) Value: 0
|
||||
ItemStat7: Type: 0 (MANA) Value: 0
|
||||
ItemStat8: Type: 0 (MANA) Value: 0
|
||||
Item: Seal of the Archmagus Entry: 17110 lookup up Class: 4 Subclass: 0
|
||||
<<<< High Level Items that match class Type: Healer 5 >>>>>
|
||||
New Item: Seal of the Archmagus Entry: 17110
|
||||
ItemStat1: Type: 6 (SPIRIT) Value: 223
|
||||
ItemStat2: Type: 43 (MANA_REGENERATION) Value: 39
|
||||
ItemStat3: Type: 5 (INTELLECT) Value: 223
|
||||
ItemStat4: Type: 7 (STAMINA) Value: 241
|
||||
ItemStat5: Type: 0 (MANA) Value: 0
|
||||
ItemStat6: Type: 0 (MANA) Value: 0
|
||||
ItemStat7: Type: 0 (MANA) Value: 0
|
||||
ItemStat8: Type: 0 (MANA) Value: 0
|
||||
Item: Nightslayer Shoulder Pads Entry: 16823 lookup up Class: 4 Subclass: 2
|
||||
<<<< High Level Items that match class Type: Strength Melee 0 >>>>>
|
||||
[31mItem: Nightslayer Shoulder Pads Entry: 16823 has no high level items HAS TO BE SCALED MANUALLY[0m
|
||||
ItemStat1: Type: 3 (AGILITY) Value: 561
|
||||
ItemStat2: Type: 7 (STAMINA) Value: 276
|
||||
ItemStat3: Type: 4 (STRENGTH) Value: 54
|
||||
ItemStat4: Type: 31 (HIT_RATING) Value: 62
|
||||
ItemStat5: Type: 0 (MANA) Value: 0
|
||||
ItemStat6: Type: 0 (MANA) Value: 0
|
||||
ItemStat7: Type: 0 (MANA) Value: 0
|
||||
ItemStat8: Type: 0 (MANA) Value: 0
|
||||
Item: Pauldrons of Might Entry: 16868 lookup up Class: 4 Subclass: 4
|
||||
<<<< High Level Items that match class Type: Tank 5 >>>>>
|
||||
New Item: Pauldrons of Might Entry: 16868
|
||||
ItemStat1: Type: 7 (STAMINA) Value: 523
|
||||
ItemStat2: Type: 4 (STRENGTH) Value: 321
|
||||
ItemStat3: Type: 15 (BLOCK_RATING) Value: 104
|
||||
ItemStat4: Type: 12 (DEFENSE_SKILL_RATING) Value: 63
|
||||
ItemStat5: Type: 0 (MANA) Value: 0
|
||||
ItemStat6: Type: 0 (MANA) Value: 0
|
||||
ItemStat7: Type: 0 (MANA) Value: 0
|
||||
ItemStat8: Type: 0 (MANA) Value: 0
|
||||
Item: Mantle of Prophecy Entry: 16816 lookup up Class: 4 Subclass: 1
|
||||
<<<< High Level Items that match class Type: Healer 18 >>>>>
|
||||
New Item: Mantle of Prophecy Entry: 16816
|
||||
ItemStat1: Type: 5 (INTELLECT) Value: 495
|
||||
ItemStat2: Type: 6 (SPIRIT) Value: 214
|
||||
ItemStat3: Type: 7 (STAMINA) Value: 305
|
||||
ItemStat4: Type: 45 (SPELL_POWER) Value: 155
|
||||
ItemStat5: Type: 0 (MANA) Value: 0
|
||||
ItemStat6: Type: 0 (MANA) Value: 0
|
||||
ItemStat7: Type: 0 (MANA) Value: 0
|
||||
ItemStat8: Type: 0 (MANA) Value: 0
|
||||
Item: Giantstalker's Epaulets Entry: 16848 lookup up Class: 4 Subclass: 3
|
||||
<<<< High Level Items that match class Type: Healer 7 >>>>>
|
||||
New Item: Giantstalker's Epaulets Entry: 16848
|
||||
ItemStat1: Type: 5 (INTELLECT) Value: 107
|
||||
ItemStat2: Type: 6 (SPIRIT) Value: 187
|
||||
ItemStat3: Type: 7 (STAMINA) Value: 334
|
||||
ItemStat4: Type: 31 (HIT_RATING) Value: 62
|
||||
ItemStat5: Type: 38 (ATTACK_POWER) Value: 550
|
||||
ItemStat6: Type: 3 (AGILITY) Value: 348
|
||||
ItemStat7: Type: 0 (MANA) Value: 0
|
||||
ItemStat8: Type: 0 (MANA) Value: 0
|
||||
Item: Shadowstrike Entry: 17074 lookup up Class: 2 Subclass: 6
|
||||
<<<< High Level Items that match class Type: Healer 0 >>>>>
|
||||
[31mItem: Shadowstrike Entry: 17074 has no high level items HAS TO BE SCALED MANUALLY[0m
|
||||
ItemStat1: Type: 0 (MANA) Value: 0
|
||||
ItemStat2: Type: 0 (MANA) Value: 0
|
||||
ItemStat3: Type: 0 (MANA) Value: 0
|
||||
ItemStat4: Type: 0 (MANA) Value: 0
|
||||
ItemStat5: Type: 0 (MANA) Value: 0
|
||||
ItemStat6: Type: 0 (MANA) Value: 0
|
||||
ItemStat7: Type: 0 (MANA) Value: 0
|
||||
ItemStat8: Type: 0 (MANA) Value: 0
|
||||
[35mStats Added: Shadowstrike now has 4 stats (minimum 4 enforced)[0m
|
||||
Item: Arcanist Leggings Entry: 16796 lookup up Class: 4 Subclass: 1
|
||||
<<<< High Level Items that match class Type: Healer 18 >>>>>
|
||||
New Item: Arcanist Leggings Entry: 16796
|
||||
ItemStat1: Type: 5 (INTELLECT) Value: 495
|
||||
ItemStat2: Type: 6 (SPIRIT) Value: 214
|
||||
ItemStat3: Type: 7 (STAMINA) Value: 422
|
||||
ItemStat4: Type: 32 (CRIT_RATING) Value: 172
|
||||
ItemStat5: Type: 45 (SPELL_POWER) Value: 344
|
||||
ItemStat6: Type: 0 (MANA) Value: 0
|
||||
ItemStat7: Type: 0 (MANA) Value: 0
|
||||
ItemStat8: Type: 0 (MANA) Value: 0
|
||||
Item: Felheart Pants Entry: 16810 lookup up Class: 4 Subclass: 1
|
||||
<<<< High Level Items that match class Type: Healer 18 >>>>>
|
||||
New Item: Felheart Pants Entry: 16810
|
||||
ItemStat1: Type: 5 (INTELLECT) Value: 414
|
||||
ItemStat2: Type: 6 (SPIRIT) Value: 214
|
||||
ItemStat3: Type: 7 (STAMINA) Value: 480
|
||||
ItemStat4: Type: 45 (SPELL_POWER) Value: 515
|
||||
ItemStat5: Type: 0 (MANA) Value: 0
|
||||
ItemStat6: Type: 0 (MANA) Value: 0
|
||||
ItemStat7: Type: 0 (MANA) Value: 0
|
||||
ItemStat8: Type: 0 (MANA) Value: 0
|
||||
Item: Pants of Prophecy Entry: 16814 lookup up Class: 4 Subclass: 1
|
||||
<<<< High Level Items that match class Type: Healer 18 >>>>>
|
||||
New Item: Pants of Prophecy Entry: 16814
|
||||
ItemStat1: Type: 6 (SPIRIT) Value: 441
|
||||
ItemStat2: Type: 7 (STAMINA) Value: 422
|
||||
ItemStat3: Type: 43 (MANA_REGENERATION) Value: 84
|
||||
ItemStat4: Type: 45 (SPELL_POWER) Value: 206
|
||||
ItemStat5: Type: 5 (INTELLECT) Value: 521
|
||||
ItemStat6: Type: 0 (MANA) Value: 0
|
||||
ItemStat7: Type: 0 (MANA) Value: 0
|
||||
ItemStat8: Type: 0 (MANA) Value: 0
|
||||
Item: Nightslayer Pants Entry: 16822 lookup up Class: 4 Subclass: 2
|
||||
<<<< High Level Items that match class Type: Strength Melee 0 >>>>>
|
||||
[31mItem: Nightslayer Pants Entry: 16822 has no high level items HAS TO BE SCALED MANUALLY[0m
|
||||
ItemStat1: Type: 3 (AGILITY) Value: 722
|
||||
ItemStat2: Type: 7 (STAMINA) Value: 349
|
||||
ItemStat3: Type: 4 (STRENGTH) Value: 214
|
||||
ItemStat4: Type: 32 (CRIT_RATING) Value: 172
|
||||
ItemStat5: Type: 0 (MANA) Value: 0
|
||||
ItemStat6: Type: 0 (MANA) Value: 0
|
||||
ItemStat7: Type: 0 (MANA) Value: 0
|
||||
ItemStat8: Type: 0 (MANA) Value: 0
|
||||
Item: Striker's Mark Entry: 17069 lookup up Class: 2 Subclass: 2
|
||||
<<<< High Level Items that match class Type: Ranged 1 >>>>>
|
||||
New Item: Striker's Mark Entry: 17069
|
||||
ItemStat1: Type: 38 (ATTACK_POWER) Value: 354
|
||||
ItemStat2: Type: 31 (HIT_RATING) Value: 59
|
||||
ItemStat3: Type: 0 (MANA) Value: 0
|
||||
ItemStat4: Type: 0 (MANA) Value: 0
|
||||
ItemStat5: Type: 0 (MANA) Value: 0
|
||||
ItemStat6: Type: 0 (MANA) Value: 0
|
||||
ItemStat7: Type: 0 (MANA) Value: 0
|
||||
ItemStat8: Type: 0 (MANA) Value: 0
|
||||
Item: Cenarion Leggings Entry: 16835 lookup up Class: 4 Subclass: 2
|
||||
<<<< High Level Items that match class Type: Healer 8 >>>>>
|
||||
New Item: Cenarion Leggings Entry: 16835
|
||||
ItemStat1: Type: 5 (INTELLECT) Value: 414
|
||||
ItemStat2: Type: 6 (SPIRIT) Value: 441
|
||||
ItemStat3: Type: 7 (STAMINA) Value: 422
|
||||
ItemStat4: Type: 32 (CRIT_RATING) Value: 172
|
||||
ItemStat5: Type: 43 (MANA_REGENERATION) Value: 53
|
||||
ItemStat6: Type: 45 (SPELL_POWER) Value: 206
|
||||
ItemStat7: Type: 0 (MANA) Value: 0
|
||||
ItemStat8: Type: 0 (MANA) Value: 0
|
||||
Item: Earthfury Legguards Entry: 16843 lookup up Class: 4 Subclass: 3
|
||||
<<<< High Level Items that match class Type: Healer 7 >>>>>
|
||||
New Item: Earthfury Legguards Entry: 16843
|
||||
ItemStat1: Type: 5 (INTELLECT) Value: 414
|
||||
ItemStat2: Type: 6 (SPIRIT) Value: 455
|
||||
ItemStat3: Type: 7 (STAMINA) Value: 422
|
||||
ItemStat4: Type: 43 (MANA_REGENERATION) Value: 84
|
||||
ItemStat5: Type: 45 (SPELL_POWER) Value: 206
|
||||
ItemStat6: Type: 0 (MANA) Value: 0
|
||||
ItemStat7: Type: 0 (MANA) Value: 0
|
||||
ItemStat8: Type: 0 (MANA) Value: 0
|
||||
Item: Giantstalker's Leggings Entry: 16847 lookup up Class: 4 Subclass: 3
|
||||
<<<< High Level Items that match class Type: Healer 7 >>>>>
|
||||
New Item: Giantstalker's Leggings Entry: 16847
|
||||
ItemStat1: Type: 5 (INTELLECT) Value: 121
|
||||
ItemStat2: Type: 6 (SPIRIT) Value: 174
|
||||
ItemStat3: Type: 7 (STAMINA) Value: 349
|
||||
ItemStat4: Type: 32 (CRIT_RATING) Value: 172
|
||||
ItemStat5: Type: 38 (ATTACK_POWER) Value: 721
|
||||
ItemStat6: Type: 3 (AGILITY) Value: 481
|
||||
ItemStat7: Type: 0 (MANA) Value: 0
|
||||
ItemStat8: Type: 0 (MANA) Value: 0
|
||||
Item: Lawbringer Legplates Entry: 16855 lookup up Class: 4 Subclass: 4
|
||||
<<<< High Level Items that match class Type: Healer 7 >>>>>
|
||||
New Item: Lawbringer Legplates Entry: 16855
|
||||
ItemStat1: Type: 4 (STRENGTH) Value: 147
|
||||
ItemStat2: Type: 43 (MANA_REGENERATION) Value: 43
|
||||
ItemStat3: Type: 45 (SPELL_POWER) Value: 206
|
||||
ItemStat4: Type: 5 (INTELLECT) Value: 388
|
||||
ItemStat5: Type: 6 (SPIRIT) Value: 388
|
||||
ItemStat6: Type: 7 (STAMINA) Value: 567
|
||||
ItemStat7: Type: 0 (MANA) Value: 0
|
||||
ItemStat8: Type: 0 (MANA) Value: 0
|
||||
Item: Legplates of Might Entry: 16867 lookup up Class: 4 Subclass: 4
|
||||
<<<< High Level Items that match class Type: Tank 5 >>>>>
|
||||
New Item: Legplates of Might Entry: 16867
|
||||
ItemStat1: Type: 7 (STAMINA) Value: 538
|
||||
ItemStat2: Type: 4 (STRENGTH) Value: 521
|
||||
ItemStat3: Type: 14 (PARRY_RATING) Value: 192
|
||||
ItemStat4: Type: 12 (DEFENSE_SKILL_RATING) Value: 79
|
||||
ItemStat5: Type: 0 (MANA) Value: 0
|
||||
ItemStat6: Type: 0 (MANA) Value: 0
|
||||
ItemStat7: Type: 0 (MANA) Value: 0
|
||||
ItemStat8: Type: 0 (MANA) Value: 0
|
||||
Item: Medallion of Steadfast Might Entry: 17065 lookup up Class: 4 Subclass: 0
|
||||
<<<< High Level Items that match class Type: Tank 3 >>>>>
|
||||
New Item: Medallion of Steadfast Might Entry: 17065
|
||||
ItemStat1: Type: 7 (STAMINA) Value: 293
|
||||
ItemStat2: Type: 4 (STRENGTH) Value: 180
|
||||
ItemStat3: Type: 13 (DODGE_RATING) Value: 83
|
||||
ItemStat4: Type: 12 (DEFENSE_SKILL_RATING) Value: 91
|
||||
ItemStat5: Type: 0 (MANA) Value: 0
|
||||
ItemStat6: Type: 0 (MANA) Value: 0
|
||||
ItemStat7: Type: 0 (MANA) Value: 0
|
||||
ItemStat8: Type: 0 (MANA) Value: 0
|
||||
Item: Earthshaker Entry: 17073 lookup up Class: 2 Subclass: 5
|
||||
<<<< High Level Items that match class Type: Unknown 0 >>>>>
|
||||
[31mItem: Earthshaker Entry: 17073 has no high level items HAS TO BE SCALED MANUALLY[0m
|
||||
ItemStat1: Type: 38 (ATTACK_POWER) Value: 378
|
||||
ItemStat2: Type: 0 (MANA) Value: 0
|
||||
ItemStat3: Type: 0 (MANA) Value: 0
|
||||
ItemStat4: Type: 0 (MANA) Value: 0
|
||||
ItemStat5: Type: 0 (MANA) Value: 0
|
||||
ItemStat6: Type: 0 (MANA) Value: 0
|
||||
ItemStat7: Type: 0 (MANA) Value: 0
|
||||
ItemStat8: Type: 0 (MANA) Value: 0
|
||||
[35mStats Added: Earthshaker now has 4 stats (minimum 4 enforced)[0m
|
||||
Item: Eskhandar's Right Claw Entry: 18203 lookup up Class: 2 Subclass: 13
|
||||
<<<< High Level Items that match class Type: Agility Melee 2 >>>>>
|
||||
New Item: Eskhandar's Right Claw Entry: 18203
|
||||
ItemStat1: Type: 3 (AGILITY) Value: 81
|
||||
ItemStat2: Type: 36 (HASTE_RATING) Value: 3391
|
||||
ItemStat3: Type: 0 (MANA) Value: 0
|
||||
ItemStat4: Type: 0 (MANA) Value: 0
|
||||
ItemStat5: Type: 0 (MANA) Value: 0
|
||||
ItemStat6: Type: 0 (MANA) Value: 0
|
||||
ItemStat7: Type: 0 (MANA) Value: 0
|
||||
ItemStat8: Type: 0 (MANA) Value: 0
|
||||
Item: Arcanist Robes Entry: 16798 lookup up Class: 4 Subclass: 1
|
||||
<<<< High Level Items that match class Type: Healer 18 >>>>>
|
||||
New Item: Arcanist Robes Entry: 16798
|
||||
ItemStat1: Type: 5 (INTELLECT) Value: 548
|
||||
ItemStat2: Type: 6 (SPIRIT) Value: 214
|
||||
ItemStat3: Type: 7 (STAMINA) Value: 451
|
||||
ItemStat4: Type: 45 (SPELL_POWER) Value: 395
|
||||
ItemStat5: Type: 0 (MANA) Value: 0
|
||||
ItemStat6: Type: 0 (MANA) Value: 0
|
||||
ItemStat7: Type: 0 (MANA) Value: 0
|
||||
ItemStat8: Type: 0 (MANA) Value: 0
|
||||
Item: Felheart Robes Entry: 16809 lookup up Class: 4 Subclass: 1
|
||||
<<<< High Level Items that match class Type: Mage 1 >>>>>
|
||||
New Item: Felheart Robes Entry: 16809
|
||||
ItemStat1: Type: 5 (INTELLECT) Value: 441
|
||||
ItemStat2: Type: 7 (STAMINA) Value: 741
|
||||
ItemStat3: Type: 45 (SPELL_POWER) Value: 224
|
||||
ItemStat4: Type: 31 (HIT_RATING) Value: 50
|
||||
ItemStat5: Type: 0 (MANA) Value: 0
|
||||
ItemStat6: Type: 0 (MANA) Value: 0
|
||||
ItemStat7: Type: 0 (MANA) Value: 0
|
||||
ItemStat8: Type: 0 (MANA) Value: 0
|
||||
Item: Robes of Prophecy Entry: 16815 lookup up Class: 4 Subclass: 1
|
||||
<<<< High Level Items that match class Type: Healer 18 >>>>>
|
||||
New Item: Robes of Prophecy Entry: 16815
|
||||
ItemStat1: Type: 5 (INTELLECT) Value: 588
|
||||
ItemStat2: Type: 6 (SPIRIT) Value: 374
|
||||
ItemStat3: Type: 7 (STAMINA) Value: 480
|
||||
ItemStat4: Type: 45 (SPELL_POWER) Value: 206
|
||||
ItemStat5: Type: 0 (MANA) Value: 0
|
||||
ItemStat6: Type: 0 (MANA) Value: 0
|
||||
ItemStat7: Type: 0 (MANA) Value: 0
|
||||
ItemStat8: Type: 0 (MANA) Value: 0
|
||||
Item: Nightslayer Chestpiece Entry: 16820 lookup up Class: 4 Subclass: 2
|
||||
<<<< High Level Items that match class Type: Strength Melee 0 >>>>>
|
||||
[31mItem: Nightslayer Chestpiece Entry: 16820 has no high level items HAS TO BE SCALED MANUALLY[0m
|
||||
ItemStat1: Type: 3 (AGILITY) Value: 628
|
||||
ItemStat2: Type: 7 (STAMINA) Value: 480
|
||||
ItemStat3: Type: 4 (STRENGTH) Value: 214
|
||||
ItemStat4: Type: 32 (CRIT_RATING) Value: 172
|
||||
ItemStat5: Type: 0 (MANA) Value: 0
|
||||
ItemStat6: Type: 0 (MANA) Value: 0
|
||||
ItemStat7: Type: 0 (MANA) Value: 0
|
||||
ItemStat8: Type: 0 (MANA) Value: 0
|
||||
Item: Cenarion Vestments Entry: 16833 lookup up Class: 4 Subclass: 2
|
||||
<<<< High Level Items that match class Type: Healer 8 >>>>>
|
||||
New Item: Cenarion Vestments Entry: 16833
|
||||
ItemStat1: Type: 5 (INTELLECT) Value: 521
|
||||
ItemStat2: Type: 6 (SPIRIT) Value: 348
|
||||
ItemStat3: Type: 7 (STAMINA) Value: 538
|
||||
ItemStat4: Type: 43 (MANA_REGENERATION) Value: 43
|
||||
ItemStat5: Type: 45 (SPELL_POWER) Value: 206
|
||||
ItemStat6: Type: 0 (MANA) Value: 0
|
||||
ItemStat7: Type: 0 (MANA) Value: 0
|
||||
ItemStat8: Type: 0 (MANA) Value: 0
|
||||
Item: Earthfury Vestments Entry: 16841 lookup up Class: 4 Subclass: 3
|
||||
<<<< High Level Items that match class Type: Healer 7 >>>>>
|
||||
New Item: Earthfury Vestments Entry: 16841
|
||||
ItemStat1: Type: 5 (INTELLECT) Value: 588
|
||||
ItemStat2: Type: 6 (SPIRIT) Value: 281
|
||||
ItemStat3: Type: 7 (STAMINA) Value: 407
|
||||
ItemStat4: Type: 32 (CRIT_RATING) Value: 172
|
||||
ItemStat5: Type: 45 (SPELL_POWER) Value: 206
|
||||
ItemStat6: Type: 0 (MANA) Value: 0
|
||||
ItemStat7: Type: 0 (MANA) Value: 0
|
||||
ItemStat8: Type: 0 (MANA) Value: 0
|
||||
Item: Giantstalker's Breastplate Entry: 16845 lookup up Class: 4 Subclass: 3
|
||||
<<<< High Level Items that match class Type: Mage 8 >>>>>
|
||||
New Item: Giantstalker's Breastplate Entry: 16845
|
||||
ItemStat1: Type: 38 (ATTACK_POWER) Value: 584
|
||||
ItemStat2: Type: 3 (AGILITY) Value: 388
|
||||
ItemStat3: Type: 5 (INTELLECT) Value: 241
|
||||
ItemStat4: Type: 7 (STAMINA) Value: 538
|
||||
ItemStat5: Type: 32 (CRIT_RATING) Value: 172
|
||||
ItemStat6: Type: 0 (MANA) Value: 0
|
||||
ItemStat7: Type: 0 (MANA) Value: 0
|
||||
ItemStat8: Type: 0 (MANA) Value: 0
|
||||
Item: Lawbringer Chestguard Entry: 16853 lookup up Class: 4 Subclass: 4
|
||||
<<<< High Level Items that match class Type: Healer 7 >>>>>
|
||||
New Item: Lawbringer Chestguard Entry: 16853
|
||||
ItemStat1: Type: 6 (SPIRIT) Value: 281
|
||||
ItemStat2: Type: 7 (STAMINA) Value: 610
|
||||
ItemStat3: Type: 4 (STRENGTH) Value: 174
|
||||
ItemStat4: Type: 45 (SPELL_POWER) Value: 206
|
||||
ItemStat5: Type: 5 (INTELLECT) Value: 455
|
||||
ItemStat6: Type: 0 (MANA) Value: 0
|
||||
ItemStat7: Type: 0 (MANA) Value: 0
|
||||
ItemStat8: Type: 0 (MANA) Value: 0
|
||||
Item: Breastplate of Might Entry: 16865 lookup up Class: 4 Subclass: 4
|
||||
<<<< High Level Items that match class Type: Tank 5 >>>>>
|
||||
New Item: Breastplate of Might Entry: 16865
|
||||
ItemStat1: Type: 7 (STAMINA) Value: 668
|
||||
ItemStat2: Type: 4 (STRENGTH) Value: 441
|
||||
ItemStat3: Type: 15 (BLOCK_RATING) Value: 156
|
||||
ItemStat4: Type: 12 (DEFENSE_SKILL_RATING) Value: 79
|
||||
ItemStat5: Type: 0 (MANA) Value: 0
|
||||
ItemStat6: Type: 0 (MANA) Value: 0
|
||||
ItemStat7: Type: 0 (MANA) Value: 0
|
||||
ItemStat8: Type: 0 (MANA) Value: 0
|
||||
Item: Blastershot Launcher Entry: 17072 lookup up Class: 2 Subclass: 3
|
||||
<<<< High Level Items that match class Type: Ranged 1 >>>>>
|
||||
New Item: Blastershot Launcher Entry: 17072
|
||||
ItemStat1: Type: 7 (STAMINA) Value: 121
|
||||
ItemStat2: Type: 32 (CRIT_RATING) Value: 160
|
||||
ItemStat3: Type: 0 (MANA) Value: 0
|
||||
ItemStat4: Type: 0 (MANA) Value: 0
|
||||
ItemStat5: Type: 0 (MANA) Value: 0
|
||||
ItemStat6: Type: 0 (MANA) Value: 0
|
||||
ItemStat7: Type: 0 (MANA) Value: 0
|
||||
ItemStat8: Type: 0 (MANA) Value: 0
|
||||
Item: Azuresong Mageblade Entry: 17103 lookup up Class: 2 Subclass: 7
|
||||
<<<< High Level Items that match class Type: Mage 1 >>>>>
|
||||
New Item: Azuresong Mageblade Entry: 17103
|
||||
ItemStat1: Type: 5 (INTELLECT) Value: 230
|
||||
ItemStat2: Type: 7 (STAMINA) Value: 145
|
||||
ItemStat3: Type: 32 (CRIT_RATING) Value: 157
|
||||
ItemStat4: Type: 45 (SPELL_POWER) Value: 616
|
||||
ItemStat5: Type: 0 (MANA) Value: 0
|
||||
ItemStat6: Type: 0 (MANA) Value: 0
|
||||
ItemStat7: Type: 0 (MANA) Value: 0
|
||||
ItemStat8: Type: 0 (MANA) Value: 0
|
||||
Item: Staff of Dominance Entry: 18842 lookup up Class: 2 Subclass: 10
|
||||
<<<< High Level Items that match class Type: Healer 0 >>>>>
|
||||
[31mItem: Staff of Dominance Entry: 18842 has no high level items HAS TO BE SCALED MANUALLY[0m
|
||||
ItemStat1: Type: 5 (INTELLECT) Value: 753
|
||||
ItemStat2: Type: 7 (STAMINA) Value: 348
|
||||
ItemStat3: Type: 6 (SPIRIT) Value: 284
|
||||
ItemStat4: Type: 32 (CRIT_RATING) Value: 160
|
||||
ItemStat5: Type: 45 (SPELL_POWER) Value: 629
|
||||
ItemStat6: Type: 0 (MANA) Value: 0
|
||||
ItemStat7: Type: 0 (MANA) Value: 0
|
||||
ItemStat8: Type: 0 (MANA) Value: 0
|
||||
[36mSpell Power Boosted: Staff of Dominance spell power increased to 1179[0m
|
||||
Item: Giantstalker's Boots Entry: 16849 lookup up Class: 4 Subclass: 3
|
||||
<<<< High Level Items that match class Type: Healer 7 >>>>>
|
||||
New Item: Giantstalker's Boots Entry: 16849
|
||||
ItemStat1: Type: 3 (AGILITY) Value: 414
|
||||
ItemStat2: Type: 6 (SPIRIT) Value: 121
|
||||
ItemStat3: Type: 7 (STAMINA) Value: 334
|
||||
ItemStat4: Type: 38 (ATTACK_POWER) Value: 618
|
||||
ItemStat5: Type: 0 (MANA) Value: 0
|
||||
ItemStat6: Type: 0 (MANA) Value: 0
|
||||
ItemStat7: Type: 0 (MANA) Value: 0
|
||||
ItemStat8: Type: 0 (MANA) Value: 0
|
||||
Item: Sabatons of Might Entry: 16862 lookup up Class: 4 Subclass: 4
|
||||
<<<< High Level Items that match class Type: Tank 5 >>>>>
|
||||
New Item: Sabatons of Might Entry: 16862
|
||||
ItemStat1: Type: 7 (STAMINA) Value: 610
|
||||
ItemStat2: Type: 4 (STRENGTH) Value: 321
|
||||
ItemStat3: Type: 12 (DEFENSE_SKILL_RATING) Value: 63
|
||||
ItemStat4: Type: 0 (MANA) Value: 0
|
||||
ItemStat5: Type: 0 (MANA) Value: 0
|
||||
ItemStat6: Type: 0 (MANA) Value: 0
|
||||
ItemStat7: Type: 0 (MANA) Value: 0
|
||||
ItemStat8: Type: 0 (MANA) Value: 0
|
||||
Item: Gloves of Prophecy Entry: 16812 lookup up Class: 4 Subclass: 1
|
||||
<<<< High Level Items that match class Type: Healer 18 >>>>>
|
||||
New Item: Gloves of Prophecy Entry: 16812
|
||||
ItemStat1: Type: 5 (INTELLECT) Value: 321
|
||||
ItemStat2: Type: 6 (SPIRIT) Value: 321
|
||||
ItemStat3: Type: 7 (STAMINA) Value: 233
|
||||
ItemStat4: Type: 43 (MANA_REGENERATION) Value: 84
|
||||
ItemStat5: Type: 45 (SPELL_POWER) Value: 155
|
||||
ItemStat6: Type: 0 (MANA) Value: 0
|
||||
ItemStat7: Type: 0 (MANA) Value: 0
|
||||
ItemStat8: Type: 0 (MANA) Value: 0
|
||||
Item: Nightslayer Gloves Entry: 16826 lookup up Class: 4 Subclass: 2
|
||||
<<<< High Level Items that match class Type: Strength Melee 0 >>>>>
|
||||
[31mItem: Nightslayer Gloves Entry: 16826 has no high level items HAS TO BE SCALED MANUALLY[0m
|
||||
ItemStat1: Type: 31 (HIT_RATING) Value: 62
|
||||
ItemStat2: Type: 3 (AGILITY) Value: 388
|
||||
ItemStat3: Type: 7 (STAMINA) Value: 407
|
||||
ItemStat4: Type: 4 (STRENGTH) Value: 254
|
||||
ItemStat5: Type: 0 (MANA) Value: 0
|
||||
ItemStat6: Type: 0 (MANA) Value: 0
|
||||
ItemStat7: Type: 0 (MANA) Value: 0
|
||||
ItemStat8: Type: 0 (MANA) Value: 0
|
||||
Item: Earthfury Gauntlets Entry: 16839 lookup up Class: 4 Subclass: 3
|
||||
<<<< High Level Items that match class Type: Healer 7 >>>>>
|
||||
New Item: Earthfury Gauntlets Entry: 16839
|
||||
ItemStat1: Type: 6 (SPIRIT) Value: 321
|
||||
ItemStat2: Type: 7 (STAMINA) Value: 334
|
||||
ItemStat3: Type: 32 (CRIT_RATING) Value: 172
|
||||
ItemStat4: Type: 45 (SPELL_POWER) Value: 155
|
||||
ItemStat5: Type: 5 (INTELLECT) Value: 281
|
||||
ItemStat6: Type: 0 (MANA) Value: 0
|
||||
ItemStat7: Type: 0 (MANA) Value: 0
|
||||
ItemStat8: Type: 0 (MANA) Value: 0
|
||||
Item: Lawbringer Gauntlets Entry: 16860 lookup up Class: 4 Subclass: 4
|
||||
<<<< High Level Items that match class Type: Healer 7 >>>>>
|
||||
New Item: Lawbringer Gauntlets Entry: 16860
|
||||
ItemStat1: Type: 4 (STRENGTH) Value: 214
|
||||
ItemStat2: Type: 45 (SPELL_POWER) Value: 155
|
||||
ItemStat3: Type: 5 (INTELLECT) Value: 321
|
||||
ItemStat4: Type: 6 (SPIRIT) Value: 308
|
||||
ItemStat5: Type: 7 (STAMINA) Value: 349
|
||||
ItemStat6: Type: 0 (MANA) Value: 0
|
||||
ItemStat7: Type: 0 (MANA) Value: 0
|
||||
ItemStat8: Type: 0 (MANA) Value: 0
|
||||
2238
cmd/raid-gear/main.go
Normal file
2238
cmd/raid-gear/main.go
Normal file
File diff suppressed because it is too large
Load Diff
225
converter.go
225
converter.go
@@ -1,225 +0,0 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
"github.com/araxiaonline/endgame-item-generator/models"
|
||||
)
|
||||
|
||||
// convert an item to a create sql statement
|
||||
func ItemToSql(item models.Item, reqLevel int, difficulty int) string {
|
||||
|
||||
entryBump := 20000000
|
||||
spellBump := 30000000
|
||||
if difficulty == 4 {
|
||||
entryBump = 21000000
|
||||
}
|
||||
if difficulty == 5 {
|
||||
entryBump = 22000000
|
||||
}
|
||||
|
||||
if *item.Quality == 4 {
|
||||
spellBump = 31000000
|
||||
}
|
||||
if *item.Quality == 5 {
|
||||
spellBump = 32000000
|
||||
}
|
||||
|
||||
spells := ""
|
||||
if len(item.Spells) > 0 {
|
||||
for i, spell := range item.Spells {
|
||||
spells += SpellToSql(spell, *item.Quality)
|
||||
item.UpdateField(fmt.Sprintf("SpellId%v", i), spellBump+spell.ID)
|
||||
}
|
||||
}
|
||||
|
||||
delete := fmt.Sprintf("DELETE FROM acore_world.item_template WHERE entry = %v;", entryBump+item.Entry)
|
||||
|
||||
clone := fmt.Sprintf(`
|
||||
INSERT INTO acore_world.item_template (
|
||||
entry, class, subclass, SoundOverrideSubclass, name, displayid, Quality, Flags, FlagsExtra, BuyCount,
|
||||
BuyPrice, SellPrice, InventoryType, AllowableClass, AllowableRace, ItemLevel, RequiredLevel,
|
||||
RequiredSkill, RequiredSkillRank, requiredspell, requiredhonorrank, RequiredCityRank,
|
||||
RequiredReputationFaction, RequiredReputationRank, maxcount, stackable, ContainerSlots, StatsCount,
|
||||
stat_type1, stat_value1, stat_type2, stat_value2, stat_type3, stat_value3, stat_type4, stat_value4,
|
||||
stat_type5, stat_value5, stat_type6, stat_value6, stat_type7, stat_value7, stat_type8, stat_value8,
|
||||
stat_type9, stat_value9, stat_type10, stat_value10, ScalingStatDistribution, ScalingStatValue,
|
||||
dmg_min1, dmg_max1, dmg_type1, dmg_min2, dmg_max2, dmg_type2, armor, holy_res, fire_res, nature_res,
|
||||
frost_res, shadow_res, arcane_res, delay, ammo_type, RangedModRange, spellid_1, spelltrigger_1,
|
||||
spellcharges_1, spellppmRate_1, spellcooldown_1, spellcategory_1, spellcategorycooldown_1, spellid_2,
|
||||
spelltrigger_2, spellcharges_2, spellppmRate_2, spellcooldown_2, spellcategory_2, spellcategorycooldown_2,
|
||||
spellid_3, spelltrigger_3, spellcharges_3, spellppmRate_3, spellcooldown_3, spellcategory_3,
|
||||
spellcategorycooldown_3, spellid_4, spelltrigger_4, spellcharges_4, spellppmRate_4, spellcooldown_4,
|
||||
spellcategory_4, spellcategorycooldown_4, spellid_5, spelltrigger_5, spellcharges_5, spellppmRate_5,
|
||||
spellcooldown_5, spellcategory_5, spellcategorycooldown_5, bonding, description, PageText, LanguageID,
|
||||
PageMaterial, startquest, lockid, Material, sheath, RandomProperty, RandomSuffix, block, itemset,
|
||||
MaxDurability, area, Map, BagFamily, TotemCategory, socketColor_1, socketContent_1, socketColor_2,
|
||||
socketContent_2, socketColor_3, socketContent_3, socketBonus, GemProperties, RequiredDisenchantSkill,
|
||||
ArmorDamageModifier, duration, ItemLimitCategory, HolidayId, ScriptName, DisenchantID, FoodType,
|
||||
minMoneyLoot, maxMoneyLoot, flagsCustom, VerifiedBuild
|
||||
)
|
||||
SELECT
|
||||
entry + %v, class, subclass, SoundOverrideSubclass, name, displayid, Quality, Flags, FlagsExtra, BuyCount,
|
||||
BuyPrice, SellPrice, InventoryType, AllowableClass, AllowableRace, ItemLevel, RequiredLevel,
|
||||
RequiredSkill, RequiredSkillRank, requiredspell, requiredhonorrank, RequiredCityRank,
|
||||
RequiredReputationFaction, RequiredReputationRank, maxcount, stackable, ContainerSlots, StatsCount,
|
||||
stat_type1, stat_value1, stat_type2, stat_value2, stat_type3, stat_value3, stat_type4, stat_value4,
|
||||
stat_type5, stat_value5, stat_type6, stat_value6, stat_type7, stat_value7, stat_type8, stat_value8,
|
||||
stat_type9, stat_value9, stat_type10, stat_value10, ScalingStatDistribution, ScalingStatValue,
|
||||
dmg_min1, dmg_max1, dmg_type1, dmg_min2, dmg_max2, dmg_type2, armor, holy_res, fire_res, nature_res,
|
||||
frost_res, shadow_res, arcane_res, delay, ammo_type, RangedModRange, spellid_1, spelltrigger_1,
|
||||
spellcharges_1, spellppmRate_1, spellcooldown_1, spellcategory_1, spellcategorycooldown_1, spellid_2,
|
||||
spelltrigger_2, spellcharges_2, spellppmRate_2, spellcooldown_2, spellcategory_2, spellcategorycooldown_2,
|
||||
spellid_3, spelltrigger_3, spellcharges_3, spellppmRate_3, spellcooldown_3, spellcategory_3,
|
||||
spellcategorycooldown_3, spellid_4, spelltrigger_4, spellcharges_4, spellppmRate_4, spellcooldown_4,
|
||||
spellcategory_4, spellcategorycooldown_4, spellid_5, spelltrigger_5, spellcharges_5, spellppmRate_5,
|
||||
spellcooldown_5, spellcategory_5, spellcategorycooldown_5, bonding, description, PageText, LanguageID,
|
||||
PageMaterial, startquest, lockid, Material, sheath, RandomProperty, RandomSuffix, block, itemset,
|
||||
MaxDurability, area, Map, BagFamily, TotemCategory, socketColor_1, socketContent_1, socketColor_2,
|
||||
socketContent_2, socketColor_3, socketContent_3, socketBonus, GemProperties, RequiredDisenchantSkill,
|
||||
ArmorDamageModifier, duration, ItemLimitCategory, HolidayId, ScriptName, DisenchantID, FoodType,
|
||||
minMoneyLoot, maxMoneyLoot, flagsCustom, VerifiedBuild
|
||||
FROM acore_world.item_template as src
|
||||
WHERE src.entry = %v ON DUPLICATE KEY UPDATE entry = src.entry + %v;
|
||||
`, entryBump, item.Entry, entryBump)
|
||||
|
||||
update := fmt.Sprintf(`
|
||||
UPDATE acore_world.item_template
|
||||
SET
|
||||
Quality = %v,
|
||||
ItemLevel = %v,
|
||||
RequiredLevel = %v,
|
||||
dmg_min1 = %v,
|
||||
dmg_max1 = %v,
|
||||
dmg_min2 = %v,
|
||||
dmg_max2 = %v,
|
||||
StatsCount = %v,
|
||||
stat_type1 = %v,
|
||||
stat_value1 = %v,
|
||||
stat_type2 = %v,
|
||||
stat_value2 = %v,
|
||||
stat_type3 = %v,
|
||||
stat_value3 = %v,
|
||||
stat_type4 = %v,
|
||||
stat_value4 = %v,
|
||||
stat_type5 = %v,
|
||||
stat_value5 = %v,
|
||||
stat_type6 = %v,
|
||||
stat_value6 = %v,
|
||||
stat_type7 = %v,
|
||||
stat_value7 = %v,
|
||||
stat_type8 = %v,
|
||||
stat_value8 = %v,
|
||||
stat_type9 = %v,
|
||||
stat_value9 = %v,
|
||||
stat_type10 = %v,
|
||||
stat_value10 = %v,
|
||||
spellid_1 = %v,
|
||||
spellid_2 = %v,
|
||||
spellid_3 = %v,
|
||||
RequiredDisenchantSkill = %v,
|
||||
DisenchantID = %v,
|
||||
SellPrice = FLOOR(100000 + (RAND() * 400001)),
|
||||
Armor = %v
|
||||
WHERE entry = %v;
|
||||
`, *item.Quality, *item.ItemLevel, reqLevel, *item.MinDmg1, *item.MaxDmg1, *item.MinDmg2, *item.MaxDmg2, *item.StatsCount,
|
||||
*item.StatType1, *item.StatValue1, *item.StatType2, *item.StatValue2, *item.StatType3, *item.StatValue3, *item.StatType4, *item.StatValue4,
|
||||
*item.StatType5, *item.StatValue5, *item.StatType6, *item.StatValue6, *item.StatType7, *item.StatValue7, *item.StatType8, *item.StatValue8,
|
||||
*item.StatType9, *item.StatValue9, *item.StatType10, *item.StatValue10, *item.SpellId1, *item.SpellId2, *item.SpellId3, 375,
|
||||
68, *item.Armor, entryBump+item.Entry)
|
||||
|
||||
return fmt.Sprintf("%s %s \n %s \n %s", spells, delete, clone, update)
|
||||
}
|
||||
|
||||
func SpellToSql(spell models.Spell, quality int) string {
|
||||
|
||||
entryBump := 30000000
|
||||
if quality == 4 {
|
||||
entryBump = 31000000
|
||||
}
|
||||
if quality == 5 {
|
||||
entryBump = 32000000
|
||||
}
|
||||
|
||||
insert := fmt.Sprintf(`
|
||||
INSERT IGNORE INTO acore_world.spell_dbc (
|
||||
ID, Category, DispelType, Mechanic, Attributes, AttributesEx, AttributesEx2, AttributesEx3, AttributesEx4,
|
||||
AttributesEx5, AttributesEx6, AttributesEx7, ShapeshiftMask, unk_320_2, ShapeshiftExclude, unk_320_3, Targets,
|
||||
TargetCreatureType, RequiresSpellFocus, FacingCasterFlags, CasterAuraState, TargetAuraState, ExcludeCasterAuraState,
|
||||
ExcludeTargetAuraState, CasterAuraSpell, TargetAuraSpell, ExcludeCasterAuraSpell, ExcludeTargetAuraSpell, CastingTimeIndex,
|
||||
RecoveryTime, CategoryRecoveryTime, InterruptFlags, AuraInterruptFlags, ChannelInterruptFlags, ProcTypeMask, ProcChance,
|
||||
ProcCharges, MaxLevel, BaseLevel, SpellLevel, DurationIndex, PowerType, ManaCost, ManaCostPerLevel, ManaPerSecond,
|
||||
ManaPerSecondPerLevel, RangeIndex, Speed, ModalNextSpell, CumulativeAura, Totem_1, Totem_2, Reagent_1, Reagent_2, Reagent_3,
|
||||
Reagent_4, Reagent_5, Reagent_6, Reagent_7, Reagent_8, ReagentCount_1, ReagentCount_2, ReagentCount_3, ReagentCount_4,
|
||||
ReagentCount_5, ReagentCount_6, ReagentCount_7, ReagentCount_8, EquippedItemClass, EquippedItemSubclass, EquippedItemInvTypes,
|
||||
Effect_1, Effect_2, Effect_3, EffectDieSides_1, EffectDieSides_2, EffectDieSides_3, EffectRealPointsPerLevel_1,
|
||||
EffectRealPointsPerLevel_2, EffectRealPointsPerLevel_3, EffectBasePoints_1, EffectBasePoints_2, EffectBasePoints_3,
|
||||
EffectMechanic_1, EffectMechanic_2, EffectMechanic_3, ImplicitTargetA_1, ImplicitTargetA_2, ImplicitTargetA_3, ImplicitTargetB_1,
|
||||
ImplicitTargetB_2, ImplicitTargetB_3, EffectRadiusIndex_1, EffectRadiusIndex_2, EffectRadiusIndex_3, EffectAura_1,
|
||||
EffectAura_2, EffectAura_3, EffectAuraPeriod_1, EffectAuraPeriod_2, EffectAuraPeriod_3, EffectMultipleValue_1, EffectMultipleValue_2,
|
||||
EffectMultipleValue_3, EffectChainTargets_1, EffectChainTargets_2, EffectChainTargets_3, EffectItemType_1, EffectItemType_2,
|
||||
EffectItemType_3, EffectMiscValue_1, EffectMiscValue_2, EffectMiscValue_3, EffectMiscValueB_1, EffectMiscValueB_2, EffectMiscValueB_3,
|
||||
EffectTriggerSpell_1, EffectTriggerSpell_2, EffectTriggerSpell_3, EffectPointsPerCombo_1, EffectPointsPerCombo_2, EffectPointsPerCombo_3,
|
||||
EffectSpellClassMaskA_1, EffectSpellClassMaskA_2, EffectSpellClassMaskA_3, EffectSpellClassMaskB_1, EffectSpellClassMaskB_2,
|
||||
EffectSpellClassMaskB_3, EffectSpellClassMaskC_1, EffectSpellClassMaskC_2, EffectSpellClassMaskC_3, SpellVisualID_1, SpellVisualID_2,
|
||||
SpellIconID, ActiveIconID, SpellPriority, Name_Lang_enUS, Name_Lang_enGB, Name_Lang_koKR, Name_Lang_frFR, Name_Lang_deDE,
|
||||
Name_Lang_enCN, Name_Lang_zhCN, Name_Lang_enTW, Name_Lang_zhTW, Name_Lang_esES, Name_Lang_esMX, Name_Lang_ruRU, Name_Lang_ptPT,
|
||||
Name_Lang_ptBR, Name_Lang_itIT, Name_Lang_Unk, Name_Lang_Mask, NameSubtext_Lang_enUS, NameSubtext_Lang_enGB, NameSubtext_Lang_koKR,
|
||||
NameSubtext_Lang_frFR, NameSubtext_Lang_deDE, NameSubtext_Lang_enCN, NameSubtext_Lang_zhCN, NameSubtext_Lang_enTW, NameSubtext_Lang_zhTW,
|
||||
NameSubtext_Lang_esES, NameSubtext_Lang_esMX, NameSubtext_Lang_ruRU, NameSubtext_Lang_ptPT, NameSubtext_Lang_ptBR, NameSubtext_Lang_itIT,
|
||||
NameSubtext_Lang_Unk, NameSubtext_Lang_Mask, Description_Lang_enUS, Description_Lang_enGB, Description_Lang_koKR, Description_Lang_frFR,
|
||||
Description_Lang_deDE, Description_Lang_enCN, Description_Lang_zhCN, Description_Lang_enTW, Description_Lang_zhTW, Description_Lang_esES,
|
||||
Description_Lang_esMX, Description_Lang_ruRU, Description_Lang_ptPT, Description_Lang_ptBR, Description_Lang_itIT, Description_Lang_Unk,
|
||||
Description_Lang_Mask, AuraDescription_Lang_enUS, AuraDescription_Lang_enGB, AuraDescription_Lang_koKR, AuraDescription_Lang_frFR,
|
||||
AuraDescription_Lang_deDE, AuraDescription_Lang_enCN, AuraDescription_Lang_zhCN, AuraDescription_Lang_enTW, AuraDescription_Lang_zhTW,
|
||||
AuraDescription_Lang_esES, AuraDescription_Lang_esMX, AuraDescription_Lang_ruRU, AuraDescription_Lang_ptPT, AuraDescription_Lang_ptBR,
|
||||
AuraDescription_Lang_itIT, AuraDescription_Lang_Unk, AuraDescription_Lang_Mask, ManaCostPct, StartRecoveryCategory, StartRecoveryTime,
|
||||
MaxTargetLevel, SpellClassSet, SpellClassMask_1, SpellClassMask_2, SpellClassMask_3, MaxTargets, DefenseType, PreventionType, StanceBarOrder,
|
||||
EffectChainAmplitude_1, EffectChainAmplitude_2, EffectChainAmplitude_3, MinFactionID, MinReputation, RequiredAuraVision, RequiredTotemCategoryID_1,
|
||||
RequiredTotemCategoryID_2, RequiredAreasID, SchoolMask, RuneCostID, SpellMissileID, PowerDisplayID, EffectBonusMultiplier_1, EffectBonusMultiplier_2,
|
||||
EffectBonusMultiplier_3, SpellDescriptionVariableID, SpellDifficultyID
|
||||
) SELECT
|
||||
ID + %v, Category, DispelType, Mechanic, Attributes, AttributesEx, AttributesEx2, AttributesEx3, AttributesEx4,
|
||||
AttributesEx5, AttributesEx6, AttributesEx7, ShapeshiftMask, unk_320_2, ShapeshiftExclude, unk_320_3, Targets,
|
||||
TargetCreatureType, RequiresSpellFocus, FacingCasterFlags, CasterAuraState, TargetAuraState, ExcludeCasterAuraState,
|
||||
ExcludeTargetAuraState, CasterAuraSpell, TargetAuraSpell, ExcludeCasterAuraSpell, ExcludeTargetAuraSpell, CastingTimeIndex,
|
||||
RecoveryTime, CategoryRecoveryTime, InterruptFlags, AuraInterruptFlags, ChannelInterruptFlags, ProcTypeMask, ProcChance,
|
||||
ProcCharges, MaxLevel, BaseLevel, SpellLevel, DurationIndex, PowerType, ManaCost, ManaCostPerLevel, ManaPerSecond,
|
||||
ManaPerSecondPerLevel, RangeIndex, Speed, ModalNextSpell, CumulativeAura, Totem_1, Totem_2, Reagent_1, Reagent_2, Reagent_3,
|
||||
Reagent_4, Reagent_5, Reagent_6, Reagent_7, Reagent_8, ReagentCount_1, ReagentCount_2, ReagentCount_3, ReagentCount_4,
|
||||
ReagentCount_5, ReagentCount_6, ReagentCount_7, ReagentCount_8, EquippedItemClass, EquippedItemSubclass, EquippedItemInvTypes,
|
||||
Effect_1, Effect_2, Effect_3, EffectDieSides_1, EffectDieSides_2, EffectDieSides_3, EffectRealPointsPerLevel_1,
|
||||
EffectRealPointsPerLevel_2, EffectRealPointsPerLevel_3, EffectBasePoints_1, EffectBasePoints_2, EffectBasePoints_3,
|
||||
EffectMechanic_1, EffectMechanic_2, EffectMechanic_3, ImplicitTargetA_1, ImplicitTargetA_2, ImplicitTargetA_3, ImplicitTargetB_1,
|
||||
ImplicitTargetB_2, ImplicitTargetB_3, EffectRadiusIndex_1, EffectRadiusIndex_2, EffectRadiusIndex_3, EffectAura_1,
|
||||
EffectAura_2, EffectAura_3, EffectAuraPeriod_1, EffectAuraPeriod_2, EffectAuraPeriod_3, EffectMultipleValue_1, EffectMultipleValue_2,
|
||||
EffectMultipleValue_3, EffectChainTargets_1, EffectChainTargets_2, EffectChainTargets_3, EffectItemType_1, EffectItemType_2,
|
||||
EffectItemType_3, EffectMiscValue_1, EffectMiscValue_2, EffectMiscValue_3, EffectMiscValueB_1, EffectMiscValueB_2, EffectMiscValueB_3,
|
||||
EffectTriggerSpell_1, EffectTriggerSpell_2, EffectTriggerSpell_3, EffectPointsPerCombo_1, EffectPointsPerCombo_2, EffectPointsPerCombo_3,
|
||||
EffectSpellClassMaskA_1, EffectSpellClassMaskA_2, EffectSpellClassMaskA_3, EffectSpellClassMaskB_1, EffectSpellClassMaskB_2,
|
||||
EffectSpellClassMaskB_3, EffectSpellClassMaskC_1, EffectSpellClassMaskC_2, EffectSpellClassMaskC_3, SpellVisualID_1, SpellVisualID_2,
|
||||
SpellIconID, ActiveIconID, SpellPriority, Name_Lang_enUS, Name_Lang_enGB, Name_Lang_koKR, Name_Lang_frFR, Name_Lang_deDE,
|
||||
Name_Lang_enCN, Name_Lang_zhCN, Name_Lang_enTW, Name_Lang_zhTW, Name_Lang_esES, Name_Lang_esMX, Name_Lang_ruRU, Name_Lang_ptPT,
|
||||
Name_Lang_ptBR, Name_Lang_itIT, Name_Lang_Unk, Name_Lang_Mask, NameSubtext_Lang_enUS, NameSubtext_Lang_enGB, NameSubtext_Lang_koKR,
|
||||
NameSubtext_Lang_frFR, NameSubtext_Lang_deDE, NameSubtext_Lang_enCN, NameSubtext_Lang_zhCN, NameSubtext_Lang_enTW, NameSubtext_Lang_zhTW,
|
||||
NameSubtext_Lang_esES, NameSubtext_Lang_esMX, NameSubtext_Lang_ruRU, NameSubtext_Lang_ptPT, NameSubtext_Lang_ptBR, NameSubtext_Lang_itIT,
|
||||
NameSubtext_Lang_Unk, NameSubtext_Lang_Mask, Description_Lang_enUS, Description_Lang_enGB, Description_Lang_koKR, Description_Lang_frFR,
|
||||
Description_Lang_deDE, Description_Lang_enCN, Description_Lang_zhCN, Description_Lang_enTW, Description_Lang_zhTW, Description_Lang_esES,
|
||||
Description_Lang_esMX, Description_Lang_ruRU, Description_Lang_ptPT, Description_Lang_ptBR, Description_Lang_itIT, Description_Lang_Unk,
|
||||
Description_Lang_Mask, AuraDescription_Lang_enUS, AuraDescription_Lang_enGB, AuraDescription_Lang_koKR, AuraDescription_Lang_frFR,
|
||||
AuraDescription_Lang_deDE, AuraDescription_Lang_enCN, AuraDescription_Lang_zhCN, AuraDescription_Lang_enTW, AuraDescription_Lang_zhTW,
|
||||
AuraDescription_Lang_esES, AuraDescription_Lang_esMX, AuraDescription_Lang_ruRU, AuraDescription_Lang_ptPT, AuraDescription_Lang_ptBR,
|
||||
AuraDescription_Lang_itIT, AuraDescription_Lang_Unk, AuraDescription_Lang_Mask, ManaCostPct, StartRecoveryCategory, StartRecoveryTime,
|
||||
MaxTargetLevel, SpellClassSet, SpellClassMask_1, SpellClassMask_2, SpellClassMask_3, MaxTargets, DefenseType, PreventionType, StanceBarOrder,
|
||||
EffectChainAmplitude_1, EffectChainAmplitude_2, EffectChainAmplitude_3, MinFactionID, MinReputation, RequiredAuraVision, RequiredTotemCategoryID_1,
|
||||
RequiredTotemCategoryID_2, RequiredAreasID, SchoolMask, RuneCostID, SpellMissileID, PowerDisplayID, EffectBonusMultiplier_1, EffectBonusMultiplier_2,
|
||||
EffectBonusMultiplier_3, SpellDescriptionVariableID, SpellDifficultyID from acore_world.spell_dbc as src
|
||||
WHERE src.ID = %v ON DUPLICATE KEY UPDATE ID = src.ID + %v;`, entryBump, spell.ID, entryBump)
|
||||
|
||||
update := fmt.Sprintf(`
|
||||
UPDATE acore_world.spell_dbc
|
||||
SET EffectBasePoints_1 = %v, EffectBasePoints_2 = %v
|
||||
WHERE ID = %v;`, spell.EffectBasePoints1, spell.EffectBasePoints2, entryBump+spell.ID)
|
||||
|
||||
return fmt.Sprintf("\n %s \n %s \n", insert, update)
|
||||
}
|
||||
File diff suppressed because it is too large
Load Diff
BIN
data/dbc/DurabilityCosts.dbc
Normal file
BIN
data/dbc/DurabilityCosts.dbc
Normal file
Binary file not shown.
1493
data/items.csv
Normal file
1493
data/items.csv
Normal file
File diff suppressed because it is too large
Load Diff
BIN
data/items.db
Normal file
BIN
data/items.db
Normal file
Binary file not shown.
BIN
data/items.sqlite
Normal file
BIN
data/items.sqlite
Normal file
Binary file not shown.
178321
data/legend-scaled.sql
Normal file
178321
data/legend-scaled.sql
Normal file
File diff suppressed because it is too large
Load Diff
1528364
data/mythic-scaled.sql
Normal file
1528364
data/mythic-scaled.sql
Normal file
File diff suppressed because it is too large
Load Diff
17
go.mod
17
go.mod
@@ -2,13 +2,14 @@ module github.com/araxiaonline/endgame-item-generator
|
||||
|
||||
go 1.22.4
|
||||
|
||||
replace github.com/araxiaonline/endgame-item-generator/models => ../models
|
||||
|
||||
require github.com/go-sql-driver/mysql v1.8.1
|
||||
|
||||
require (
|
||||
filippo.io/edwards25519 v1.1.0 // indirect
|
||||
github.com/jmoiron/sqlx v1.4.0 // indirect
|
||||
github.com/joho/godotenv v1.5.1 // indirect
|
||||
github.com/thoas/go-funk v0.9.3 // indirect
|
||||
github.com/go-sql-driver/mysql v1.8.1
|
||||
github.com/gocarina/gocsv v0.0.0-20240520201108-78e41c74b4b1
|
||||
github.com/jmoiron/sqlx v1.4.0
|
||||
github.com/joho/godotenv v1.5.1
|
||||
github.com/mattn/go-sqlite3 v1.14.22
|
||||
github.com/thoas/go-funk v0.9.3
|
||||
golang.org/x/exp v0.0.0-20240808152545-0cdaa3abc0fa
|
||||
)
|
||||
|
||||
require filippo.io/edwards25519 v1.1.0 // indirect
|
||||
|
||||
10
go.sum
10
go.sum
@@ -1,18 +1,28 @@
|
||||
filippo.io/edwards25519 v1.1.0 h1:FNf4tywRC1HmFuKW5xopWpigGjJKiJSV0Cqo0cJWDaA=
|
||||
filippo.io/edwards25519 v1.1.0/go.mod h1:BxyFTGdWcka3PhytdK4V28tE5sGfRvvvRV7EaN4VDT4=
|
||||
github.com/davecgh/go-spew v1.1.0 h1:ZDRjVQ15GmhC3fiQ8ni8+OwkZQO4DARzQgrnXU1Liz8=
|
||||
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||
github.com/go-sql-driver/mysql v1.8.1 h1:LedoTUt/eveggdHS9qUFC1EFSa8bU2+1pZjSRpvNJ1Y=
|
||||
github.com/go-sql-driver/mysql v1.8.1/go.mod h1:wEBSXgmK//2ZFJyE+qWnIsVGmvmEKlqwuVSjsCm7DZg=
|
||||
github.com/gocarina/gocsv v0.0.0-20240520201108-78e41c74b4b1 h1:FWNFq4fM1wPfcK40yHE5UO3RUdSNPaBC+j3PokzA6OQ=
|
||||
github.com/gocarina/gocsv v0.0.0-20240520201108-78e41c74b4b1/go.mod h1:5YoVOkjYAQumqlV356Hj3xeYh4BdZuLE0/nRkf2NKkI=
|
||||
github.com/jmoiron/sqlx v1.4.0 h1:1PLqN7S1UYp5t4SrVVnt4nUVNemrDAtxlulVe+Qgm3o=
|
||||
github.com/jmoiron/sqlx v1.4.0/go.mod h1:ZrZ7UsYB/weZdl2Bxg6jCRO9c3YHl8r3ahlKmRT4JLY=
|
||||
github.com/joho/godotenv v1.5.1 h1:7eLL/+HRGLY0ldzfGMeQkb7vMd0as4CfYvUVzLqw0N0=
|
||||
github.com/joho/godotenv v1.5.1/go.mod h1:f4LDr5Voq0i2e/R5DDNOoa2zzDfwtkZa6DnEwAbqwq4=
|
||||
github.com/lib/pq v1.10.9 h1:YXG7RB+JIjhP29X+OtkiDnYaXQwpS4JEWq7dtCCRUEw=
|
||||
github.com/lib/pq v1.10.9/go.mod h1:AlVN5x4E4T544tWzH6hKfbfQvm3HdbOxrmggDNAPY9o=
|
||||
github.com/mattn/go-sqlite3 v1.14.22 h1:2gZY6PC6kBnID23Tichd1K+Z0oS6nE/XwU+Vz/5o4kU=
|
||||
github.com/mattn/go-sqlite3 v1.14.22/go.mod h1:Uh1q+B4BYcTPb+yiD3kU8Ct7aC0hY9fxUwlHK0RXw+Y=
|
||||
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
|
||||
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
|
||||
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
|
||||
github.com/stretchr/testify v1.4.0 h1:2E4SXV/wtOkTonXsotYi4li6zVWxYlZuYNCXe9XRJyk=
|
||||
github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4=
|
||||
github.com/thoas/go-funk v0.9.3 h1:7+nAEx3kn5ZJcnDm2Bh23N2yOtweO14bi//dvRtgLpw=
|
||||
github.com/thoas/go-funk v0.9.3/go.mod h1:+IWnUfUmFO1+WVYQWQtIJHeRRdaIyyYglZN7xzUPe4Q=
|
||||
golang.org/x/exp v0.0.0-20240808152545-0cdaa3abc0fa h1:ELnwvuAXPNtPk1TJRuGkI9fDTwym6AYBu0qzT8AcHdI=
|
||||
golang.org/x/exp v0.0.0-20240808152545-0cdaa3abc0fa/go.mod h1:akd2r19cwCdwSwWeIdzYQGa/EZZyqcOdwWiwj5L5eKQ=
|
||||
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||
gopkg.in/yaml.v2 v2.2.2 h1:ZCJp+EgiOT7lHqUV2J862kp8Qj64Jo6az82+3Td9dZw=
|
||||
gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
||||
|
||||
10
internal/config/itemLevels.go
Normal file
10
internal/config/itemLevels.go
Normal file
@@ -0,0 +1,10 @@
|
||||
package config
|
||||
|
||||
var MythicItemLevelStart = 300
|
||||
var MythicItemLevelEnd = 340
|
||||
|
||||
var LegendaryItemLevelStart = 340
|
||||
var LegendaryItemLevelEnd = 379
|
||||
|
||||
var AscendantItemLevelStart = 380
|
||||
var AscendantItemLevelEnd = 419
|
||||
200
internal/config/modifier.go
Normal file
200
internal/config/modifier.go
Normal file
@@ -0,0 +1,200 @@
|
||||
package config
|
||||
|
||||
// modifiers to stats based on inventory type
|
||||
var InvTypeModifiers = map[int]float64{
|
||||
0: 0.6, // Trinket
|
||||
1: 0.813, // Head
|
||||
2: 1.0, // Neck
|
||||
3: 0.75, // Shoulder
|
||||
5: 0.95, // Chest
|
||||
6: 0.562, // Waist
|
||||
7: 0.875, // Legs
|
||||
8: 0.688, // Feet
|
||||
9: 0.437, // Wrists
|
||||
10: 0.625, // Hands
|
||||
11: 1.0, // Finger
|
||||
13: 0.70, // One-Hand (not to confuse with Off-Hand = 22)
|
||||
14: 0.66, // Shield (class = armor, not weapon even if in weapon slot)
|
||||
15: 0.32, // Ranged (Bows) (see also Ranged right = 26)
|
||||
16: 0.70, // Back
|
||||
17: 1.3, // Two-Hand
|
||||
18: 1.0, // Bag (assuming same as Chest for simplicity)
|
||||
19: 1.0, // Tabard (assuming same as Chest for simplicity)
|
||||
20: 1.0, // Robe (see also Chest = 5)
|
||||
21: 0.85, // Main hand
|
||||
22: 0.65, // Off Hand weapons (see also One-Hand = 13)
|
||||
23: 0.60, // Held in Off-Hand (class = armor, not weapon even if in weapon slot)
|
||||
24: 1.0, // Ammo (assuming same as Chest for simplicity)
|
||||
25: 0.38, // Thrown
|
||||
26: 0.38, // Ranged right (Wands, Guns) (see also Ranged = 15)
|
||||
27: 1.0, // Quiver (assuming same as Chest for simplicity)
|
||||
}
|
||||
|
||||
var QualityModifiers = map[int]float64{
|
||||
0: 0.8, // Poor
|
||||
1: 0.9, // Common
|
||||
2: 1.0, // UnCommon
|
||||
3: 1.2, // Rare
|
||||
4: 1.5, // Epic
|
||||
5: 2.0, // Legendary
|
||||
}
|
||||
|
||||
var MaterialModifiers = map[int]float64{
|
||||
1: 1.2, // Cloth
|
||||
2: 2.2, // Leather
|
||||
3: 4.75, // Mail
|
||||
4: 9.0, // Plate
|
||||
6: 20.0, // Plate
|
||||
}
|
||||
|
||||
// Modifies stats flat for difficulty of dungeon / raid itself.
|
||||
var GearTierModifiers = map[int]float64{
|
||||
1: 1.25,
|
||||
2: 1.50,
|
||||
3: 1.75,
|
||||
4: 2.00,
|
||||
5: 2.25,
|
||||
}
|
||||
|
||||
// how much a stat weighs against the stat point pool based on iLevel
|
||||
var StatModifiers = map[int]float64{
|
||||
0: 1.0, // ITEM_MOD_MANA
|
||||
1: 1.0, // ITEM_MOD_HEALTH
|
||||
3: 1.0, // ITEM_MOD_AGILITY
|
||||
4: 1.0, // ITEM_MOD_STRENGTH
|
||||
5: 1.0, // ITEM_MOD_INTELLECT
|
||||
6: 1.0, // ITEM_MOD_SPIRIT
|
||||
7: 1.0, // ITEM_MOD_STAMINA
|
||||
12: 1.5, // ITEM_MOD_DEFENSE_SKILL_RATING
|
||||
13: 1.0, // ITEM_MOD_DODGE_RATING
|
||||
14: 1.0, // ITEM_MOD_PARRY_RATING
|
||||
15: 0.8, // ITEM_MOD_BLOCK_RATING
|
||||
16: 1.0, // ITEM_MOD_HIT_MELEE_RATING
|
||||
17: 1.0, // ITEM_MOD_HIT_RANGED_RATING
|
||||
18: 1.0, // ITEM_MOD_HIT_SPELL_RATING
|
||||
19: 1.0, // ITEM_MOD_CRIT_MELEE_RATING
|
||||
20: 1.0, // ITEM_MOD_CRIT_RANGED_RATING
|
||||
21: 1.0, // ITEM_MOD_CRIT_SPELL_RATING
|
||||
22: 1.0, // ITEM_MOD_HIT_TAKEN_MELEE_RATING
|
||||
23: 1.0, // ITEM_MOD_HIT_TAKEN_RANGED_RATING
|
||||
24: 1.0, // ITEM_MOD_HIT_TAKEN_SPELL_RATING
|
||||
25: 1.0, // ITEM_MOD_CRIT_TAKEN_MELEE_RATING
|
||||
26: 1.0, // ITEM_MOD_CRIT_TAKEN_RANGED_RATING
|
||||
27: 1.0, // ITEM_MOD_CRIT_TAKEN_SPELL_RATING
|
||||
28: 1.0, // ITEM_MOD_HASTE_MELEE_RATING
|
||||
29: 1.0, // ITEM_MOD_HASTE_RANGED_RATING
|
||||
30: 1.0, // ITEM_MOD_HASTE_SPELL_RATING
|
||||
31: 1.3, // ITEM_MOD_HIT_RATING
|
||||
32: 1.0, // ITEM_MOD_CRIT_RATING
|
||||
33: 1.0, // ITEM_MOD_HIT_TAKEN_RATING
|
||||
34: 1.0, // ITEM_MOD_CRIT_TAKEN_RATING
|
||||
35: 1.0, // ITEM_MOD_RESILIENCE_RATING
|
||||
36: 1.0, // ITEM_MOD_HASTE_RATING
|
||||
37: 1.5, // ITEM_MOD_EXPERTISE_RATING
|
||||
38: 0.65, // ITEM_MOD_ATTACK_POWER
|
||||
39: 0.70, // ITEM_MOD_RANGED_ATTACK_POWER
|
||||
40: 0.95, // ITEM_MOD_FERAL_ATTACK_POWER (not used as of 3.3)
|
||||
41: 0.95, // ITEM_MOD_SPELL_HEALING_DONE
|
||||
42: 0.95, // ITEM_MOD_SPELL_DAMAGE_DONE
|
||||
43: 2.0, // ITEM_MOD_MANA_REGENERATION
|
||||
44: 1.3, // ITEM_MOD_ARMOR_PENETRATION_RATING
|
||||
45: 0.95, // ITEM_MOD_SPELL_POWER
|
||||
46: 1.0, // ITEM_MOD_HEALTH_REGEN
|
||||
47: 1.2, // ITEM_MOD_SPELL_PENETRATION
|
||||
48: 1.5, // ITEM_MOD_BLOCK_VALUE
|
||||
}
|
||||
|
||||
var StatModifierNames = map[int]string{
|
||||
0: "MANA",
|
||||
1: "HEALTH",
|
||||
3: "AGILITY",
|
||||
4: "STRENGTH",
|
||||
5: "INTELLECT",
|
||||
6: "SPIRIT",
|
||||
7: "STAMINA",
|
||||
12: "DEFENSE_SKILL_RATING",
|
||||
13: "DODGE_RATING",
|
||||
14: "PARRY_RATING",
|
||||
15: "BLOCK_RATING",
|
||||
16: "HIT_MELEE_RATING",
|
||||
17: "HIT_RANGED_RATING",
|
||||
18: "HIT_SPELL_RATING",
|
||||
19: "CRIT_MELEE_RATING",
|
||||
20: "CRIT_RANGED_RATING",
|
||||
21: "CRIT_SPELL_RATING",
|
||||
22: "HIT_TAKEN_MELEE_RATING",
|
||||
23: "HIT_TAKEN_RANGED_RATING",
|
||||
24: "HIT_TAKEN_SPELL_RATING",
|
||||
25: "CRIT_TAKEN_MELEE_RATING",
|
||||
26: "CRIT_TAKEN_RANGED_RATING",
|
||||
27: "CRIT_TAKEN_SPELL_RATING",
|
||||
28: "HASTE_MELEE_RATING",
|
||||
29: "HASTE_RANGED_RATING",
|
||||
30: "HASTE_SPELL_RATING",
|
||||
31: "HIT_RATING",
|
||||
32: "CRIT_RATING",
|
||||
33: "HIT_TAKEN_RATING",
|
||||
34: "CRIT_TAKEN_RATING",
|
||||
35: "RESILIENCE_RATING",
|
||||
36: "HASTE_RATING",
|
||||
37: "EXPERTISE_RATING",
|
||||
38: "ATTACK_POWER",
|
||||
39: "RANGED_ATTACK_POWER",
|
||||
40: "FERAL_ATTACK_POWER",
|
||||
41: "SPELL_HEALING_DONE",
|
||||
42: "SPELL_DAMAGE_DONE",
|
||||
43: "MANA_REGENERATION",
|
||||
44: "ARMOR_PENETRATION_RATING",
|
||||
45: "SPELL_POWER",
|
||||
46: "HEALTH_REGEN",
|
||||
47: "SPELL_PENETRATION",
|
||||
48: "BLOCK_VALUE",
|
||||
}
|
||||
|
||||
// how much a bonus to apply
|
||||
var ScalingFactor = map[int]float64{
|
||||
0: 1.1, // ITEM_MOD_MANA
|
||||
1: 1.2, // ITEM_MOD_HEALTH
|
||||
3: 1.35, // ITEM_MOD_AGILITY
|
||||
4: 1.35, // ITEM_MOD_STRENGTH
|
||||
5: 1.35, // ITEM_MOD_INTELLECT
|
||||
6: 1.35, // ITEM_MOD_SPIRIT
|
||||
7: 1.40, // ITEM_MOD_STAMINA
|
||||
12: 1.25, // ITEM_MOD_DEFENSE_SKILL_RATING
|
||||
13: 1.0, // ITEM_MOD_DODGE_RATING
|
||||
14: 0.85, // ITEM_MOD_PARRY_RATING
|
||||
15: 1.15, // ITEM_MOD_BLOCK_RATING
|
||||
16: 1.0, // ITEM_MOD_HIT_MELEE_RATING
|
||||
17: 1.1, // ITEM_MOD_HIT_RANGED_RATING
|
||||
18: 1.1, // ITEM_MOD_HIT_SPELL_RATING
|
||||
19: 1.2, // ITEM_MOD_CRIT_MELEE_RATING
|
||||
20: 1.2, // ITEM_MOD_CRIT_RANGED_RATING
|
||||
21: 1.3, // ITEM_MOD_CRIT_SPELL_RATING
|
||||
22: 1.3, // ITEM_MOD_HIT_TAKEN_MELEE_RATING
|
||||
23: 1.3, // ITEM_MOD_HIT_TAKEN_RANGED_RATING
|
||||
24: 1.3, // ITEM_MOD_HIT_TAKEN_SPELL_RATING
|
||||
25: 1.3, // ITEM_MOD_CRIT_TAKEN_MELEE_RATING
|
||||
26: 1.3, // ITEM_MOD_CRIT_TAKEN_RANGED_RATING
|
||||
27: 1.3, // ITEM_MOD_CRIT_TAKEN_SPELL_RATING
|
||||
28: 1.0, // ITEM_MOD_HASTE_MELEE_RATING
|
||||
29: 1.0, // ITEM_MOD_HASTE_RANGED_RATING
|
||||
30: 1.0, // ITEM_MOD_HASTE_SPELL_RATING
|
||||
31: 1.15, // ITEM_MOD_HIT_RATING
|
||||
32: 1.30, // ITEM_MOD_CRIT_RATING
|
||||
33: 1.3, // ITEM_MOD_HIT_TAKEN_RATING
|
||||
34: 1.3, // ITEM_MOD_CRIT_TAKEN_RATING
|
||||
35: 1.0, // ITEM_MOD_RESILIENCE_RATING
|
||||
36: 1.0, // ITEM_MOD_HASTE_RATING
|
||||
37: 0.8, // ITEM_MOD_EXPERTISE_RATING
|
||||
38: 1.0, // ITEM_MOD_ATTACK_POWER
|
||||
39: 1.0, // ITEM_MOD_RANGED_ATTACK_POWER
|
||||
40: 1.0, // ITEM_MOD_FERAL_ATTACK_POWER (not used as of 3.3)
|
||||
41: 1.0, // ITEM_MOD_SPELL_HEALING_DONE
|
||||
42: 1.0, // ITEM_MOD_SPELL_DAMAGE_DONE
|
||||
43: 1.0, // ITEM_MOD_MANA_REGENERATION
|
||||
44: 1.1, // ITEM_MOD_ARMOR_PENETRATION_RATING
|
||||
45: 1.0, // ITEM_MOD_SPELL_POWER
|
||||
46: 1.0, // ITEM_MOD_HEALTH_REGEN
|
||||
47: 1.0, // ITEM_MOD_SPELL_PENETRATION
|
||||
48: 1.2, // ITEM_MOD_BLOCK_VALUE
|
||||
}
|
||||
241
internal/db/mysql/creatures.go
Normal file
241
internal/db/mysql/creatures.go
Normal file
@@ -0,0 +1,241 @@
|
||||
package mysql
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
)
|
||||
|
||||
type Boss struct {
|
||||
Entry int
|
||||
Name string
|
||||
ScriptName string `db:"ScriptName"`
|
||||
ExperienceModifier int `db:"ExperienceModifier"`
|
||||
}
|
||||
|
||||
var BossIDs = map[int]bool{
|
||||
11520: true, // Taragaman the Hungerer (Ragefire Chasm)
|
||||
3654: true, // Mutanus the Devourer (Wailing Caverns)
|
||||
639: true, // Edwin VanCleef (The Deadmines)
|
||||
4275: true, // Archmage Arugal (Shadowfang Keep)
|
||||
4829: true, // Aku'mai (Blackfathom Deeps)
|
||||
1716: true, // Bazil Thredd (Stormwind Stockade)
|
||||
7800: true, // Mekgineer Thermaplugg (Gnomeregan)
|
||||
4421: true, // Charlga Razorflank (Razorfen Kraul)
|
||||
4543: true, // Bloodmage Thalnos (Scarlet Monastery Graveyard)
|
||||
6487: true, // Arcanist Doan (Scarlet Monastery Library)
|
||||
3975: true, // Herod (Scarlet Monastery Armory)
|
||||
3977: true, // High Inquisitor Whitemane (Scarlet Monastery Cathedral)
|
||||
7358: true, // Amnennar the Coldbringer (Razorfen Downs)
|
||||
2748: true, // Archaedas (Uldaman)
|
||||
7267: true, // Chief Ukorz Sandscalp (Zul'Farrak)
|
||||
12201: true, // Princess Theradras (Maraudon)
|
||||
8443: true, // Avatar of Hakkar (Sunken Temple)
|
||||
9019: true, // Emperor Dagran Thaurissan (Blackrock Depths)
|
||||
9568: true, // Overlord Wyrmthalak (Lower Blackrock Spire)
|
||||
10363: true, // General Drakkisath (Upper Blackrock Spire)
|
||||
11492: true, // Alzzin the Wildshaper (Dire Maul East)
|
||||
11489: true, // Tendris Warpwood (Dire Maul West)
|
||||
11501: true, // King Gordok (Dire Maul North)
|
||||
10440: true, // Baron Rivendare (Stratholme Undead Side)
|
||||
10813: true, // Balnazzar (Stratholme Live Side)
|
||||
1853: true, // Darkmaster Gandling (Scholomance)
|
||||
|
||||
17307: true, // Vazruden (Hellfire Ramparts)
|
||||
17536: true, // Nazan (Hellfire Ramparts)
|
||||
17377: true, // Keli'dan the Breaker (The Blood Furnace)
|
||||
16808: true, // Warchief Kargath Bladefist (The Shattered Halls)
|
||||
17942: true, // Quagmirran (The Slave Pens)
|
||||
17826: true, // Swamplord Musel'ek (The Underbog)
|
||||
17798: true, // Warlord Kalithresh (The Steamvault)
|
||||
18344: true, // Nexus-Prince Shaffar (Mana-Tombs)
|
||||
18373: true, // Exarch Maladaar (Auchenai Crypts)
|
||||
18473: true, // Talon King Ikiss (Sethekk Halls)
|
||||
18708: true, // Murmur (Shadow Labyrinth)
|
||||
19220: true, // Pathaleon the Calculator (The Mechanar)
|
||||
17977: true, // Warp Splinter (The Botanica)
|
||||
20912: true, // Harbinger Skyriss (The Arcatraz)
|
||||
17881: true, // Aeonus (The Black Morass)
|
||||
18096: true, // Epoch Hunter (Old Hillsbrad Foothills)
|
||||
24664: true, // Kael'thas Sunstrider (Magisters' Terrace)
|
||||
|
||||
23954: true, // Ingvar the Plunderer (Utgarde Keep)
|
||||
26723: true, // Keristrasza (The Nexus)
|
||||
29120: true, // Anub'arak (Azjol-Nerub)
|
||||
29311: true, // Herald Volazj (Ahn'kahet: The Old Kingdom)
|
||||
26632: true, // The Prophet Tharon'ja (Drak'Tharon Keep)
|
||||
31134: true, // Cyanigosa (Violet Hold)
|
||||
29306: true, // Gal'darah (Gundrak)
|
||||
27978: true, // Sjonnir the Ironshaper (Halls of Stone)
|
||||
28923: true, // Loken (Halls of Lightning)
|
||||
27656: true, // Ley-Guardian Eregos (The Oculus)
|
||||
26533: true, // Mal'Ganis (Culling of Stratholme)
|
||||
26861: true, // King Ymiron (Utgarde Pinnacle)
|
||||
35451: true, // The Black Knight (Trial of the Champion)
|
||||
36502: true, // Devourer of Souls (Forge of Souls)
|
||||
36658: true, // Scourgelord Tyrannus (Pit of Saron)
|
||||
37226: true, // The Lich King (Halls of Reflection)
|
||||
|
||||
// Molten Core
|
||||
12118: true, // Lucifron
|
||||
11982: true, // Magmadar
|
||||
12259: true, // Gehennas
|
||||
12057: true, // Garr
|
||||
12264: true, // Shazzrah
|
||||
12056: true, // Baron Geddon
|
||||
12098: true, // Sulfuron Harbinger
|
||||
11988: true, // Golemagg the Incinerator
|
||||
12018: true, // Majordomo Executus
|
||||
11502: true, // Ragnaros
|
||||
|
||||
// Blackwing Lair
|
||||
12435: true, // Razorgore the Untamed
|
||||
13020: true, // Vaelastrasz the Corrupt
|
||||
12017: true, // Broodlord Lashlayer
|
||||
11983: true, // Firemaw
|
||||
14601: true, // Ebonroc
|
||||
11981: true, // Flamegor
|
||||
14020: true, // Chromaggus
|
||||
11583: true, // Nefarian
|
||||
|
||||
// Ruins of Ahn'Qiraj
|
||||
15348: true, // Kurinnaxx
|
||||
15341: true, // General Rajaxx
|
||||
15340: true, // Moam
|
||||
15370: true, // Buru the Gorger
|
||||
15369: true, // Ayamiss the Hunter
|
||||
15339: true, // Ossirian the Unscarred
|
||||
|
||||
// Temple of Ahn'Qiraj
|
||||
15263: true, // The Prophet Skeram
|
||||
15516: true, // Battleguard Sartura
|
||||
15510: true, // Fankriss the Unyielding
|
||||
15509: true, // Princess Huhuran
|
||||
15275: true, // Emperor Vek'lor
|
||||
15276: true, // Emperor Vek'nilash
|
||||
15727: true, // C'Thun
|
||||
|
||||
// Zul'Gurub
|
||||
14517: true, // High Priestess Jeklik
|
||||
14507: true, // High Priest Venoxis
|
||||
14510: true, // High Priestess Mar'li
|
||||
14509: true, // High Priest Thekal
|
||||
14515: true, // High Priestess Arlokk
|
||||
14834: true, // Hakkar the Soulflayer
|
||||
11382: true, // Bloodlord Mandokir
|
||||
11380: true, // Jin'do the Hexxer
|
||||
15114: true, // Gahz'ranka
|
||||
15082: true, // Renataki
|
||||
15083: true, // Grilek
|
||||
15084: true, // Hazza'rah
|
||||
15085: true, // Wushoolay
|
||||
|
||||
// Karazhan (Full Boss List)
|
||||
16152: true, // Attumen the Huntsman (Karazhan)
|
||||
15687: true, // Moroes (Karazhan)
|
||||
16457: true, // Maiden of Virtue (Karazhan)
|
||||
17521: true, // The Big Bad Wolf (Karazhan)
|
||||
18168: true, // The Crone (Karazhan)
|
||||
17533: true, // Romulo (Karazhan)
|
||||
17534: true, // Julianne (Karazhan)
|
||||
15691: true, // The Curator (Karazhan)
|
||||
15688: true, // Terestian Illhoof (Karazhan)
|
||||
16524: true, // Shade of Aran (Karazhan)
|
||||
15689: true, // Netherspite (Karazhan)
|
||||
16816: true, // Chess Event / Echo of Medivh (Karazhan)
|
||||
15690: true, // Prince Malchezaar (Karazhan)
|
||||
17225: true, // Nightbane (Karazhan)
|
||||
}
|
||||
|
||||
func (db *MySqlDb) GetBosses(mapId int) ([]Boss, error) {
|
||||
|
||||
if mapId == 0 {
|
||||
return nil, errors.New("mapId cannot be 0")
|
||||
}
|
||||
|
||||
bosses := []Boss{}
|
||||
var sql string
|
||||
|
||||
// 540 is pre-classic dungeons so XP Multiplier is best way to determine bosses / rare mobs
|
||||
if mapId < 540 {
|
||||
sql = `
|
||||
SELECT ct.entry, ct.name, ct.ScriptName, ct.ExperienceModifier from acore_world.creature c
|
||||
JOIN acore_world.creature_template ct ON(c.id1 = ct.entry) WHERE map = ? and ExperienceModifier >= 2;
|
||||
`
|
||||
} else {
|
||||
sql = `
|
||||
SELECT ct.entry, ct.name, ct.ScriptName, ct.ExperienceModifier from acore_world.creature c
|
||||
JOIN acore_world.creature_template ct ON(c.id1 = ct.entry) WHERE map = ? and ct.ScriptName Like 'boss_%'
|
||||
`
|
||||
}
|
||||
|
||||
err := db.Select(&bosses, sql, mapId)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return bosses, nil
|
||||
}
|
||||
|
||||
func (db *MySqlDb) GetBossLoot(bossId int) ([]DbItem, error) {
|
||||
if bossId == 0 {
|
||||
return nil, errors.New("bossId cannot be 0")
|
||||
}
|
||||
|
||||
// This will first find items that are not in the reference boss loot table
|
||||
items := []DbItem{}
|
||||
fields := GetItemFields("")
|
||||
sql := `
|
||||
SELECT ` + fields + `
|
||||
from acore_world.item_template
|
||||
where
|
||||
entry in
|
||||
(SELECT item from acore_world.creature_loot_template where entry = ? and GroupId != 0 and Reference = 0)
|
||||
and Quality > 2
|
||||
`
|
||||
|
||||
udb := db.Unsafe()
|
||||
err := udb.Select(&items, sql, bossId)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// Get all the boss reference items now
|
||||
var references []int
|
||||
sql = `
|
||||
SELECT reference
|
||||
FROM acore_world.creature_loot_template
|
||||
WHERE entry = ? AND Reference != 0
|
||||
`
|
||||
err = db.Select(&references, sql, bossId)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to get references: %v sql %s", err, sql)
|
||||
}
|
||||
|
||||
if len(references) == 0 {
|
||||
return items, nil
|
||||
}
|
||||
|
||||
refItems := []DbItem{}
|
||||
|
||||
// For each reference we now need to get the items and add them to the items slice
|
||||
for _, ref := range references {
|
||||
sql = `
|
||||
SELECT ` + GetItemFields("it") + `
|
||||
FROM acore_world.reference_loot_template rlt
|
||||
JOIN acore_world.item_template it ON rlt.Item = it.entry
|
||||
WHERE rlt.Entry = ? and it.Quality > 2
|
||||
`
|
||||
err = db.Select(&refItems, sql, ref)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to get ref items: %v sql %s", err, sql)
|
||||
}
|
||||
|
||||
items = append(items, refItems...)
|
||||
}
|
||||
|
||||
return items, nil
|
||||
}
|
||||
|
||||
func IsFinalBoss(bossId int) bool {
|
||||
return BossIDs[bossId]
|
||||
}
|
||||
618
internal/db/mysql/items.go
Normal file
618
internal/db/mysql/items.go
Normal file
@@ -0,0 +1,618 @@
|
||||
package mysql
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"log"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/araxiaonline/endgame-item-generator/internal/config"
|
||||
)
|
||||
|
||||
type DbItem struct {
|
||||
Entry int
|
||||
Name string
|
||||
DisplayId int `db:"displayid"`
|
||||
Quality *int
|
||||
ItemLevel *int `db:"ItemLevel"`
|
||||
Class *int
|
||||
Subclass *int
|
||||
Armor *int `db:"armor"`
|
||||
Material *int `db:"material"`
|
||||
InventoryType *int `db:"inventoryType"`
|
||||
AllowableClass *int `db:"allowableClass"`
|
||||
AllowableRace *int `db:"allowableRace"`
|
||||
RequiredSkill *int `db:"requiredSkill"`
|
||||
RequiredLevel *int `db:"requiredLevel"`
|
||||
Durability *int `db:"MaxDurability"`
|
||||
MinDmg1 *float64 `db:"dmg_min1"`
|
||||
MaxDmg1 *float64 `db:"dmg_max1"`
|
||||
MinDmg2 *float64 `db:"dmg_min2"`
|
||||
MaxDmg2 *float64 `db:"dmg_max2"`
|
||||
DmgType1 *int `db:"dmg_type1"`
|
||||
DmgType2 *int `db:"dmg_type2"`
|
||||
Delay *float64
|
||||
Sheath *int
|
||||
StatsCount *int `db:"statsCount"`
|
||||
StatType1 *int `db:"stat_type1"`
|
||||
StatValue1 *int `db:"stat_value1"`
|
||||
StatType2 *int `db:"stat_type2"`
|
||||
StatValue2 *int `db:"stat_value2"`
|
||||
StatType3 *int `db:"stat_type3"`
|
||||
StatValue3 *int `db:"stat_value3"`
|
||||
StatType4 *int `db:"stat_type4"`
|
||||
StatValue4 *int `db:"stat_value4"`
|
||||
StatType5 *int `db:"stat_type5"`
|
||||
StatValue5 *int `db:"stat_value5"`
|
||||
StatType6 *int `db:"stat_type6"`
|
||||
StatValue6 *int `db:"stat_value6"`
|
||||
StatType7 *int `db:"stat_type7"`
|
||||
StatValue7 *int `db:"stat_value7"`
|
||||
StatType8 *int `db:"stat_type8"`
|
||||
StatValue8 *int `db:"stat_value8"`
|
||||
StatType9 *int `db:"stat_type9"`
|
||||
StatValue9 *int `db:"stat_value9"`
|
||||
StatType10 *int `db:"stat_type10"`
|
||||
StatValue10 *int `db:"stat_value10"`
|
||||
HolyRes *int `db:"holy_res"`
|
||||
FireRes *int `db:"fire_res"`
|
||||
NatureRes *int `db:"nature_res"`
|
||||
FrostRes *int `db:"frost_res"`
|
||||
ShadowRes *int `db:"shadow_res"`
|
||||
ArcaneRes *int `db:"arcane_res"`
|
||||
SpellId1 *int `db:"spellid_1"`
|
||||
SpellId2 *int `db:"spellid_2"`
|
||||
SpellId3 *int `db:"spellid_3"`
|
||||
SpellTrigger1 *int `db:"spelltrigger_1"`
|
||||
SpellTrigger2 *int `db:"spelltrigger_2"`
|
||||
SpellTrigger3 *int `db:"spelltrigger_3"`
|
||||
SocketColor1 *int `db:"socketColor_1"`
|
||||
SocketContent1 *int `db:"socketContent_1"`
|
||||
SocketColor2 *int `db:"socketColor_2"`
|
||||
SocketContent2 *int `db:"socketContent_2"`
|
||||
SocketColor3 *int `db:"socketColor_3"`
|
||||
SocketContent3 *int `db:"socketContent_3"`
|
||||
SocketBonus *int `db:"socketBonus"`
|
||||
GemProperties *int `db:"GemProperties"`
|
||||
}
|
||||
|
||||
type DbItemCsv struct {
|
||||
Entry int `csv:"entry"`
|
||||
Name string `csv:"name"`
|
||||
DisplayId int `csv:"displayid"`
|
||||
Quality *int `csv:"Quality"`
|
||||
ItemLevel *int `csv:"ItemLevel"`
|
||||
Class *int `csv:"class"`
|
||||
Subclass *int `csv:"subclass"`
|
||||
InventoryType *int `csv:"inventoryType"`
|
||||
RequiredLevel *int `csv:"requiredLevel"`
|
||||
StatsCount *int `csv:"statsCount"`
|
||||
StatType1 *int `csv:"stat_type1"`
|
||||
StatValue1 *int `csv:"stat_value1"`
|
||||
StatType2 *int `csv:"stat_type2"`
|
||||
StatValue2 *int `csv:"stat_value2"`
|
||||
StatType3 *int `csv:"stat_type3"`
|
||||
StatValue3 *int `csv:"stat_value3"`
|
||||
StatType4 *int `csv:"stat_type4"`
|
||||
StatValue4 *int `csv:"stat_value4"`
|
||||
StatType5 *int `csv:"stat_type5"`
|
||||
StatValue5 *int `csv:"stat_value5"`
|
||||
StatType6 *int `csv:"stat_type6"`
|
||||
StatValue6 *int `csv:"stat_value6"`
|
||||
StatType7 *int `csv:"stat_type7"`
|
||||
StatValue7 *int `csv:"stat_value7"`
|
||||
StatType8 *int `csv:"stat_type8"`
|
||||
StatValue8 *int `csv:"stat_value8"`
|
||||
StatType9 *int `csv:"stat_type9"`
|
||||
StatValue9 *int `csv:"stat_value9"`
|
||||
StatType10 *int `csv:"stat_type10"`
|
||||
StatValue10 *int `csv:"stat_value10"`
|
||||
}
|
||||
|
||||
func (db *MySqlDb) GetItem(entry int) (DbItem, error) {
|
||||
if entry == 0 {
|
||||
return DbItem{}, fmt.Errorf("entry cannot be 0")
|
||||
}
|
||||
|
||||
item := DbItem{}
|
||||
sql := "SELECT " + GetItemFields("") + " FROM item_template WHERE entry = ?"
|
||||
err := db.Get(&item, sql, entry)
|
||||
if err != nil {
|
||||
return DbItem{}, err
|
||||
}
|
||||
|
||||
return item, nil
|
||||
}
|
||||
|
||||
// Look up a mythic item by name
|
||||
func (db *MySqlDb) GetByNameAndDifficulty(name string, difficulty int) (DbItem, error) {
|
||||
item := DbItem{}
|
||||
var min, max int = 0, 0
|
||||
if difficulty == 0 {
|
||||
return DbItem{}, errors.New("difficulty cannot be 0")
|
||||
}
|
||||
|
||||
if difficulty == 3 {
|
||||
min = config.MythicItemLevelStart
|
||||
max = config.MythicItemLevelEnd
|
||||
}
|
||||
|
||||
if difficulty == 4 {
|
||||
min = config.LegendaryItemLevelStart
|
||||
max = config.LegendaryItemLevelEnd
|
||||
}
|
||||
|
||||
if difficulty == 5 {
|
||||
min = config.AscendantItemLevelStart
|
||||
max = config.AscendantItemLevelEnd
|
||||
}
|
||||
|
||||
// though levels are flexible I am going to assume here that mythics are between 300 to 340 these can be overriden in config
|
||||
sql := "SELECT " + GetItemFields("") + " FROM item_template WHERE name like ? and ItemLevel >= ? and ItemLevel < ? LIMIT 1"
|
||||
name = "%" + name
|
||||
err := db.Get(&item, sql, name, min, max)
|
||||
if err != nil {
|
||||
log.Printf("failed to get item: %v sql: %v", err, fmt.Sprintf("SELECT * FROM item_template WHERE name like %v and ItemLevel >= %v and ItemLevel < %v LIMIT 1", name, min, max))
|
||||
return DbItem{}, err
|
||||
}
|
||||
|
||||
return item, nil
|
||||
}
|
||||
|
||||
// returns all items from item_template where the quality is between rare and legendary items
|
||||
func (db *MySqlDb) GetRarePlusItems(limit, offset int) ([]DbItem, error) {
|
||||
items := []DbItem{}
|
||||
sql := "SELECT " + GetItemFields("") + " FROM item_template WHERE Quality >= 3 and Quality <= 5 and (class = 2 or class = 4) "
|
||||
sql += "and subclass != 20 AND entry < 20000000 ORDER BY entry ASC"
|
||||
|
||||
if limit != 0 && offset != 0 {
|
||||
sql += fmt.Sprintf("LIMIT %v OFFSET %v", limit, offset)
|
||||
}
|
||||
|
||||
err := db.Select(&items, sql)
|
||||
if err != nil {
|
||||
return []DbItem{}, err
|
||||
}
|
||||
|
||||
return items, nil
|
||||
}
|
||||
|
||||
func (db *MySqlDb) GetBossMapItems(mapId int, bossEntries []int, gameObjectEntries []int, limit, offset int) ([]DbItem, error) {
|
||||
items := []DbItem{}
|
||||
|
||||
// Build the boss entries condition
|
||||
bossEntriesCondition := ""
|
||||
if len(bossEntries) > 0 {
|
||||
bossEntriesStr := make([]string, len(bossEntries))
|
||||
for i, entry := range bossEntries {
|
||||
bossEntriesStr[i] = fmt.Sprintf("%d", entry)
|
||||
}
|
||||
bossEntriesCondition = fmt.Sprintf("OR ct.entry IN (%s)", strings.Join(bossEntriesStr, ","))
|
||||
}
|
||||
|
||||
// Build the GameObject entries condition
|
||||
gameObjectEntriesCondition := ""
|
||||
if len(gameObjectEntries) > 0 {
|
||||
gameObjectEntriesStr := make([]string, len(gameObjectEntries))
|
||||
for i, entry := range gameObjectEntries {
|
||||
gameObjectEntriesStr[i] = fmt.Sprintf("%d", entry)
|
||||
}
|
||||
gameObjectEntriesCondition = fmt.Sprintf("AND got.entry IN (%s)", strings.Join(gameObjectEntriesStr, ","))
|
||||
}
|
||||
|
||||
sql := `SELECT DISTINCT ` + GetItemFields("it") + `
|
||||
FROM acore_world.creature_template ct
|
||||
LEFT JOIN acore_world.creature c ON c.id1 = ct.entry
|
||||
LEFT JOIN acore_world.map_dbc m ON c.map = m.ID
|
||||
LEFT JOIN acore_world.creature_loot_template clt ON ct.lootid = clt.Entry
|
||||
LEFT JOIN acore_world.reference_loot_template rlt ON clt.Reference = rlt.Entry
|
||||
LEFT JOIN acore_world.item_template it ON rlt.Item = it.entry
|
||||
|
||||
WHERE
|
||||
( m.ID = ? ` + bossEntriesCondition + ` )
|
||||
AND ct.rank IN (3)
|
||||
AND it.class IN (2, 4) -- Weapons and armor
|
||||
AND it.bonding IN (1, 2) -- Binds when picked up/equipped
|
||||
AND it.Quality >= 4 -- Epic and above`
|
||||
|
||||
// Only add the UNION clause if we have GameObject entries
|
||||
if len(gameObjectEntries) > 0 {
|
||||
sql += `
|
||||
|
||||
UNION
|
||||
|
||||
SELECT DISTINCT ` + GetItemFields("it") + `
|
||||
|
||||
FROM acore_world.gameobject go
|
||||
JOIN acore_world.gameobject_template got ON go.id = got.entry
|
||||
LEFT JOIN acore_world.gameobject_loot_template glt ON got.Data1 = glt.Entry
|
||||
LEFT JOIN acore_world.reference_loot_template rlt ON glt.Reference = rlt.Entry
|
||||
LEFT JOIN acore_world.item_template it ON rlt.Item = it.entry
|
||||
|
||||
WHERE go.map = ?
|
||||
` + gameObjectEntriesCondition + `
|
||||
AND it.class IN (2, 4) -- Weapons and armor
|
||||
AND it.bonding IN (1, 2) -- Binds when picked up/equipped
|
||||
AND it.Quality >= 4`
|
||||
}
|
||||
|
||||
if limit != 0 && offset != 0 {
|
||||
sql += fmt.Sprintf(" LIMIT %v OFFSET %v", limit, offset)
|
||||
}
|
||||
|
||||
// Prepare query parameters
|
||||
var args []interface{}
|
||||
args = append(args, mapId)
|
||||
if len(gameObjectEntries) > 0 {
|
||||
args = append(args, mapId) // Second mapId for the UNION query
|
||||
}
|
||||
|
||||
err := db.Select(&items, sql, args...)
|
||||
if err != nil {
|
||||
return []DbItem{}, err
|
||||
}
|
||||
|
||||
return items, nil
|
||||
}
|
||||
|
||||
func (db *MySqlDb) GetRaidPhase1Items(class, subclass, limit, offset int) ([]DbItem, error) {
|
||||
items := []DbItem{}
|
||||
|
||||
sql := `SELECT DISTINCT ` + GetItemFields("it") + `
|
||||
FROM acore_world.creature c
|
||||
JOIN acore_world.creature_template ct ON c.id1 = ct.entry
|
||||
JOIN acore_world.map_dbc m ON c.map = m.ID
|
||||
JOIN acore_world.creature_loot_template clt ON ct.lootid = clt.Entry
|
||||
JOIN acore_world.item_template it ON clt.Item = it.entry
|
||||
WHERE
|
||||
m.ID IN (533,615,616)
|
||||
AND ct.rank = 3
|
||||
AND it.class = ?
|
||||
AND it.subclass = ?
|
||||
AND it.bonding IN (1, 2) -- Binds when picked up/equipped
|
||||
AND it.Quality >= 4 -- Epic and above
|
||||
|
||||
UNION ALL
|
||||
|
||||
-- Get loot from reference_loot_template (reference items)
|
||||
SELECT DISTINCT ` + GetItemFields("it") + `
|
||||
FROM acore_world.creature c
|
||||
JOIN acore_world.creature_template ct ON c.id1 = ct.entry
|
||||
JOIN acore_world.map_dbc m ON c.map = m.ID
|
||||
JOIN acore_world.creature_loot_template clt ON ct.lootid = clt.Entry
|
||||
JOIN acore_world.reference_loot_template rlt ON clt.Reference = rlt.Entry
|
||||
JOIN acore_world.item_template it ON rlt.Item = it.entry
|
||||
WHERE
|
||||
m.ID IN (533,615,616)
|
||||
AND ct.rank = 3
|
||||
AND it.class = ?
|
||||
AND it.subclass = ?
|
||||
AND it.bonding IN (1, 2) -- Binds when picked up/equipped
|
||||
AND it.Quality >= 4 -- Epic and above
|
||||
|
||||
`
|
||||
|
||||
if limit != 0 && offset != 0 {
|
||||
sql += fmt.Sprintf("LIMIT %v OFFSET %v", limit, offset)
|
||||
}
|
||||
|
||||
err := db.Select(&items, sql, class, subclass, class, subclass)
|
||||
if err != nil {
|
||||
return []DbItem{}, err
|
||||
}
|
||||
|
||||
return items, nil
|
||||
}
|
||||
|
||||
func GetItemFields(prefix string) string {
|
||||
pre := ""
|
||||
if prefix != "" {
|
||||
pre = prefix + "."
|
||||
}
|
||||
|
||||
return `
|
||||
` + pre + `entry, ` + pre + `name, ` + pre + `displayid,
|
||||
quality, ItemLevel, class, subclass, inventoryType,
|
||||
allowableClass, allowableRace,
|
||||
armor,material,
|
||||
holy_res, fire_res, nature_res, frost_res, shadow_res, arcane_res,
|
||||
requiredSkill, requiredLevel,
|
||||
dmg_min1, dmg_max1,
|
||||
dmg_min2,dmg_max2,
|
||||
dmg_type1, dmg_type2,
|
||||
delay, sheath, MaxDurability,
|
||||
statsCount,
|
||||
stat_type1, stat_value1,
|
||||
stat_type2, stat_value2,
|
||||
stat_type3, stat_value3,
|
||||
stat_type4, stat_value4,
|
||||
stat_type5, stat_value5,
|
||||
stat_type6, stat_value6,
|
||||
stat_type7, stat_value7,
|
||||
stat_type8, stat_value8,
|
||||
stat_type9, stat_value9,
|
||||
stat_type10, stat_value10,
|
||||
spellid_1, spellid_2, spellid_3,
|
||||
spelltrigger_1, spelltrigger_2, spelltrigger_3,
|
||||
socketColor_1, socketContent_1, socketColor_2, socketContent_2, socketColor_3, socketContent_3,
|
||||
socketBonus, GemProperties`
|
||||
}
|
||||
|
||||
// This will write an DBItem to the database of the specified table..
|
||||
// It must match the item_template schema
|
||||
// CopyItem copies an item from one table to another with an optional new ID
|
||||
// This uses a temporary table approach to handle copying ALL fields without having to list them
|
||||
// If newId is 0, it keeps the original ID
|
||||
func (db *MySqlDb) CopyItem(sourceTable string, destTable string, itemEntry int, newEntry int) error {
|
||||
// Generate a unique temporary table name using timestamp
|
||||
tempTableName := fmt.Sprintf("temp_item_copy_%d", time.Now().UnixNano())
|
||||
|
||||
// Create a temporary table with the same structure as the source table
|
||||
sql := fmt.Sprintf("CREATE TEMPORARY TABLE %s LIKE %s", tempTableName, sourceTable)
|
||||
_, err := db.Exec(sql)
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to create temporary table: %w", err)
|
||||
}
|
||||
|
||||
// Copy the item to the temporary table
|
||||
sql = fmt.Sprintf("INSERT INTO %s SELECT * FROM %s WHERE entry = %d",
|
||||
tempTableName, sourceTable, itemEntry)
|
||||
_, err = db.Exec(sql)
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to copy item to temporary table: %w", err)
|
||||
}
|
||||
|
||||
// If we need to change the entry, update it in the temporary table
|
||||
if newEntry > 0 && newEntry != itemEntry {
|
||||
sql = fmt.Sprintf("UPDATE %s SET entry = %d", tempTableName, newEntry)
|
||||
_, err = db.Exec(sql)
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to update item entry in temporary table: %w", err)
|
||||
}
|
||||
}
|
||||
|
||||
// Copy from temporary table to destination table
|
||||
sql = fmt.Sprintf("REPLACE INTO %s SELECT * FROM %s", destTable, tempTableName)
|
||||
_, err = db.Exec(sql)
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to copy item from temporary table to destination: %w", err)
|
||||
}
|
||||
|
||||
// Drop the temporary table
|
||||
sql = fmt.Sprintf("DROP TEMPORARY TABLE IF EXISTS %s", tempTableName)
|
||||
_, err = db.Exec(sql)
|
||||
if err != nil {
|
||||
log.Printf("Warning: failed to drop temporary table %s: %v", tempTableName, err)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (db *MySqlDb) WriteItem(table string, item DbItem) error {
|
||||
// We'll use INSERT ... ON DUPLICATE KEY UPDATE to preserve fields not explicitly set
|
||||
// First, build the field list for the INSERT part
|
||||
fields := GetItemFields("")
|
||||
|
||||
// Construct the SQL insert statement using the item fields
|
||||
sql := "INSERT INTO " + table + " (" + fields + ") VALUES (" +
|
||||
"?, ?, ?, " + // entry, name, displayid
|
||||
"?, ?, ?, ?, ?, " + // quality, ItemLevel, class, subclass, inventoryType
|
||||
"?, ?, " + // allowableClass, allowableRace
|
||||
"?, ?, " + // armor, material
|
||||
"?, ?, ?, ?, ?, ?, " + // holy_res, fire_res, nature_res, frost_res, shadow_res, arcane_res
|
||||
"?, ?, " + // requiredSkill, requiredLevel
|
||||
"?, ?, " + // dmg_min1, dmg_max1
|
||||
"?, ?, " + // dmg_min2, dmg_max2
|
||||
"?, ?, " + // dmg_type1, dmg_type2
|
||||
"?, ?, ?, " + // delay, sheath, MaxDurability
|
||||
"?, " + // statsCount
|
||||
"?, ?, ?, ?, ?, ?, ?, ?, ?, ?, " + // stat_type1-5, stat_value1-5
|
||||
"?, ?, ?, ?, ?, ?, ?, ?, ?, ?, " + // stat_type6-10, stat_value6-10
|
||||
"?, ?, ?, " + // spellid_1-3
|
||||
"?, ?, ?, " + // spelltrigger_1-3
|
||||
"?, ?, ?, ?, ?, ?, " + // socketColor_1-3, socketContent_1-3
|
||||
"?, ?" + // socketBonus, GemProperties
|
||||
") ON DUPLICATE KEY UPDATE " +
|
||||
"name = VALUES(name), " +
|
||||
"quality = VALUES(quality), " +
|
||||
"ItemLevel = VALUES(ItemLevel), " +
|
||||
"requiredLevel = VALUES(requiredLevel), " +
|
||||
"dmg_min1 = VALUES(dmg_min1), dmg_max1 = VALUES(dmg_max1), " +
|
||||
"dmg_min2 = VALUES(dmg_min2), dmg_max2 = VALUES(dmg_max2), " +
|
||||
"dmg_type1 = VALUES(dmg_type1), dmg_type2 = VALUES(dmg_type2), " +
|
||||
"statsCount = VALUES(statsCount), " +
|
||||
"stat_type1 = VALUES(stat_type1), stat_value1 = VALUES(stat_value1), " +
|
||||
"stat_type2 = VALUES(stat_type2), stat_value2 = VALUES(stat_value2), " +
|
||||
"stat_type3 = VALUES(stat_type3), stat_value3 = VALUES(stat_value3), " +
|
||||
"stat_type4 = VALUES(stat_type4), stat_value4 = VALUES(stat_value4), " +
|
||||
"stat_type5 = VALUES(stat_type5), stat_value5 = VALUES(stat_value5), " +
|
||||
"stat_type6 = VALUES(stat_type6), stat_value6 = VALUES(stat_value6), " +
|
||||
"stat_type7 = VALUES(stat_type7), stat_value7 = VALUES(stat_value7), " +
|
||||
"stat_type8 = VALUES(stat_type8), stat_value8 = VALUES(stat_value8), " +
|
||||
"stat_type9 = VALUES(stat_type9), stat_value9 = VALUES(stat_value9), " +
|
||||
"stat_type10 = VALUES(stat_type10), stat_value10 = VALUES(stat_value10), " +
|
||||
"spellid_1 = VALUES(spellid_1), spellid_2 = VALUES(spellid_2), spellid_3 = VALUES(spellid_3)"
|
||||
|
||||
// Execute the query with all the item fields as parameters
|
||||
_, err := db.Exec(sql,
|
||||
item.Entry, item.Name, item.DisplayId,
|
||||
item.Quality, item.ItemLevel, item.Class, item.Subclass, item.InventoryType,
|
||||
item.AllowableClass, item.AllowableRace,
|
||||
item.Armor, item.Material,
|
||||
item.HolyRes, item.FireRes, item.NatureRes, item.FrostRes, item.ShadowRes, item.ArcaneRes,
|
||||
item.RequiredSkill, item.RequiredLevel,
|
||||
item.MinDmg1, item.MaxDmg1,
|
||||
item.MinDmg2, item.MaxDmg2,
|
||||
item.DmgType1, item.DmgType2,
|
||||
item.Delay, item.Sheath, item.Durability,
|
||||
item.StatsCount,
|
||||
item.StatType1, item.StatValue1,
|
||||
item.StatType2, item.StatValue2,
|
||||
item.StatType3, item.StatValue3,
|
||||
item.StatType4, item.StatValue4,
|
||||
item.StatType5, item.StatValue5,
|
||||
item.StatType6, item.StatValue6,
|
||||
item.StatType7, item.StatValue7,
|
||||
item.StatType8, item.StatValue8,
|
||||
item.StatType9, item.StatValue9,
|
||||
item.StatType10, item.StatValue10,
|
||||
item.SpellId1, item.SpellId2, item.SpellId3,
|
||||
item.SpellTrigger1, item.SpellTrigger2, item.SpellTrigger3,
|
||||
item.SocketColor1, item.SocketContent1,
|
||||
item.SocketColor2, item.SocketContent2,
|
||||
item.SocketColor3, item.SocketContent3,
|
||||
item.SocketBonus, item.GemProperties,
|
||||
)
|
||||
|
||||
if err != nil {
|
||||
log.Printf("Failed to run sql query: %v", sql)
|
||||
return fmt.Errorf("failed to insert item into %s: %w", table, err)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// This will convert a DbItemCsv to a DbItem and return
|
||||
// It will first look up the original item in the database though first and populate
|
||||
// the DbItem with the original item's values then override with the values from the csv
|
||||
func (db *MySqlDb) ConvertCsvToDbItem(csv DbItemCsv) (DbItem, error) {
|
||||
|
||||
// Try to find the original item in the database
|
||||
lookupEntry := csv.Entry - 2000000
|
||||
item, err := db.GetItem(lookupEntry)
|
||||
if err != nil {
|
||||
// Log the error with more details
|
||||
log.Printf("Error finding original item with entry %d: %v", lookupEntry, err)
|
||||
|
||||
item, err = db.GetItem(csv.Entry)
|
||||
|
||||
if err != nil {
|
||||
log.Printf("Error finding item with direct entry %d: %v", csv.Entry, err)
|
||||
|
||||
// Create a new item with the CSV data
|
||||
item = DbItem{
|
||||
Entry: csv.Entry,
|
||||
Name: csv.Name,
|
||||
DisplayId: csv.DisplayId,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Override values from CSV
|
||||
item.Name = csv.Name
|
||||
|
||||
// Override pointer fields if they exist in CSV
|
||||
if csv.Quality != nil {
|
||||
item.Quality = csv.Quality
|
||||
}
|
||||
if csv.ItemLevel != nil {
|
||||
item.ItemLevel = csv.ItemLevel
|
||||
}
|
||||
if csv.RequiredLevel != nil {
|
||||
item.RequiredLevel = csv.RequiredLevel
|
||||
}
|
||||
|
||||
// Handle stats count and stats
|
||||
if csv.StatsCount != nil {
|
||||
item.StatsCount = csv.StatsCount
|
||||
} else if csv.StatType1 != nil {
|
||||
// Calculate stats count if not provided but stats exist
|
||||
statsCount := 0
|
||||
if csv.StatType1 != nil && *csv.StatType1 > 0 {
|
||||
statsCount++
|
||||
}
|
||||
if csv.StatType2 != nil && *csv.StatType2 > 0 {
|
||||
statsCount++
|
||||
}
|
||||
if csv.StatType3 != nil && *csv.StatType3 > 0 {
|
||||
statsCount++
|
||||
}
|
||||
if csv.StatType4 != nil && *csv.StatType4 > 0 {
|
||||
statsCount++
|
||||
}
|
||||
if csv.StatType5 != nil && *csv.StatType5 > 0 {
|
||||
statsCount++
|
||||
}
|
||||
if csv.StatType6 != nil && *csv.StatType6 > 0 {
|
||||
statsCount++
|
||||
}
|
||||
if csv.StatType7 != nil && *csv.StatType7 > 0 {
|
||||
statsCount++
|
||||
}
|
||||
if csv.StatType8 != nil && *csv.StatType8 > 0 {
|
||||
statsCount++
|
||||
}
|
||||
if csv.StatType9 != nil && *csv.StatType9 > 0 {
|
||||
statsCount++
|
||||
}
|
||||
if csv.StatType10 != nil && *csv.StatType10 > 0 {
|
||||
statsCount++
|
||||
}
|
||||
item.StatsCount = &statsCount
|
||||
}
|
||||
|
||||
// Override stat types and values
|
||||
if csv.StatType1 != nil {
|
||||
item.StatType1 = csv.StatType1
|
||||
}
|
||||
if csv.StatValue1 != nil {
|
||||
item.StatValue1 = csv.StatValue1
|
||||
}
|
||||
if csv.StatType2 != nil {
|
||||
item.StatType2 = csv.StatType2
|
||||
}
|
||||
if csv.StatValue2 != nil {
|
||||
item.StatValue2 = csv.StatValue2
|
||||
}
|
||||
if csv.StatType3 != nil {
|
||||
item.StatType3 = csv.StatType3
|
||||
}
|
||||
if csv.StatValue3 != nil {
|
||||
item.StatValue3 = csv.StatValue3
|
||||
}
|
||||
if csv.StatType4 != nil {
|
||||
item.StatType4 = csv.StatType4
|
||||
}
|
||||
if csv.StatValue4 != nil {
|
||||
item.StatValue4 = csv.StatValue4
|
||||
}
|
||||
if csv.StatType5 != nil {
|
||||
item.StatType5 = csv.StatType5
|
||||
}
|
||||
if csv.StatValue5 != nil {
|
||||
item.StatValue5 = csv.StatValue5
|
||||
}
|
||||
if csv.StatType6 != nil {
|
||||
item.StatType6 = csv.StatType6
|
||||
}
|
||||
if csv.StatValue6 != nil {
|
||||
item.StatValue6 = csv.StatValue6
|
||||
}
|
||||
if csv.StatType7 != nil {
|
||||
item.StatType7 = csv.StatType7
|
||||
}
|
||||
if csv.StatValue7 != nil {
|
||||
item.StatValue7 = csv.StatValue7
|
||||
}
|
||||
if csv.StatType8 != nil {
|
||||
item.StatType8 = csv.StatType8
|
||||
}
|
||||
if csv.StatValue8 != nil {
|
||||
item.StatValue8 = csv.StatValue8
|
||||
}
|
||||
if csv.StatType9 != nil {
|
||||
item.StatType9 = csv.StatType9
|
||||
}
|
||||
if csv.StatValue9 != nil {
|
||||
item.StatValue9 = csv.StatValue9
|
||||
}
|
||||
if csv.StatType10 != nil {
|
||||
item.StatType10 = csv.StatType10
|
||||
}
|
||||
if csv.StatValue10 != nil {
|
||||
item.StatValue10 = csv.StatValue10
|
||||
}
|
||||
|
||||
return item, nil
|
||||
}
|
||||
@@ -1,9 +1,7 @@
|
||||
package models
|
||||
package mysql
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
"github.com/araxiaonline/endgame-item-generator/utils"
|
||||
)
|
||||
|
||||
type Dungeon struct {
|
||||
@@ -74,7 +72,32 @@ var dungeonLevels = map[int]int{
|
||||
668: 80, // Halls of Reflection
|
||||
}
|
||||
|
||||
func (db Database) GetDungeons(expansionId int) ([]Dungeon, error) {
|
||||
var raidLevels = map[int]int{
|
||||
249: 60, // Onyxia's Lair
|
||||
409: 60, // Molten Core
|
||||
469: 60, // Blackwing Lair
|
||||
309: 60, // Zul'Gurub
|
||||
531: 60, // Ahn'Qiraj Temple
|
||||
509: 60, // Ruins of Ahn'Qiraj
|
||||
532: 70, // Karazhan
|
||||
548: 70, // Serpentshrine Cavern
|
||||
550: 70, // Tempest Keep
|
||||
534: 70, // The Battle for Mount Hyjal
|
||||
564: 70, // Black Temple
|
||||
565: 70, // Gruul's Lair
|
||||
568: 70, // Zul'Aman
|
||||
580: 70, // Sunwell Plateau
|
||||
533: 80, // Naxxramas
|
||||
616: 80, // The Eye of Eternity
|
||||
615: 80, // The Obsidian Sanctum
|
||||
624: 80, // Vault of Archavon
|
||||
603: 80, // Ulduar
|
||||
649: 80, // Trial of the Crusader
|
||||
631: 80, // Icecrown Citadel
|
||||
724: 80, // The Ruby Sanctum
|
||||
}
|
||||
|
||||
func (db *MySqlDb) GetDungeons(expansionId int) ([]Dungeon, error) {
|
||||
dungeons := []Dungeon{}
|
||||
|
||||
sql := `
|
||||
@@ -85,9 +108,9 @@ func (db Database) GetDungeons(expansionId int) ([]Dungeon, error) {
|
||||
var err error
|
||||
if expansionId != -1 {
|
||||
sql = sql + "AND ExpansionID = ?"
|
||||
err = db.client.Select(&dungeons, sql, expansionId)
|
||||
err = db.Select(&dungeons, sql, expansionId)
|
||||
} else {
|
||||
err = db.client.Select(&dungeons, sql)
|
||||
err = db.Select(&dungeons, sql)
|
||||
}
|
||||
|
||||
if err != nil {
|
||||
@@ -103,11 +126,13 @@ func (db Database) GetDungeons(expansionId int) ([]Dungeon, error) {
|
||||
return dungeons, nil
|
||||
}
|
||||
|
||||
func (db Database) GetAddlDungeonDrops(instanceId int) ([]Item, error) {
|
||||
// Gets a list of other rare+ items that drop in a specific instance.
|
||||
func (db *MySqlDb) GetAddlDungeonDrops(instanceId int) ([]DbItem, error) {
|
||||
|
||||
var items []Item
|
||||
fields := GetItemFields("it")
|
||||
var items []DbItem
|
||||
sql := fmt.Sprintf(`
|
||||
SELECT `+utils.GetItemFields("it")+`
|
||||
SELECT `+fields+`
|
||||
from
|
||||
acore_world.map_dbc m
|
||||
join acore_world.creature c on m.ID = c.map
|
||||
@@ -118,7 +143,7 @@ from
|
||||
WHERE m.ID = %v and Quality >= 3 and it.bonding = 2 and class IN(2,4)
|
||||
|
||||
UNION
|
||||
SELECT `+utils.GetItemFields("it")+`
|
||||
SELECT `+fields+`
|
||||
from
|
||||
acore_world.map_dbc m
|
||||
join acore_world.creature c on m.ID = c.map
|
||||
@@ -127,7 +152,7 @@ from
|
||||
left join item_template it on clt.Item = it.entry
|
||||
WHERE m.ID = %v and Quality >= 3 and it.bonding = 2 and it.class IN(2,4)
|
||||
UNION
|
||||
SELECT `+utils.GetItemFields("it")+`
|
||||
SELECT `+fields+`
|
||||
from
|
||||
acore_world.map_dbc m
|
||||
join acore_world.gameobject go on m.ID = go.map
|
||||
@@ -140,7 +165,7 @@ where m.ID = %v and Quality >=3 and it.bonding IN(1,2) and it.class IN(2,4);
|
||||
|
||||
// log.Printf("sql: %s", sql)
|
||||
|
||||
err := db.client.Select(&items, sql)
|
||||
err := db.Select(&items, sql)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to get additional dungeon items: %v ", err)
|
||||
}
|
||||
64
internal/db/mysql/mysql.go
Normal file
64
internal/db/mysql/mysql.go
Normal file
@@ -0,0 +1,64 @@
|
||||
package mysql
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"os"
|
||||
|
||||
_ "github.com/go-sql-driver/mysql"
|
||||
"github.com/jmoiron/sqlx"
|
||||
)
|
||||
|
||||
type MySqlDb struct {
|
||||
*sqlx.DB
|
||||
}
|
||||
|
||||
type MySqlConfig struct {
|
||||
Host string
|
||||
User string
|
||||
Password string
|
||||
Database string
|
||||
}
|
||||
|
||||
var MySql *MySqlDb
|
||||
|
||||
func Connect(config *MySqlConfig) (*MySqlDb, error) {
|
||||
|
||||
if config == nil {
|
||||
config = &MySqlConfig{
|
||||
Host: os.Getenv("DB_HOST"),
|
||||
User: os.Getenv("DB_USER"),
|
||||
Password: os.Getenv("DB_PASSWORD"),
|
||||
Database: os.Getenv("DB_NAME"),
|
||||
}
|
||||
}
|
||||
|
||||
connString := config.User + ":" + config.Password + "@tcp(" + config.Host + ")/" + config.Database
|
||||
client, err := sqlx.Open("mysql", connString)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("error opening database connection: %w", err)
|
||||
}
|
||||
|
||||
// Verify the connection is actually working
|
||||
err = client.Ping()
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("error connecting to database: %w", err)
|
||||
}
|
||||
|
||||
MySql = &MySqlDb{client}
|
||||
return MySql, nil
|
||||
}
|
||||
|
||||
func GetDb() (*MySqlDb, error) {
|
||||
if MySql == nil {
|
||||
return nil, errors.New("mysql not connected")
|
||||
}
|
||||
|
||||
return MySql, nil
|
||||
}
|
||||
|
||||
func (db *MySqlDb) Close() {
|
||||
if db.DB != nil {
|
||||
db.DB.Close()
|
||||
}
|
||||
}
|
||||
238
internal/db/mysql/spells.go
Normal file
238
internal/db/mysql/spells.go
Normal file
@@ -0,0 +1,238 @@
|
||||
package mysql
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"log"
|
||||
"strconv"
|
||||
"time"
|
||||
)
|
||||
|
||||
type DbSpell struct {
|
||||
ID int `db:"ID"`
|
||||
Name string `db:"Name_Lang_enUS"`
|
||||
Description string `db:"Description_Lang_enUS"`
|
||||
AuraDescription string `db:"AuraDescription_Lang_enUS"`
|
||||
ProcChance int `db:"ProcChance"`
|
||||
SpellLevel int `db:"SpellLevel"`
|
||||
Effect1 int `db:"Effect_1"`
|
||||
Effect2 int `db:"Effect_2"`
|
||||
Effect3 int `db:"Effect_3"`
|
||||
EffectDieSides1 int `db:"EffectDieSides_1"`
|
||||
EffectDieSides2 int `db:"EffectDieSides_2"`
|
||||
EffectDieSides3 int `db:"EffectDieSides_3"`
|
||||
EffectRealPointsPerLevel1 int `db:"EffectRealPointsPerLevel_1"`
|
||||
EffectRealPointsPerLevel2 int `db:"EffectRealPointsPerLevel_2"`
|
||||
EffectRealPointsPerLevel3 int `db:"EffectRealPointsPerLevel_3"`
|
||||
EffectBasePoints1 int `db:"EffectBasePoints_1"`
|
||||
EffectBasePoints2 int `db:"EffectBasePoints_2"`
|
||||
EffectBasePoints3 int `db:"EffectBasePoints_3"`
|
||||
EffectAura1 int `db:"EffectAura_1"`
|
||||
EffectAura2 int `db:"EffectAura_2"`
|
||||
EffectAura3 int `db:"EffectAura_3"`
|
||||
EffectBonusMultiplier1 int `db:"EffectBonusMultiplier_1"`
|
||||
EffectBonusMultiplier2 int `db:"EffectBonusMultiplier_2"`
|
||||
EffectBonusMultiplier3 int `db:"EffectBonusMultiplier_3"`
|
||||
}
|
||||
|
||||
func (db *MySqlDb) GetSpell(id int) (DbSpell, error) {
|
||||
|
||||
if id == 0 {
|
||||
return DbSpell{}, fmt.Errorf("id cannot be 0")
|
||||
}
|
||||
|
||||
spell := DbSpell{}
|
||||
sql := "SELECT " + GetSpellFields() + " FROM `spell_dbc` WHERE ID = ? -- " + strconv.Itoa(id)
|
||||
|
||||
err := db.Get(&spell, sql, id)
|
||||
if err != nil {
|
||||
return DbSpell{}, fmt.Errorf("failed to get spell: %v", err)
|
||||
}
|
||||
|
||||
return spell, nil
|
||||
}
|
||||
|
||||
func GetSpellFields() string {
|
||||
return `
|
||||
ID,
|
||||
Name_Lang_enUS,
|
||||
COALESCE(Description_Lang_enUS, '') as Description_Lang_enUS,
|
||||
COALESCE(AuraDescription_Lang_enUS, '') as AuraDescription_Lang_enUS,
|
||||
ProcChance,
|
||||
SpellLevel,
|
||||
Effect_1,
|
||||
Effect_2,
|
||||
Effect_3,
|
||||
EffectDieSides_1,
|
||||
EffectDieSides_2,
|
||||
EffectDieSides_3,
|
||||
EffectRealPointsPerLevel_1,
|
||||
EffectRealPointsPerLevel_2,
|
||||
EffectRealPointsPerLevel_3,
|
||||
EffectBasePoints_1,
|
||||
EffectBasePoints_2,
|
||||
EffectBasePoints_3,
|
||||
EffectAura_1,
|
||||
EffectAura_2,
|
||||
EffectAura_3,
|
||||
EffectBonusMultiplier_1,
|
||||
EffectBonusMultiplier_2,
|
||||
EffectBonusMultiplier_3
|
||||
`
|
||||
}
|
||||
func GetSpellWriteFields() string {
|
||||
return `
|
||||
ID,
|
||||
Name_Lang_enUS,
|
||||
Description_Lang_enUS,
|
||||
AuraDescription_Lang_enUS,
|
||||
ProcChance,
|
||||
SpellLevel,
|
||||
Effect_1,
|
||||
Effect_2,
|
||||
Effect_3,
|
||||
EffectDieSides_1,
|
||||
EffectDieSides_2,
|
||||
EffectDieSides_3,
|
||||
EffectRealPointsPerLevel_1,
|
||||
EffectRealPointsPerLevel_2,
|
||||
EffectRealPointsPerLevel_3,
|
||||
EffectBasePoints_1,
|
||||
EffectBasePoints_2,
|
||||
EffectBasePoints_3,
|
||||
EffectAura_1,
|
||||
EffectAura_2,
|
||||
EffectAura_3,
|
||||
EffectBonusMultiplier_1,
|
||||
EffectBonusMultiplier_2,
|
||||
EffectBonusMultiplier_3
|
||||
`
|
||||
}
|
||||
|
||||
// Writes a new upgraded spell to the database for the specified table
|
||||
func (db *MySqlDb) WriteSpell(table string, spell DbSpell) error {
|
||||
// Get the field names from GetSpellFields
|
||||
fields := GetSpellWriteFields()
|
||||
|
||||
// Construct the SQL insert statement using the spell fields
|
||||
sql := "INSERT INTO " + table + " (" + fields + ") VALUES (" +
|
||||
"?, ?, ?, ?, ?, ?, " + // ID, Name_Lang_enUS, Description_Lang_enUS, AuraDescription_Lang_enUS, ProcChance, SpellLevel
|
||||
"?, ?, ?, " + // Effect_1, Effect_2, Effect_3
|
||||
"?, ?, ?, " + // EffectDieSides_1, EffectDieSides_2, EffectDieSides_3
|
||||
"?, ?, ?, " + // EffectRealPointsPerLevel_1, EffectRealPointsPerLevel_2, EffectRealPointsPerLevel_3
|
||||
"?, ?, ?, " + // EffectBasePoints_1, EffectBasePoints_2, EffectBasePoints_3
|
||||
"?, ?, ?, " + // EffectAura_1, EffectAura_2, EffectAura_3
|
||||
"?, ?, ?" + // EffectBonusMultiplier_1, EffectBonusMultiplier_2, EffectBonusMultiplier_3
|
||||
") ON DUPLICATE KEY UPDATE " +
|
||||
"Name_Lang_enUS = VALUES(Name_Lang_enUS), " +
|
||||
"Description_Lang_enUS = VALUES(Description_Lang_enUS), " +
|
||||
"AuraDescription_Lang_enUS = VALUES(AuraDescription_Lang_enUS), " +
|
||||
"ProcChance = VALUES(ProcChance), " +
|
||||
"SpellLevel = VALUES(SpellLevel), " +
|
||||
"Effect_1 = VALUES(Effect_1), " +
|
||||
"Effect_2 = VALUES(Effect_2), " +
|
||||
"Effect_3 = VALUES(Effect_3), " +
|
||||
"EffectDieSides_1 = VALUES(EffectDieSides_1), " +
|
||||
"EffectDieSides_2 = VALUES(EffectDieSides_2), " +
|
||||
"EffectDieSides_3 = VALUES(EffectDieSides_3), " +
|
||||
"EffectRealPointsPerLevel_1 = VALUES(EffectRealPointsPerLevel_1), " +
|
||||
"EffectRealPointsPerLevel_2 = VALUES(EffectRealPointsPerLevel_2), " +
|
||||
"EffectRealPointsPerLevel_3 = VALUES(EffectRealPointsPerLevel_3), " +
|
||||
"EffectBasePoints_1 = VALUES(EffectBasePoints_1), " +
|
||||
"EffectBasePoints_2 = VALUES(EffectBasePoints_2), " +
|
||||
"EffectBasePoints_3 = VALUES(EffectBasePoints_3), " +
|
||||
"EffectAura_1 = VALUES(EffectAura_1), " +
|
||||
"EffectAura_2 = VALUES(EffectAura_2), " +
|
||||
"EffectAura_3 = VALUES(EffectAura_3), " +
|
||||
"EffectBonusMultiplier_1 = VALUES(EffectBonusMultiplier_1), " +
|
||||
"EffectBonusMultiplier_2 = VALUES(EffectBonusMultiplier_2), " +
|
||||
"EffectBonusMultiplier_3 = VALUES(EffectBonusMultiplier_3)"
|
||||
|
||||
// Execute the query with all the spell fields as parameters
|
||||
_, err := db.Exec(sql,
|
||||
spell.ID,
|
||||
spell.Name,
|
||||
spell.Description,
|
||||
spell.AuraDescription,
|
||||
spell.ProcChance,
|
||||
spell.SpellLevel,
|
||||
spell.Effect1,
|
||||
spell.Effect2,
|
||||
spell.Effect3,
|
||||
spell.EffectDieSides1,
|
||||
spell.EffectDieSides2,
|
||||
spell.EffectDieSides3,
|
||||
spell.EffectRealPointsPerLevel1,
|
||||
spell.EffectRealPointsPerLevel2,
|
||||
spell.EffectRealPointsPerLevel3,
|
||||
spell.EffectBasePoints1,
|
||||
spell.EffectBasePoints2,
|
||||
spell.EffectBasePoints3,
|
||||
spell.EffectAura1,
|
||||
spell.EffectAura2,
|
||||
spell.EffectAura3,
|
||||
spell.EffectBonusMultiplier1,
|
||||
spell.EffectBonusMultiplier2,
|
||||
spell.EffectBonusMultiplier3,
|
||||
)
|
||||
|
||||
if err != nil {
|
||||
log.Printf("Failed to run sql query: %v", sql)
|
||||
return fmt.Errorf("failed to insert spell into %s: %w", table, err)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// CopySpell copies a spell from one table to another with an optional new ID
|
||||
// This uses a temporary table approach to handle copying ALL fields without having to list them
|
||||
// If newId is 0, it keeps the original ID
|
||||
func (db *MySqlDb) CopySpell(sourceTable string, destTable string, spellId int, newId int) error {
|
||||
// Generate a unique temporary table name using timestamp
|
||||
tempTableName := fmt.Sprintf("temp_spell_copy_%d", time.Now().UnixNano())
|
||||
|
||||
// Create a temporary table with the same structure as the source table
|
||||
sql := fmt.Sprintf("CREATE TEMPORARY TABLE %s LIKE %s", tempTableName, sourceTable)
|
||||
_, err := db.Exec(sql)
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to create temporary table: %w", err)
|
||||
}
|
||||
|
||||
// Copy the spell to the temporary table
|
||||
sql = fmt.Sprintf("INSERT INTO %s SELECT * FROM %s WHERE ID = %d",
|
||||
tempTableName, sourceTable, spellId)
|
||||
_, err = db.Exec(sql)
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to copy spell to temporary table: %w", err)
|
||||
}
|
||||
|
||||
// If we need to change the ID, update it in the temporary table
|
||||
if newId > 0 && newId != spellId {
|
||||
sql = fmt.Sprintf("UPDATE %s SET ID = %d", tempTableName, newId)
|
||||
_, err = db.Exec(sql)
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to update spell ID in temporary table: %w", err)
|
||||
}
|
||||
}
|
||||
|
||||
// Copy from temporary table to destination table
|
||||
sql = fmt.Sprintf("INSERT INTO %s SELECT * FROM %s", destTable, tempTableName)
|
||||
_, err = db.Exec(sql)
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to copy spell from temporary table to destination: %w", err)
|
||||
}
|
||||
|
||||
// Drop the temporary table (MySQL automatically drops temporary tables at the end of the session,
|
||||
// but it's good practice to clean up explicitly)
|
||||
sql = fmt.Sprintf("DROP TEMPORARY TABLE IF EXISTS %s", tempTableName)
|
||||
_, err = db.Exec(sql)
|
||||
if err != nil {
|
||||
log.Printf("Warning: failed to drop temporary table %s: %v", tempTableName, err)
|
||||
}
|
||||
|
||||
log.Printf("Successfully copied spell %d to %s", spellId, destTable)
|
||||
if newId > 0 && newId != spellId {
|
||||
log.Printf(" with new ID: %d", newId)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
107
internal/db/sqlite/items.go
Normal file
107
internal/db/sqlite/items.go
Normal file
@@ -0,0 +1,107 @@
|
||||
package sqlite
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"log"
|
||||
"strings"
|
||||
|
||||
"github.com/araxiaonline/endgame-item-generator/internal/db/mysql"
|
||||
)
|
||||
|
||||
type HighLevelItem struct {
|
||||
Entry int `db:"entry"`
|
||||
Class *int `db:"class"`
|
||||
Name string `db:"name"`
|
||||
Quality int `db:"Quality"`
|
||||
ItemLevel int `db:"itemLevel"`
|
||||
Subclass *int `db:"subclass"`
|
||||
StatsList string `db:"stats_list"`
|
||||
}
|
||||
|
||||
type DungeonItem struct {
|
||||
Entry int `db:"entry"`
|
||||
MapId int `db:"mapId"`
|
||||
CreatureId int `db:"creatureId"`
|
||||
Quality int `db:"Quality"`
|
||||
Expansion int `db:"expansion"`
|
||||
DungeonLevel int `db:"dungeonLevel"`
|
||||
}
|
||||
|
||||
func (db *SqlLite) GetItem(entry int) (HighLevelItem, error) {
|
||||
if entry == 0 {
|
||||
return HighLevelItem{}, fmt.Errorf("entry cannot be 0")
|
||||
}
|
||||
|
||||
item := HighLevelItem{}
|
||||
sql := "SELECT " + mysql.GetItemFields("") + " FROM item_template WHERE entry = ?"
|
||||
err := db.Get(&item, sql, entry)
|
||||
if err != nil {
|
||||
return HighLevelItem{}, err
|
||||
}
|
||||
|
||||
return item, nil
|
||||
}
|
||||
|
||||
// This gets a random item that is close in stats type to the lower level items with some randomness
|
||||
func (db *SqlLite) GetRandItem(class, subclass int, statsList []int, end bool) (HighLevelItem, error) {
|
||||
rndItem := HighLevelItem{}
|
||||
var statsTxt string
|
||||
var err error
|
||||
var sql string
|
||||
|
||||
// if we have a stats_list try to match by that first, if not then just select a random item from the class and subclass
|
||||
if len(statsList) == 0 {
|
||||
sql = "SELECT * FROM items WHERE class = ? and subclass = ? and itemLevel >= 240 ORDER BY RANDOM() LIMIT 1"
|
||||
err = db.Get(&rndItem, sql, class, subclass)
|
||||
} else {
|
||||
// convert the array of ints to a commas string for lookup
|
||||
statsTxt = intSliceToString(statsList)
|
||||
sql = "SELECT * FROM items WHERE class = ? and subclass = ? and stats_list and itemLevel >= 240 like ? ORDER BY RANDOM() LIMIT 1"
|
||||
err = db.Get(&rndItem, sql, class, subclass, statsTxt+"%")
|
||||
}
|
||||
|
||||
if err != nil {
|
||||
|
||||
// if we hit the last check and still no item match then return an error
|
||||
if end {
|
||||
msg := fmt.Sprintf("Failed to find a matching item class %v subclass %v statsTxt %v", class, subclass, statsTxt)
|
||||
return HighLevelItem{}, errors.New(msg)
|
||||
}
|
||||
|
||||
// if there was not a remove the last stat and try again
|
||||
if err.Error() == "sql: no rows in result set" {
|
||||
|
||||
if len(statsList) == 0 {
|
||||
return db.GetRandItem(class, subclass, statsList, true)
|
||||
} else {
|
||||
statsList = statsList[:len(statsList)-1]
|
||||
return db.GetRandItem(class, subclass, statsList, false)
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
log.Fatalf("Error getting random sql: %v error: %v", sql, err)
|
||||
return HighLevelItem{}, err
|
||||
}
|
||||
|
||||
return rndItem, nil
|
||||
}
|
||||
|
||||
func (db *SqlLite) GetItemFromDungeon(itemEntry int) (DungeonItem, error) {
|
||||
item := DungeonItem{}
|
||||
sql := "SELECT * FROM dungeon_items WHERE entry = ?"
|
||||
|
||||
err := db.Get(&item, sql, itemEntry)
|
||||
if err != nil {
|
||||
return item, err
|
||||
}
|
||||
|
||||
return item, nil
|
||||
}
|
||||
|
||||
func intSliceToString(slice []int) string {
|
||||
str := fmt.Sprint(slice)
|
||||
str = strings.Trim(str, "[]")
|
||||
return strings.ReplaceAll(str, " ", ",")
|
||||
}
|
||||
33
internal/db/sqlite/sqlite.go
Normal file
33
internal/db/sqlite/sqlite.go
Normal file
@@ -0,0 +1,33 @@
|
||||
package sqlite
|
||||
|
||||
import (
|
||||
"github.com/jmoiron/sqlx"
|
||||
|
||||
_ "github.com/mattn/go-sqlite3"
|
||||
)
|
||||
|
||||
type SqlLite struct {
|
||||
*sqlx.DB
|
||||
}
|
||||
|
||||
var SqlLiteDb *SqlLite
|
||||
|
||||
func Connect(path string) (*SqlLite, error) {
|
||||
client, err := sqlx.Open("sqlite3", path)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
SqlLiteDb = &SqlLite{client}
|
||||
return SqlLiteDb, nil
|
||||
}
|
||||
|
||||
func GetDb() (*SqlLite, error) {
|
||||
return SqlLiteDb, nil
|
||||
}
|
||||
|
||||
func (db *SqlLite) Close() {
|
||||
if db.DB != nil {
|
||||
db.DB.Close()
|
||||
}
|
||||
}
|
||||
616
internal/items/get_class_user_type_test.go
Normal file
616
internal/items/get_class_user_type_test.go
Normal file
@@ -0,0 +1,616 @@
|
||||
package items
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
"github.com/araxiaonline/endgame-item-generator/internal/db/mysql"
|
||||
)
|
||||
|
||||
func TestGetClassUserType(t *testing.T) {
|
||||
tests := []struct {
|
||||
name string
|
||||
item Item
|
||||
expected int
|
||||
}{
|
||||
// Tank items (return 6) - Priority stats: Parry, Defense, Block
|
||||
{
|
||||
name: "Tank item with Parry Rating",
|
||||
item: Item{
|
||||
DbItem: mysql.DbItem{
|
||||
Entry: 1,
|
||||
Name: "Tank Weapon",
|
||||
Class: ptrInt(2), // Weapon
|
||||
Subclass: ptrInt(1), // One-handed sword
|
||||
StatType1: ptrInt(STAT.ParryRating),
|
||||
StatValue1: ptrInt(20),
|
||||
},
|
||||
},
|
||||
expected: 6,
|
||||
},
|
||||
{
|
||||
name: "Tank item with Defense Rating",
|
||||
item: Item{
|
||||
DbItem: mysql.DbItem{
|
||||
Entry: 2,
|
||||
Name: "Tank Shield",
|
||||
Class: ptrInt(4), // Armor
|
||||
Subclass: ptrInt(4), // Plate
|
||||
StatType1: ptrInt(STAT.DefenseSkillRating),
|
||||
StatValue1: ptrInt(15),
|
||||
},
|
||||
},
|
||||
expected: 6,
|
||||
},
|
||||
{
|
||||
name: "Tank item with Block Rating",
|
||||
item: Item{
|
||||
DbItem: mysql.DbItem{
|
||||
Entry: 3,
|
||||
Name: "Tank Shield",
|
||||
Class: ptrInt(4), // Armor
|
||||
StatType1: ptrInt(STAT.BlockRating),
|
||||
StatValue1: ptrInt(25),
|
||||
},
|
||||
},
|
||||
expected: 6,
|
||||
},
|
||||
{
|
||||
name: "Tank item with Block Value",
|
||||
item: Item{
|
||||
DbItem: mysql.DbItem{
|
||||
Entry: 4,
|
||||
Name: "Tank Shield",
|
||||
Class: ptrInt(4), // Armor
|
||||
StatType1: ptrInt(STAT.BlockValue),
|
||||
StatValue1: ptrInt(30),
|
||||
},
|
||||
},
|
||||
expected: 6,
|
||||
},
|
||||
|
||||
// Healer items (return 5) - Priority stats: MP5, Spell Healing Done
|
||||
{
|
||||
name: "Healer item with Mana Regeneration",
|
||||
item: Item{
|
||||
DbItem: mysql.DbItem{
|
||||
Entry: 5,
|
||||
Name: "Healer Staff",
|
||||
Class: ptrInt(2), // Weapon
|
||||
StatType1: ptrInt(STAT.ManaRegeneration),
|
||||
StatValue1: ptrInt(10),
|
||||
},
|
||||
},
|
||||
expected: 5,
|
||||
},
|
||||
{
|
||||
name: "Healer item with Spell Healing Done",
|
||||
item: Item{
|
||||
DbItem: mysql.DbItem{
|
||||
Entry: 6,
|
||||
Name: "Healer Robe",
|
||||
Class: ptrInt(4), // Armor
|
||||
StatType1: ptrInt(STAT.SpellHealingDone),
|
||||
StatValue1: ptrInt(50),
|
||||
},
|
||||
},
|
||||
expected: 5,
|
||||
},
|
||||
|
||||
// Mage items (return 4) - Priority stat: Spell Penetration
|
||||
{
|
||||
name: "Mage item with Spell Penetration",
|
||||
item: Item{
|
||||
DbItem: mysql.DbItem{
|
||||
Entry: 7,
|
||||
Name: "Mage Wand",
|
||||
Class: ptrInt(2), // Weapon
|
||||
StatType1: ptrInt(STAT.SpellPenetration),
|
||||
StatValue1: ptrInt(15),
|
||||
},
|
||||
},
|
||||
expected: 4,
|
||||
},
|
||||
|
||||
// Ranged Attacker items (return 3) - Priority stats: Ranged Attack Power, Ranged Crit, Ranged Hit
|
||||
{
|
||||
name: "Ranged item with Ranged Attack Power",
|
||||
item: Item{
|
||||
DbItem: mysql.DbItem{
|
||||
Entry: 8,
|
||||
Name: "Hunter Bow",
|
||||
Class: ptrInt(2), // Weapon
|
||||
StatType1: ptrInt(STAT.RangedAttackPower),
|
||||
StatValue1: ptrInt(40),
|
||||
},
|
||||
},
|
||||
expected: 3,
|
||||
},
|
||||
{
|
||||
name: "Ranged item with Ranged Crit Rating",
|
||||
item: Item{
|
||||
DbItem: mysql.DbItem{
|
||||
Entry: 9,
|
||||
Name: "Hunter Crossbow",
|
||||
Class: ptrInt(2), // Weapon
|
||||
StatType1: ptrInt(STAT.CritRangedRating),
|
||||
StatValue1: ptrInt(20),
|
||||
},
|
||||
},
|
||||
expected: 3,
|
||||
},
|
||||
{
|
||||
name: "Ranged item with Ranged Hit Rating",
|
||||
item: Item{
|
||||
DbItem: mysql.DbItem{
|
||||
Entry: 10,
|
||||
Name: "Hunter Gun",
|
||||
Class: ptrInt(2), // Weapon
|
||||
StatType1: ptrInt(STAT.HitRangedRating),
|
||||
StatValue1: ptrInt(15),
|
||||
},
|
||||
},
|
||||
expected: 3,
|
||||
},
|
||||
|
||||
// Cloth armor classification (return 4 for mage)
|
||||
{
|
||||
name: "Cloth armor without healer stats",
|
||||
item: Item{
|
||||
DbItem: mysql.DbItem{
|
||||
Entry: 11,
|
||||
Name: "Cloth Robe",
|
||||
Class: ptrInt(4), // Armor
|
||||
Subclass: ptrInt(1), // Cloth
|
||||
InventoryType: ptrInt(5), // Not off-hand (16)
|
||||
StatType1: ptrInt(STAT.Intellect),
|
||||
StatValue1: ptrInt(20),
|
||||
},
|
||||
},
|
||||
expected: 4,
|
||||
},
|
||||
|
||||
// Plate armor classification (return 1 for strength melee)
|
||||
{
|
||||
name: "Plate armor",
|
||||
item: Item{
|
||||
DbItem: mysql.DbItem{
|
||||
Entry: 12,
|
||||
Name: "Plate Chest",
|
||||
Class: ptrInt(4), // Armor
|
||||
Subclass: ptrInt(4), // Plate
|
||||
StatType1: ptrInt(STAT.Strength),
|
||||
StatValue1: ptrInt(25),
|
||||
},
|
||||
},
|
||||
expected: 1,
|
||||
},
|
||||
|
||||
// Mail/Leather armor with spell stats (return 4 for mage)
|
||||
{
|
||||
name: "Mail armor with spell power",
|
||||
item: Item{
|
||||
DbItem: mysql.DbItem{
|
||||
Entry: 13,
|
||||
Name: "Mail Vest",
|
||||
Class: ptrInt(4), // Armor
|
||||
Subclass: ptrInt(3), // Mail
|
||||
StatType1: ptrInt(STAT.SpellPower),
|
||||
StatValue1: ptrInt(30),
|
||||
},
|
||||
},
|
||||
expected: 4,
|
||||
},
|
||||
{
|
||||
name: "Leather armor with spell crit",
|
||||
item: Item{
|
||||
DbItem: mysql.DbItem{
|
||||
Entry: 14,
|
||||
Name: "Leather Tunic",
|
||||
Class: ptrInt(4), // Armor
|
||||
Subclass: ptrInt(2), // Leather
|
||||
StatType1: ptrInt(STAT.CritSpellRating),
|
||||
StatValue1: ptrInt(15),
|
||||
},
|
||||
},
|
||||
expected: 4,
|
||||
},
|
||||
|
||||
// Mail/Leather armor without spell stats (return 2 for agility)
|
||||
{
|
||||
name: "Mail armor without spell stats",
|
||||
item: Item{
|
||||
DbItem: mysql.DbItem{
|
||||
Entry: 15,
|
||||
Name: "Mail Armor",
|
||||
Class: ptrInt(4), // Armor
|
||||
Subclass: ptrInt(3), // Mail
|
||||
StatType1: ptrInt(STAT.Agility),
|
||||
StatValue1: ptrInt(20),
|
||||
},
|
||||
},
|
||||
expected: 2,
|
||||
},
|
||||
|
||||
// Weapon classifications
|
||||
{
|
||||
name: "Fist weapon (agility)",
|
||||
item: Item{
|
||||
DbItem: mysql.DbItem{
|
||||
Entry: 16,
|
||||
Name: "Fist Weapon",
|
||||
Class: ptrInt(2), // Weapon
|
||||
Subclass: ptrInt(13), // Fist weapon
|
||||
StatType1: ptrInt(STAT.Agility),
|
||||
StatValue1: ptrInt(15),
|
||||
},
|
||||
},
|
||||
expected: 2,
|
||||
},
|
||||
{
|
||||
name: "Throwing weapon (agility)",
|
||||
item: Item{
|
||||
DbItem: mysql.DbItem{
|
||||
Entry: 17,
|
||||
Name: "Throwing Knife",
|
||||
Class: ptrInt(2), // Weapon
|
||||
Subclass: ptrInt(16), // Thrown
|
||||
StatType1: ptrInt(STAT.Agility),
|
||||
StatValue1: ptrInt(12),
|
||||
},
|
||||
},
|
||||
expected: 2,
|
||||
},
|
||||
{
|
||||
name: "Wand (mage)",
|
||||
item: Item{
|
||||
DbItem: mysql.DbItem{
|
||||
Entry: 18,
|
||||
Name: "Magic Wand",
|
||||
Class: ptrInt(2), // Weapon
|
||||
Subclass: ptrInt(19), // Wand
|
||||
StatType1: ptrInt(STAT.SpellPower),
|
||||
StatValue1: ptrInt(25),
|
||||
},
|
||||
},
|
||||
expected: 4,
|
||||
},
|
||||
|
||||
// Polearm/Spear with strength (return 1)
|
||||
{
|
||||
name: "Polearm with strength",
|
||||
item: Item{
|
||||
DbItem: mysql.DbItem{
|
||||
Entry: 19,
|
||||
Name: "Strength Polearm",
|
||||
Class: ptrInt(2), // Weapon
|
||||
Subclass: ptrInt(17), // Polearm
|
||||
StatType1: ptrInt(STAT.Strength),
|
||||
StatValue1: ptrInt(30),
|
||||
},
|
||||
},
|
||||
expected: 1,
|
||||
},
|
||||
{
|
||||
name: "Spear with attack power",
|
||||
item: Item{
|
||||
DbItem: mysql.DbItem{
|
||||
Entry: 20,
|
||||
Name: "Attack Power Spear",
|
||||
Class: ptrInt(2), // Weapon
|
||||
Subclass: ptrInt(6), // Spear
|
||||
StatType1: ptrInt(STAT.AttackPower),
|
||||
StatValue1: ptrInt(50),
|
||||
},
|
||||
},
|
||||
expected: 1,
|
||||
},
|
||||
|
||||
// Polearm/Spear with agility (return 2)
|
||||
{
|
||||
name: "Polearm with agility",
|
||||
item: Item{
|
||||
DbItem: mysql.DbItem{
|
||||
Entry: 21,
|
||||
Name: "Agility Polearm",
|
||||
Class: ptrInt(2), // Weapon
|
||||
Subclass: ptrInt(17), // Polearm
|
||||
StatType1: ptrInt(STAT.Agility),
|
||||
StatValue1: ptrInt(25),
|
||||
},
|
||||
},
|
||||
expected: 2,
|
||||
},
|
||||
|
||||
// Polearm/Spear fallback (return 5 for healer)
|
||||
{
|
||||
name: "Polearm fallback to healer",
|
||||
item: Item{
|
||||
DbItem: mysql.DbItem{
|
||||
Entry: 22,
|
||||
Name: "Generic Polearm",
|
||||
Class: ptrInt(2), // Weapon
|
||||
Subclass: ptrInt(17), // Polearm
|
||||
StatType1: ptrInt(STAT.Stamina),
|
||||
StatValue1: ptrInt(20),
|
||||
},
|
||||
},
|
||||
expected: 5,
|
||||
},
|
||||
|
||||
// Bow/Gun/Crossbow with strength (return 1)
|
||||
{
|
||||
name: "Bow with strength",
|
||||
item: Item{
|
||||
DbItem: mysql.DbItem{
|
||||
Entry: 23,
|
||||
Name: "Strength Bow",
|
||||
Class: ptrInt(2), // Weapon
|
||||
Subclass: ptrInt(2), // Bow
|
||||
StatType1: ptrInt(STAT.Strength),
|
||||
StatValue1: ptrInt(20),
|
||||
},
|
||||
},
|
||||
expected: 1,
|
||||
},
|
||||
|
||||
// Bow/Gun/Crossbow fallback (return 3 for ranged)
|
||||
{
|
||||
name: "Bow fallback to ranged",
|
||||
item: Item{
|
||||
DbItem: mysql.DbItem{
|
||||
Entry: 24,
|
||||
Name: "Generic Bow",
|
||||
Class: ptrInt(2), // Weapon
|
||||
Subclass: ptrInt(2), // Bow
|
||||
StatType1: ptrInt(STAT.Stamina),
|
||||
StatValue1: ptrInt(15),
|
||||
},
|
||||
},
|
||||
expected: 3,
|
||||
},
|
||||
|
||||
// Base stat priority tests
|
||||
{
|
||||
name: "Item with Spirit (healer priority)",
|
||||
item: Item{
|
||||
DbItem: mysql.DbItem{
|
||||
Entry: 25,
|
||||
Name: "Spirit Item",
|
||||
Class: ptrInt(4), // Armor
|
||||
StatType1: ptrInt(STAT.Spirit),
|
||||
StatValue1: ptrInt(15),
|
||||
},
|
||||
},
|
||||
expected: 5,
|
||||
},
|
||||
{
|
||||
name: "Item with Intellect (mage priority)",
|
||||
item: Item{
|
||||
DbItem: mysql.DbItem{
|
||||
Entry: 26,
|
||||
Name: "Intellect Item",
|
||||
Class: ptrInt(4), // Armor
|
||||
StatType1: ptrInt(STAT.Intellect),
|
||||
StatValue1: ptrInt(20),
|
||||
},
|
||||
},
|
||||
expected: 4,
|
||||
},
|
||||
{
|
||||
name: "Item with Strength (strength melee priority)",
|
||||
item: Item{
|
||||
DbItem: mysql.DbItem{
|
||||
Entry: 27,
|
||||
Name: "Strength Item",
|
||||
Class: ptrInt(4), // Armor
|
||||
StatType1: ptrInt(STAT.Strength),
|
||||
StatValue1: ptrInt(25),
|
||||
},
|
||||
},
|
||||
expected: 1,
|
||||
},
|
||||
{
|
||||
name: "Item with Agility (agility melee priority)",
|
||||
item: Item{
|
||||
DbItem: mysql.DbItem{
|
||||
Entry: 28,
|
||||
Name: "Agility Item",
|
||||
Class: ptrInt(4), // Armor
|
||||
StatType1: ptrInt(STAT.Agility),
|
||||
StatValue1: ptrInt(18),
|
||||
},
|
||||
},
|
||||
expected: 2,
|
||||
},
|
||||
|
||||
// Secondary stat tests
|
||||
{
|
||||
name: "Item with Attack Power (agility melee)",
|
||||
item: Item{
|
||||
DbItem: mysql.DbItem{
|
||||
Entry: 29,
|
||||
Name: "Attack Power Item",
|
||||
Class: ptrInt(4), // Armor
|
||||
StatType1: ptrInt(STAT.AttackPower),
|
||||
StatValue1: ptrInt(40),
|
||||
},
|
||||
},
|
||||
expected: 2,
|
||||
},
|
||||
{
|
||||
name: "Item with Melee Haste (agility melee)",
|
||||
item: Item{
|
||||
DbItem: mysql.DbItem{
|
||||
Entry: 30,
|
||||
Name: "Melee Haste Item",
|
||||
Class: ptrInt(4), // Armor
|
||||
StatType1: ptrInt(STAT.HasteMeleeRating),
|
||||
StatValue1: ptrInt(15),
|
||||
},
|
||||
},
|
||||
expected: 2,
|
||||
},
|
||||
{
|
||||
name: "Item with Spell Power (mage)",
|
||||
item: Item{
|
||||
DbItem: mysql.DbItem{
|
||||
Entry: 31,
|
||||
Name: "Spell Power Item",
|
||||
Class: ptrInt(4), // Armor
|
||||
StatType1: ptrInt(STAT.SpellPower),
|
||||
StatValue1: ptrInt(35),
|
||||
},
|
||||
},
|
||||
expected: 4,
|
||||
},
|
||||
{
|
||||
name: "Item with Ranged Attack Power (ranged)",
|
||||
item: Item{
|
||||
DbItem: mysql.DbItem{
|
||||
Entry: 32,
|
||||
Name: "Ranged AP Item",
|
||||
Class: ptrInt(4), // Armor
|
||||
StatType1: ptrInt(STAT.RangedAttackPower),
|
||||
StatValue1: ptrInt(30),
|
||||
},
|
||||
},
|
||||
expected: 3,
|
||||
},
|
||||
|
||||
// Armor type fallback tests
|
||||
{
|
||||
name: "Cloth armor fallback",
|
||||
item: Item{
|
||||
DbItem: mysql.DbItem{
|
||||
Entry: 33,
|
||||
Name: "Generic Cloth",
|
||||
Class: ptrInt(4), // Armor
|
||||
Subclass: ptrInt(1), // Cloth
|
||||
StatType1: ptrInt(STAT.Stamina),
|
||||
StatValue1: ptrInt(20),
|
||||
},
|
||||
},
|
||||
expected: 4,
|
||||
},
|
||||
{
|
||||
name: "Plate armor fallback",
|
||||
item: Item{
|
||||
DbItem: mysql.DbItem{
|
||||
Entry: 34,
|
||||
Name: "Generic Plate",
|
||||
Class: ptrInt(4), // Armor
|
||||
Subclass: ptrInt(4), // Plate
|
||||
StatType1: ptrInt(STAT.Stamina),
|
||||
StatValue1: ptrInt(25),
|
||||
},
|
||||
},
|
||||
expected: 1,
|
||||
},
|
||||
{
|
||||
name: "Leather armor fallback",
|
||||
item: Item{
|
||||
DbItem: mysql.DbItem{
|
||||
Entry: 35,
|
||||
Name: "Generic Leather",
|
||||
Class: ptrInt(4), // Armor
|
||||
Subclass: ptrInt(2), // Leather
|
||||
StatType1: ptrInt(STAT.Stamina),
|
||||
StatValue1: ptrInt(18),
|
||||
},
|
||||
},
|
||||
expected: 2,
|
||||
},
|
||||
|
||||
// Generic fallback (return 7)
|
||||
{
|
||||
name: "Generic item with no identifiable stats",
|
||||
item: Item{
|
||||
DbItem: mysql.DbItem{
|
||||
Entry: 36,
|
||||
Name: "Generic Item",
|
||||
Class: ptrInt(15), // Miscellaneous
|
||||
StatType1: ptrInt(STAT.Stamina),
|
||||
StatValue1: ptrInt(10),
|
||||
},
|
||||
},
|
||||
expected: 7,
|
||||
},
|
||||
}
|
||||
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
result := tt.item.GetClassUserType()
|
||||
if result != tt.expected {
|
||||
t.Errorf("GetClassUserType() = %v, expected %v for item: %s", result, tt.expected, tt.item.Name)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
// Test edge cases and complex scenarios
|
||||
func TestGetClassUserTypeEdgeCases(t *testing.T) {
|
||||
tests := []struct {
|
||||
name string
|
||||
item Item
|
||||
expected int
|
||||
}{
|
||||
{
|
||||
name: "Item with multiple stats - tank priority wins",
|
||||
item: Item{
|
||||
DbItem: mysql.DbItem{
|
||||
Entry: 100,
|
||||
Name: "Multi-stat Tank Item",
|
||||
Class: ptrInt(4), // Armor
|
||||
StatType1: ptrInt(STAT.Strength),
|
||||
StatValue1: ptrInt(20),
|
||||
StatType2: ptrInt(STAT.ParryRating), // Tank stat should win
|
||||
StatValue2: ptrInt(15),
|
||||
StatType3: ptrInt(STAT.Agility),
|
||||
StatValue3: ptrInt(18),
|
||||
},
|
||||
},
|
||||
expected: 6, // Tank
|
||||
},
|
||||
{
|
||||
name: "Item with multiple stats - healer priority wins",
|
||||
item: Item{
|
||||
DbItem: mysql.DbItem{
|
||||
Entry: 101,
|
||||
Name: "Multi-stat Healer Item",
|
||||
Class: ptrInt(4), // Armor
|
||||
StatType1: ptrInt(STAT.Intellect),
|
||||
StatValue1: ptrInt(25),
|
||||
StatType2: ptrInt(STAT.ManaRegeneration), // Healer stat should win
|
||||
StatValue2: ptrInt(8),
|
||||
StatType3: ptrInt(STAT.SpellPower),
|
||||
StatValue3: ptrInt(30),
|
||||
},
|
||||
},
|
||||
expected: 5, // Healer
|
||||
},
|
||||
{
|
||||
name: "Cloth off-hand item (should not be classified as mage)",
|
||||
item: Item{
|
||||
DbItem: mysql.DbItem{
|
||||
Entry: 102,
|
||||
Name: "Cloth Off-hand",
|
||||
Class: ptrInt(4), // Armor
|
||||
Subclass: ptrInt(1), // Cloth
|
||||
InventoryType: ptrInt(16), // Off-hand
|
||||
StatType1: ptrInt(STAT.Intellect),
|
||||
StatValue1: ptrInt(20),
|
||||
},
|
||||
},
|
||||
expected: 4, // Still mage due to intellect in base stats
|
||||
},
|
||||
}
|
||||
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
result := tt.item.GetClassUserType()
|
||||
if result != tt.expected {
|
||||
t.Errorf("GetClassUserType() = %v, expected %v for item: %s", result, tt.expected, tt.item.Name)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
504
internal/items/item_test.go
Normal file
504
internal/items/item_test.go
Normal file
@@ -0,0 +1,504 @@
|
||||
package items
|
||||
|
||||
import (
|
||||
"io"
|
||||
"log"
|
||||
"math"
|
||||
"reflect"
|
||||
"testing"
|
||||
|
||||
"github.com/araxiaonline/endgame-item-generator/internal/db/mysql"
|
||||
"golang.org/x/exp/rand"
|
||||
)
|
||||
|
||||
func TestGetPrimaryStat(t *testing.T) {
|
||||
|
||||
originalLog := log.Writer()
|
||||
log.SetOutput(io.Discard)
|
||||
defer log.SetOutput(originalLog)
|
||||
|
||||
tests := []struct {
|
||||
name string
|
||||
item Item
|
||||
wantStat int
|
||||
wantValue int
|
||||
expectError bool
|
||||
}{
|
||||
{
|
||||
name: "No primary stat found",
|
||||
item: Item{
|
||||
DbItem: mysql.DbItem{
|
||||
Entry: 1,
|
||||
Name: "Test Item",
|
||||
StatType1: ptrInt(1), StatValue1: ptrInt(10),
|
||||
StatType2: ptrInt(2), StatValue2: ptrInt(20),
|
||||
StatType3: ptrInt(12), StatValue3: ptrInt(15),
|
||||
},
|
||||
},
|
||||
wantStat: 0,
|
||||
wantValue: 0,
|
||||
expectError: false,
|
||||
},
|
||||
{
|
||||
name: "Primary stat found with higher value",
|
||||
item: Item{
|
||||
DbItem: mysql.DbItem{
|
||||
Entry: 1,
|
||||
Name: "Test Item",
|
||||
StatType1: ptrInt(3), StatValue1: ptrInt(10), // Agility
|
||||
StatType2: ptrInt(4), StatValue2: ptrInt(20), // Strength
|
||||
StatType3: ptrInt(5), StatValue3: ptrInt(15), // Intellect
|
||||
},
|
||||
},
|
||||
wantStat: 4, // Strength
|
||||
wantValue: 20,
|
||||
expectError: false,
|
||||
},
|
||||
{
|
||||
name: "Primary stat found with lower value",
|
||||
item: Item{
|
||||
DbItem: mysql.DbItem{
|
||||
Entry: 1,
|
||||
Name: "Test Item",
|
||||
StatType1: ptrInt(3), StatValue1: ptrInt(30), // Agility
|
||||
StatType2: ptrInt(4), StatValue2: ptrInt(20), // Strength
|
||||
StatType3: ptrInt(5), StatValue3: ptrInt(15), // Intellect
|
||||
},
|
||||
},
|
||||
wantStat: 3, // Agility
|
||||
wantValue: 30,
|
||||
expectError: false,
|
||||
},
|
||||
}
|
||||
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
gotStat, gotValue, err := tt.item.GetPrimaryStat()
|
||||
if (err != nil) != tt.expectError {
|
||||
t.Errorf("GetPrimaryStat() error = %v, expectError %v", err, tt.expectError)
|
||||
return
|
||||
}
|
||||
if gotStat != tt.wantStat {
|
||||
t.Errorf("GetPrimaryStat() gotStat = %v, want %v", gotStat, tt.wantStat)
|
||||
}
|
||||
if gotValue != tt.wantValue {
|
||||
t.Errorf("GetPrimaryStat() gotValue = %v, want %v", gotValue, tt.wantValue)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestGetStatList(t *testing.T) {
|
||||
originalLog := log.Writer()
|
||||
log.SetOutput(io.Discard)
|
||||
defer log.SetOutput(originalLog)
|
||||
|
||||
tests := []struct {
|
||||
name string
|
||||
item Item
|
||||
want []int
|
||||
expectError bool
|
||||
}{
|
||||
{
|
||||
name: "No stats available",
|
||||
item: Item{
|
||||
DbItem: mysql.DbItem{
|
||||
Entry: 1,
|
||||
Name: "Test Item",
|
||||
StatType1: ptrInt(0), StatValue1: ptrInt(0),
|
||||
StatType2: ptrInt(0), StatValue2: ptrInt(0),
|
||||
},
|
||||
},
|
||||
want: []int{},
|
||||
expectError: false,
|
||||
},
|
||||
{
|
||||
name: "Multiple stats available",
|
||||
item: Item{
|
||||
DbItem: mysql.DbItem{
|
||||
Entry: 1,
|
||||
Name: "Test Item",
|
||||
StatType1: ptrInt(3), StatValue1: ptrInt(10), // Agility
|
||||
StatType2: ptrInt(4), StatValue2: ptrInt(20), // Strength
|
||||
StatType3: ptrInt(5), StatValue3: ptrInt(15), // Intellect
|
||||
},
|
||||
},
|
||||
want: []int{3, 4, 5},
|
||||
expectError: false,
|
||||
},
|
||||
{
|
||||
name: "Stats are ordered correctly",
|
||||
item: Item{
|
||||
DbItem: mysql.DbItem{
|
||||
Entry: 1,
|
||||
Name: "Test Item",
|
||||
StatType1: ptrInt(7), StatValue1: ptrInt(10), // Agility
|
||||
StatType2: ptrInt(4), StatValue2: ptrInt(20), // Strength
|
||||
StatType3: ptrInt(31), StatValue3: ptrInt(15), // Intellect
|
||||
},
|
||||
},
|
||||
want: []int{4, 7, 31},
|
||||
expectError: false,
|
||||
},
|
||||
{
|
||||
name: "Some stats are zero",
|
||||
item: Item{
|
||||
DbItem: mysql.DbItem{
|
||||
Entry: 1,
|
||||
Name: "Test Item",
|
||||
StatType1: ptrInt(3), StatValue1: ptrInt(0), // Agility
|
||||
StatType2: ptrInt(4), StatValue2: ptrInt(20), // Strength
|
||||
StatType3: ptrInt(5), StatValue3: ptrInt(0), // Intellect
|
||||
},
|
||||
},
|
||||
want: []int{4},
|
||||
expectError: false,
|
||||
},
|
||||
}
|
||||
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
got, err := tt.item.GetStatList()
|
||||
if (err != nil) != tt.expectError {
|
||||
t.Errorf("GetStatList() error = %v, expectError %v", err, tt.expectError)
|
||||
return
|
||||
}
|
||||
if !reflect.DeepEqual(got, tt.want) {
|
||||
t.Errorf("GetStatList() got = %v, want %v", got, tt.want)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestGetDPS(t *testing.T) {
|
||||
tests := []struct {
|
||||
name string
|
||||
item Item
|
||||
wantDPS float64
|
||||
expectError bool
|
||||
}{
|
||||
{
|
||||
name: "Valid DPS calculation",
|
||||
item: Item{
|
||||
DbItem: mysql.DbItem{
|
||||
MinDmg1: ptrFloat64(50),
|
||||
MaxDmg1: ptrFloat64(70),
|
||||
Delay: ptrFloat64(3000),
|
||||
},
|
||||
},
|
||||
wantDPS: 20.00,
|
||||
expectError: false,
|
||||
},
|
||||
{
|
||||
name: "High damage DPS calculation",
|
||||
item: Item{
|
||||
DbItem: mysql.DbItem{
|
||||
MinDmg1: ptrFloat64(100),
|
||||
MaxDmg1: ptrFloat64(150),
|
||||
Delay: ptrFloat64(2000),
|
||||
},
|
||||
},
|
||||
wantDPS: 62.50,
|
||||
expectError: false,
|
||||
},
|
||||
{
|
||||
name: "Low damage DPS calculation",
|
||||
item: Item{
|
||||
DbItem: mysql.DbItem{
|
||||
MinDmg1: ptrFloat64(10),
|
||||
MaxDmg1: ptrFloat64(15),
|
||||
Delay: ptrFloat64(1500),
|
||||
},
|
||||
},
|
||||
wantDPS: 8.33,
|
||||
expectError: false,
|
||||
},
|
||||
{
|
||||
name: "Missing MinDmg1",
|
||||
item: Item{
|
||||
DbItem: mysql.DbItem{
|
||||
MaxDmg1: ptrFloat64(70),
|
||||
Delay: ptrFloat64(3000),
|
||||
},
|
||||
},
|
||||
wantDPS: 0,
|
||||
expectError: true,
|
||||
},
|
||||
{
|
||||
name: "Missing MaxDmg1",
|
||||
item: Item{
|
||||
DbItem: mysql.DbItem{
|
||||
MinDmg1: ptrFloat64(50),
|
||||
Delay: ptrFloat64(3000),
|
||||
},
|
||||
},
|
||||
wantDPS: 0,
|
||||
expectError: true,
|
||||
},
|
||||
{
|
||||
name: "Missing Delay",
|
||||
item: Item{
|
||||
DbItem: mysql.DbItem{
|
||||
MinDmg1: ptrFloat64(50),
|
||||
MaxDmg1: ptrFloat64(70),
|
||||
},
|
||||
},
|
||||
wantDPS: 0,
|
||||
expectError: true,
|
||||
},
|
||||
}
|
||||
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
gotDPS, err := tt.item.GetDPS()
|
||||
if (err != nil) != tt.expectError {
|
||||
t.Errorf("GetDPS() error = %v, expectError %v", err, tt.expectError)
|
||||
return
|
||||
}
|
||||
if !tt.expectError && !almostEqual(gotDPS, tt.wantDPS, 0.01) {
|
||||
t.Errorf("GetDPS() = %v, want %v", gotDPS, tt.wantDPS)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestScaleDPS(t *testing.T) {
|
||||
tests := []struct {
|
||||
name string
|
||||
item Item
|
||||
level int
|
||||
wantDPSMin float64
|
||||
wantDPSMax float64
|
||||
expectError bool
|
||||
}{
|
||||
{
|
||||
name: "Valid Scale DPS calculation",
|
||||
item: Item{
|
||||
DbItem: mysql.DbItem{
|
||||
ItemLevel: ptrInt(60),
|
||||
Delay: ptrFloat64(3000),
|
||||
MinDmg1: ptrFloat64(50),
|
||||
MaxDmg1: ptrFloat64(70),
|
||||
Subclass: ptrInt(4), // One-handed weapon
|
||||
Quality: ptrInt(3), // Rare
|
||||
},
|
||||
},
|
||||
level: 70,
|
||||
wantDPSMin: 53.0, // Expected DPS range due to randomness
|
||||
wantDPSMax: 107.0,
|
||||
expectError: false,
|
||||
},
|
||||
{
|
||||
name: "High level Scale DPS calculation",
|
||||
item: Item{
|
||||
DbItem: mysql.DbItem{
|
||||
ItemLevel: ptrInt(80),
|
||||
Delay: ptrFloat64(2000),
|
||||
MinDmg1: ptrFloat64(150),
|
||||
MaxDmg1: ptrFloat64(200),
|
||||
Subclass: ptrInt(17), // Two-handed weapon
|
||||
Quality: ptrInt(4), // Epic
|
||||
},
|
||||
},
|
||||
level: 100,
|
||||
wantDPSMin: 120.0, // Expected DPS range due to randomness
|
||||
wantDPSMax: 240.0,
|
||||
expectError: false,
|
||||
},
|
||||
{
|
||||
name: "Low level Scale DPS calculation",
|
||||
item: Item{
|
||||
DbItem: mysql.DbItem{
|
||||
ItemLevel: ptrInt(20),
|
||||
Delay: ptrFloat64(1000),
|
||||
MinDmg1: ptrFloat64(30),
|
||||
MaxDmg1: ptrFloat64(50),
|
||||
Subclass: ptrInt(2), // Ranged weapon
|
||||
Quality: ptrInt(2), // Uncommon
|
||||
},
|
||||
},
|
||||
level: 25,
|
||||
wantDPSMin: 21.0, // Expected DPS range due to randomness
|
||||
wantDPSMax: 42.0,
|
||||
expectError: false,
|
||||
},
|
||||
{
|
||||
name: "Missing ItemLevel",
|
||||
item: Item{
|
||||
DbItem: mysql.DbItem{
|
||||
Delay: ptrFloat64(3000),
|
||||
MinDmg1: ptrFloat64(50),
|
||||
MaxDmg1: ptrFloat64(70),
|
||||
Subclass: ptrInt(4), // One-handed weapon
|
||||
Quality: ptrInt(3), // Rare
|
||||
},
|
||||
},
|
||||
level: 70,
|
||||
wantDPSMin: 0,
|
||||
wantDPSMax: 0,
|
||||
expectError: true,
|
||||
},
|
||||
{
|
||||
name: "Missing Delay",
|
||||
item: Item{
|
||||
DbItem: mysql.DbItem{
|
||||
ItemLevel: ptrInt(60),
|
||||
MinDmg1: ptrFloat64(50),
|
||||
MaxDmg1: ptrFloat64(70),
|
||||
Subclass: ptrInt(4), // One-handed weapon
|
||||
Quality: ptrInt(3), // Rare
|
||||
},
|
||||
},
|
||||
level: 70,
|
||||
wantDPSMin: 0,
|
||||
wantDPSMax: 0,
|
||||
expectError: true,
|
||||
},
|
||||
{
|
||||
name: "Secondary damage scaling",
|
||||
item: Item{
|
||||
DbItem: mysql.DbItem{
|
||||
ItemLevel: ptrInt(60),
|
||||
Delay: ptrFloat64(3000),
|
||||
MinDmg1: ptrFloat64(50),
|
||||
MaxDmg1: ptrFloat64(70),
|
||||
MinDmg2: ptrFloat64(25),
|
||||
MaxDmg2: ptrFloat64(35),
|
||||
Subclass: ptrInt(4), // One-handed weapon
|
||||
Quality: ptrInt(3), // Rare
|
||||
},
|
||||
},
|
||||
level: 70,
|
||||
wantDPSMin: 53.0, // Expected DPS range due to randomness
|
||||
wantDPSMax: 107.0,
|
||||
expectError: false,
|
||||
},
|
||||
}
|
||||
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
// Seed the random number generator for consistent test results
|
||||
rand.Seed(1)
|
||||
|
||||
gotDPS, err := tt.item.ScaleDPS(tt.level, 100)
|
||||
if (err != nil) != tt.expectError {
|
||||
t.Errorf("ScaleDPS() error = %v, expectError %v", err, tt.expectError)
|
||||
return
|
||||
}
|
||||
if !tt.expectError && (gotDPS < tt.wantDPSMin || gotDPS > tt.wantDPSMax) {
|
||||
t.Errorf("ScaleDPS() = %v, want between %v and %v", gotDPS, tt.wantDPSMin, tt.wantDPSMax)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestGetDpsModifier(t *testing.T) {
|
||||
tests := []struct {
|
||||
name string
|
||||
item Item
|
||||
wantModifier float64
|
||||
expectError bool
|
||||
}{
|
||||
{
|
||||
name: "Valid one-handed weapon modifier",
|
||||
item: Item{
|
||||
DbItem: mysql.DbItem{
|
||||
Subclass: ptrInt(4), // One-handed weapon
|
||||
Quality: ptrInt(3), // Rare
|
||||
},
|
||||
},
|
||||
wantModifier: 0.64 * 1.38,
|
||||
expectError: false,
|
||||
},
|
||||
{
|
||||
name: "Valid two-handed weapon modifier",
|
||||
item: Item{
|
||||
DbItem: mysql.DbItem{
|
||||
Subclass: ptrInt(17), // Two-handed weapon
|
||||
Quality: ptrInt(4), // Epic
|
||||
},
|
||||
},
|
||||
wantModifier: 0.80 * 1.5,
|
||||
expectError: false,
|
||||
},
|
||||
{
|
||||
name: "Valid ranged weapon modifier",
|
||||
item: Item{
|
||||
DbItem: mysql.DbItem{
|
||||
Subclass: ptrInt(2), // Ranged weapon
|
||||
Quality: ptrInt(2), // Uncommon
|
||||
},
|
||||
},
|
||||
wantModifier: 0.70 * 1.25,
|
||||
expectError: false,
|
||||
},
|
||||
{
|
||||
name: "Valid wand modifier",
|
||||
item: Item{
|
||||
DbItem: mysql.DbItem{
|
||||
Subclass: ptrInt(19), // Wand
|
||||
Quality: ptrInt(4), // Epic
|
||||
},
|
||||
},
|
||||
wantModifier: 0.70 * 1.5,
|
||||
expectError: false,
|
||||
},
|
||||
{
|
||||
name: "Invalid subclass",
|
||||
item: Item{
|
||||
DbItem: mysql.DbItem{
|
||||
Subclass: ptrInt(99), // Invalid subclass
|
||||
Quality: ptrInt(3), // Rare
|
||||
},
|
||||
},
|
||||
wantModifier: 0,
|
||||
expectError: true,
|
||||
},
|
||||
{
|
||||
name: "Missing subclass",
|
||||
item: Item{
|
||||
DbItem: mysql.DbItem{
|
||||
Quality: ptrInt(3), // Rare
|
||||
},
|
||||
},
|
||||
wantModifier: 0,
|
||||
expectError: true,
|
||||
},
|
||||
{
|
||||
name: "Missing quality",
|
||||
item: Item{
|
||||
DbItem: mysql.DbItem{
|
||||
Subclass: ptrInt(4), // One-handed weapon
|
||||
},
|
||||
},
|
||||
wantModifier: 0,
|
||||
expectError: true,
|
||||
},
|
||||
}
|
||||
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
gotModifier, err := tt.item.GetDpsModifier()
|
||||
if (err != nil) != tt.expectError {
|
||||
t.Errorf("GetDpsModifier() error = %v, expectError %v", err, tt.expectError)
|
||||
return
|
||||
}
|
||||
if !tt.expectError && !almostEqual(gotModifier, tt.wantModifier, 0.01) {
|
||||
t.Errorf("GetDpsModifier() = %v, want %v", gotModifier, tt.wantModifier)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
// Helper function to return a pointer to an int
|
||||
func ptrInt(i int) *int {
|
||||
return &i
|
||||
}
|
||||
|
||||
func ptrFloat64(f float64) *float64 {
|
||||
return &f
|
||||
}
|
||||
|
||||
func almostEqual(a, b, tolerance float64) bool {
|
||||
return math.Abs(a-b) <= tolerance
|
||||
}
|
||||
1604
internal/items/items.go
Normal file
1604
internal/items/items.go
Normal file
File diff suppressed because it is too large
Load Diff
95
internal/items/stat.go
Normal file
95
internal/items/stat.go
Normal file
@@ -0,0 +1,95 @@
|
||||
package items
|
||||
|
||||
type stats struct {
|
||||
Mana int
|
||||
Health int
|
||||
Agility int
|
||||
Strength int
|
||||
Intellect int
|
||||
Spirit int
|
||||
Stamina int
|
||||
DefenseSkillRating int
|
||||
DodgeRating int
|
||||
ParryRating int
|
||||
BlockRating int
|
||||
HitMeleeRating int
|
||||
HitRangedRating int
|
||||
HitSpellRating int
|
||||
CritMeleeRating int
|
||||
CritRangedRating int
|
||||
CritSpellRating int
|
||||
HitTakenMeleeRating int
|
||||
HitTakenRangedRating int
|
||||
HitTakenSpellRating int
|
||||
CritTakenMeleeRating int
|
||||
CritTakenRangedRating int
|
||||
CritTakenSpellRating int
|
||||
HasteMeleeRating int
|
||||
HasteRangedRating int
|
||||
HasteSpellRating int
|
||||
HitRating int
|
||||
CritRating int
|
||||
HitTakenRating int
|
||||
CritTakenRating int
|
||||
ResilienceRating int
|
||||
HasteRating int
|
||||
ExpertiseRating int
|
||||
AttackPower int
|
||||
RangedAttackPower int
|
||||
FeralAttackPower int
|
||||
SpellHealingDone int
|
||||
SpellDamageDone int
|
||||
ManaRegeneration int
|
||||
ArmorPenetrationRating int
|
||||
SpellPower int
|
||||
HealthRegen int
|
||||
SpellPenetration int
|
||||
BlockValue int
|
||||
}
|
||||
|
||||
var STAT = stats{
|
||||
Mana: 0,
|
||||
Health: 1,
|
||||
Agility: 3,
|
||||
Strength: 4,
|
||||
Intellect: 5,
|
||||
Spirit: 6,
|
||||
Stamina: 7,
|
||||
DefenseSkillRating: 12,
|
||||
DodgeRating: 13,
|
||||
ParryRating: 14,
|
||||
BlockRating: 15,
|
||||
HitMeleeRating: 16,
|
||||
HitRangedRating: 17,
|
||||
HitSpellRating: 18,
|
||||
CritMeleeRating: 19,
|
||||
CritRangedRating: 20,
|
||||
CritSpellRating: 21,
|
||||
HitTakenMeleeRating: 22,
|
||||
HitTakenRangedRating: 23,
|
||||
HitTakenSpellRating: 24,
|
||||
CritTakenMeleeRating: 25,
|
||||
CritTakenRangedRating: 26,
|
||||
CritTakenSpellRating: 27,
|
||||
HasteMeleeRating: 28,
|
||||
HasteRangedRating: 29,
|
||||
HasteSpellRating: 30,
|
||||
HitRating: 31,
|
||||
CritRating: 32,
|
||||
HitTakenRating: 33,
|
||||
CritTakenRating: 34,
|
||||
ResilienceRating: 35,
|
||||
HasteRating: 36,
|
||||
ExpertiseRating: 37,
|
||||
AttackPower: 38,
|
||||
RangedAttackPower: 39,
|
||||
FeralAttackPower: 40,
|
||||
SpellHealingDone: 41,
|
||||
SpellDamageDone: 42,
|
||||
ManaRegeneration: 43,
|
||||
ArmorPenetrationRating: 44,
|
||||
SpellPower: 45,
|
||||
HealthRegen: 46,
|
||||
SpellPenetration: 47,
|
||||
BlockValue: 48,
|
||||
}
|
||||
262
internal/items/templates.go
Normal file
262
internal/items/templates.go
Normal file
@@ -0,0 +1,262 @@
|
||||
package items
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"log"
|
||||
"math/rand"
|
||||
)
|
||||
|
||||
// StatTemplate represents a template for generating item stats
|
||||
type StatTemplate struct {
|
||||
Name string
|
||||
RequiredStats []StatEntry // Stats that are always present
|
||||
OptionalStats []StatEntry // Stats that may be present with variance
|
||||
MaxOptional int // Maximum number of optional stats to add
|
||||
}
|
||||
|
||||
// StatEntry represents a stat type and value range
|
||||
type StatEntry struct {
|
||||
StatType int
|
||||
BaseValue int
|
||||
ValueRange int // Random variance range (0 to ValueRange-1)
|
||||
Multiplier float64 // Multiplier for base stat value
|
||||
}
|
||||
|
||||
// StatTemplateManager handles stat template application
|
||||
type StatTemplateManager struct {
|
||||
debug bool
|
||||
}
|
||||
|
||||
// NewStatTemplateManager creates a new stat template manager
|
||||
func NewStatTemplateManager(debug bool) *StatTemplateManager {
|
||||
return &StatTemplateManager{debug: debug}
|
||||
}
|
||||
|
||||
// ApplySimpleStatTemplate applies a basic stat template to an item for phase 0 scaling
|
||||
func (stm *StatTemplateManager) ApplySimpleStatTemplate(item *Item) {
|
||||
if stm.debug {
|
||||
log.Printf("Applying simple stat template for %s (Class: %d, Subclass: %d)",
|
||||
item.Name, *item.Class, *item.Subclass)
|
||||
}
|
||||
|
||||
// Clear existing stats
|
||||
stm.clearItemStats(item)
|
||||
|
||||
// Get base stat value with variance
|
||||
baseStatValue := 6 + rand.Intn(5) // Random between 6-10 for variance
|
||||
|
||||
// Apply template based on item type
|
||||
if *item.Class == 2 { // Weapons
|
||||
stm.applyWeaponTemplate(item, baseStatValue)
|
||||
} else if *item.Class == 4 { // Armor
|
||||
stm.applyArmorTemplate(item, baseStatValue)
|
||||
}
|
||||
|
||||
// Update stats count
|
||||
stm.updateStatsCount(item)
|
||||
|
||||
if stm.debug {
|
||||
statsCount, _ := item.GetField("StatsCount")
|
||||
log.Printf("Applied simple template: %d stats for %s", statsCount, item.Name)
|
||||
}
|
||||
}
|
||||
|
||||
// clearItemStats clears all existing stats on an item
|
||||
func (stm *StatTemplateManager) clearItemStats(item *Item) {
|
||||
for i := 1; i <= 10; i++ {
|
||||
item.UpdateField(fmt.Sprintf("StatType%d", i), 0)
|
||||
item.UpdateField(fmt.Sprintf("StatValue%d", i), 0)
|
||||
}
|
||||
}
|
||||
|
||||
// applyWeaponTemplate applies weapon-specific stat templates
|
||||
func (stm *StatTemplateManager) applyWeaponTemplate(item *Item, baseStatValue int) {
|
||||
classType := item.GetClassUserType()
|
||||
|
||||
// Determine weapon type
|
||||
isPhysicalWeapon := stm.isPhysicalWeapon(*item.Subclass, classType)
|
||||
isTankWeapon := (*item.Subclass == 6) // Shield
|
||||
|
||||
if stm.debug {
|
||||
log.Printf("Weapon %s (subclass %d, classType %d) determined as physical: %t",
|
||||
item.Name, *item.Subclass, classType, isPhysicalWeapon)
|
||||
}
|
||||
|
||||
if isPhysicalWeapon {
|
||||
stm.applyPhysicalWeaponTemplate(item, baseStatValue, isTankWeapon)
|
||||
} else {
|
||||
stm.applyCasterWeaponTemplate(item, baseStatValue, isTankWeapon)
|
||||
}
|
||||
}
|
||||
|
||||
// isPhysicalWeapon determines if a weapon should use physical stats
|
||||
func (stm *StatTemplateManager) isPhysicalWeapon(subclass, classType int) bool {
|
||||
// Physical weapon subclasses
|
||||
physicalSubclasses := []int{0, 1, 2, 3, 4, 5, 6, 7, 8, 13, 15, 16, 17, 18}
|
||||
for _, sc := range physicalSubclasses {
|
||||
if subclass == sc {
|
||||
// Special case: daggers can be physical or caster
|
||||
if subclass == 15 { // Dagger
|
||||
// If classType is generic (7), assume physical for daggers
|
||||
return classType == 7 || classType == 1 || classType == 2
|
||||
}
|
||||
return true
|
||||
}
|
||||
}
|
||||
|
||||
// Caster weapon subclasses
|
||||
casterSubclasses := []int{10, 19, 20} // Staff, Wand, Fishing Pole
|
||||
for _, sc := range casterSubclasses {
|
||||
if subclass == sc {
|
||||
return false
|
||||
}
|
||||
}
|
||||
|
||||
return false // Default to caster if unknown
|
||||
}
|
||||
|
||||
// applyPhysicalWeaponTemplate applies physical DPS weapon stats
|
||||
func (stm *StatTemplateManager) applyPhysicalWeaponTemplate(item *Item, baseStatValue int, isTankWeapon bool) {
|
||||
statSlot := 1
|
||||
|
||||
// Primary stat (ALWAYS present) - choose based on weapon type
|
||||
primaryStat := 3 // Agility default
|
||||
|
||||
// Weapon-specific stat assignment
|
||||
if *item.Subclass == 15 { // Dagger - ALWAYS Agility
|
||||
primaryStat = 3 // Agility
|
||||
} else if *item.Subclass == 0 || *item.Subclass == 1 || *item.Subclass == 8 { // Axe, Sword, Two-handed Sword
|
||||
// These can be Strength or Agility, with slight preference for Strength
|
||||
if rand.Intn(4) < 3 { // 75% chance for Strength
|
||||
primaryStat = 4 // Strength
|
||||
} else {
|
||||
primaryStat = 3 // Agility
|
||||
}
|
||||
} else if *item.Subclass == 2 || *item.Subclass == 3 || *item.Subclass == 18 { // Bow, Gun, Crossbow
|
||||
primaryStat = 3 // Agility (ranged weapons)
|
||||
} else {
|
||||
// Other weapons - random choice
|
||||
if rand.Intn(2) == 0 {
|
||||
primaryStat = 3 // Agility
|
||||
} else {
|
||||
primaryStat = 4 // Strength
|
||||
}
|
||||
}
|
||||
|
||||
*item.StatType1 = primaryStat
|
||||
*item.StatValue1 = baseStatValue + 3 + rand.Intn(2) // 3-4 bonus, consistent
|
||||
statSlot++
|
||||
|
||||
// Attack Power (ALWAYS present for physical weapons)
|
||||
*item.StatType2 = 38 // Attack Power
|
||||
*item.StatValue2 = baseStatValue*4 + rand.Intn(2) // Consistent high value with small variance
|
||||
statSlot++
|
||||
|
||||
// Secondary stats (VARY these) - choose 1-3 randomly
|
||||
availableSecondaries := []int{32, 36, 31, 44} // Crit, Haste, Hit, Armor Pen
|
||||
stm.addRandomSecondaryStats(item, availableSecondaries, baseStatValue, &statSlot, 1+rand.Intn(3))
|
||||
|
||||
// Only add stamina for tank weapons
|
||||
if isTankWeapon && statSlot <= 5 {
|
||||
item.UpdateField(fmt.Sprintf("StatType%d", statSlot), 7) // Stamina
|
||||
item.UpdateField(fmt.Sprintf("StatValue%d", statSlot), baseStatValue+8+rand.Intn(3)) // 8-10 bonus
|
||||
}
|
||||
}
|
||||
|
||||
// applyCasterWeaponTemplate applies caster weapon stats
|
||||
func (stm *StatTemplateManager) applyCasterWeaponTemplate(item *Item, baseStatValue int, isTankWeapon bool) {
|
||||
statSlot := 1
|
||||
|
||||
// Intellect (ALWAYS present for casters)
|
||||
*item.StatType1 = 5 // Intellect
|
||||
*item.StatValue1 = baseStatValue + 3 + rand.Intn(2) // 3-4 bonus, consistent
|
||||
statSlot++
|
||||
|
||||
// Spell Power (ALWAYS present for caster weapons)
|
||||
*item.StatType2 = 45 // Spell Power
|
||||
*item.StatValue2 = baseStatValue*3 + rand.Intn(2) // Consistent high value with small variance
|
||||
statSlot++
|
||||
|
||||
// Secondary stats (VARY these) - choose 1-3 randomly
|
||||
availableSecondaries := []int{32, 36, 31, 43, 6} // Crit, Haste, Hit, MP5, Spirit
|
||||
stm.addRandomSecondaryStats(item, availableSecondaries, baseStatValue, &statSlot, 1+rand.Intn(3))
|
||||
|
||||
// Only add stamina for tank weapons (rare for casters)
|
||||
if isTankWeapon && statSlot <= 5 {
|
||||
item.UpdateField(fmt.Sprintf("StatType%d", statSlot), 7) // Stamina
|
||||
item.UpdateField(fmt.Sprintf("StatValue%d", statSlot), baseStatValue+8+rand.Intn(3)) // 8-10 bonus
|
||||
}
|
||||
}
|
||||
|
||||
// applyArmorTemplate applies armor-specific stat templates
|
||||
func (stm *StatTemplateManager) applyArmorTemplate(item *Item, baseStatValue int) {
|
||||
if *item.Subclass == 0 { // Trinkets
|
||||
stm.applyTrinketTemplate(item, baseStatValue)
|
||||
} else {
|
||||
stm.applyGenericArmorTemplate(item, baseStatValue)
|
||||
}
|
||||
}
|
||||
|
||||
// applyTrinketTemplate applies trinket stats (minimal stats, power from spells)
|
||||
func (stm *StatTemplateManager) applyTrinketTemplate(item *Item, baseStatValue int) {
|
||||
*item.StatType1 = 7 // Stamina
|
||||
*item.StatValue1 = baseStatValue + 3 + rand.Intn(3) // 3-5 bonus with variance
|
||||
}
|
||||
|
||||
// applyGenericArmorTemplate applies generic armor stats
|
||||
func (stm *StatTemplateManager) applyGenericArmorTemplate(item *Item, baseStatValue int) {
|
||||
classType := item.GetClassUserType()
|
||||
statSlot := 1
|
||||
|
||||
// Stamina (ALWAYS present on armor)
|
||||
*item.StatType1 = 7 // Stamina
|
||||
*item.StatValue1 = baseStatValue + 4 + rand.Intn(2) // 4-5 bonus, consistent
|
||||
statSlot++
|
||||
|
||||
// Primary stat (ALWAYS present) based on class type
|
||||
primaryStat := 5 // Default to Intellect
|
||||
if classType == 1 { // Strength
|
||||
primaryStat = 4 // Strength
|
||||
} else if classType == 2 { // Agility
|
||||
primaryStat = 3 // Agility
|
||||
} else if classType == 7 { // Generic/Unknown - random choice
|
||||
primaryStats := []int{3, 4, 5} // Agi, Str, Int
|
||||
primaryStat = primaryStats[rand.Intn(len(primaryStats))]
|
||||
}
|
||||
// classType 3,4,5,6 (casters) get Intellect by default
|
||||
|
||||
*item.StatType2 = primaryStat
|
||||
*item.StatValue2 = baseStatValue + 2 + rand.Intn(2) // 2-3 bonus, consistent
|
||||
statSlot++
|
||||
|
||||
// Secondary stats (VARY these) - choose 0-2 randomly
|
||||
availableSecondaries := []int{32, 36, 31, 6} // Crit, Haste, Hit, Spirit
|
||||
stm.addRandomSecondaryStats(item, availableSecondaries, baseStatValue-3, &statSlot, rand.Intn(3))
|
||||
}
|
||||
|
||||
// addRandomSecondaryStats adds random secondary stats to an item
|
||||
func (stm *StatTemplateManager) addRandomSecondaryStats(item *Item, availableStats []int, baseValue int, statSlot *int, count int) {
|
||||
// Shuffle available stats
|
||||
rand.Shuffle(len(availableStats), func(i, j int) {
|
||||
availableStats[i], availableStats[j] = availableStats[j], availableStats[i]
|
||||
})
|
||||
|
||||
// Add the specified number of secondary stats
|
||||
for i := 0; i < count && i < len(availableStats) && *statSlot <= 5; i++ {
|
||||
item.UpdateField(fmt.Sprintf("StatType%d", *statSlot), availableStats[i])
|
||||
item.UpdateField(fmt.Sprintf("StatValue%d", *statSlot), baseValue+rand.Intn(4)) // 0 to +3 variance
|
||||
(*statSlot)++
|
||||
}
|
||||
}
|
||||
|
||||
// updateStatsCount updates the StatsCount field based on non-zero stats
|
||||
func (stm *StatTemplateManager) updateStatsCount(item *Item) {
|
||||
statsCount := 0
|
||||
for i := 1; i <= 10; i++ {
|
||||
statType, _ := item.GetField(fmt.Sprintf("StatType%d", i))
|
||||
if statType > 0 {
|
||||
statsCount++
|
||||
}
|
||||
}
|
||||
*item.StatsCount = statsCount
|
||||
}
|
||||
877
internal/spells/spells.go
Normal file
877
internal/spells/spells.go
Normal file
@@ -0,0 +1,877 @@
|
||||
package spells
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"log"
|
||||
"math"
|
||||
"strings"
|
||||
|
||||
"github.com/araxiaonline/endgame-item-generator/internal/config"
|
||||
"github.com/araxiaonline/endgame-item-generator/internal/db/mysql"
|
||||
"github.com/thoas/go-funk"
|
||||
)
|
||||
|
||||
// list of spell effects that require scaling
|
||||
var SpellEffects = [...]int{
|
||||
2, // School Damage
|
||||
6, // AppyAura
|
||||
9, // HealthLeech
|
||||
10, // Heal
|
||||
30, // Restores Mana
|
||||
35, // Apply Area Aura
|
||||
}
|
||||
|
||||
// list of spell aura effects that require scaling
|
||||
var SpellAuraEffects = [...]int{
|
||||
3, // DOT
|
||||
8, // HOT
|
||||
13, // Modifies Spell Damage Done
|
||||
15, // Modifies Damage Shield
|
||||
22, // Modifies Resistance
|
||||
29, // Modifies Strength
|
||||
34, // Modifies HEalth
|
||||
85, // Modifies Mana Regen
|
||||
99, // Modifies Attack Power
|
||||
124, // Modifies Range Attack Power
|
||||
135, // Modifies Healing Done
|
||||
189, // Modifies Critical Strike
|
||||
}
|
||||
|
||||
// Mapping of spell aura effects to stat types they modify
|
||||
var AuraEffectsStatMap = map[int]int{
|
||||
8: 46,
|
||||
13: 45,
|
||||
29: 4,
|
||||
85: 43,
|
||||
99: 38,
|
||||
124: 38,
|
||||
135: 45,
|
||||
}
|
||||
|
||||
// Usually in EffectMiscValueA to describe what the Aura modifies
|
||||
var SpellModifiers = [...]int{
|
||||
0, // damage
|
||||
1, // duration
|
||||
2, // threat
|
||||
3, // effect1
|
||||
4, // charges
|
||||
5, // range
|
||||
6, // radius
|
||||
7, // crit chance
|
||||
8, // all effects
|
||||
9, // No pushback
|
||||
10, // Cast Time
|
||||
11, // CD
|
||||
12, // effect2
|
||||
13, // ignore armor
|
||||
14, // cost
|
||||
15, // crit damage bonus
|
||||
16, // resist miss chance
|
||||
17, // jump targets
|
||||
18, // Chance of success
|
||||
19, // Amplitude
|
||||
20, // Dmg multiplier
|
||||
21, // GCD
|
||||
22, // DoT
|
||||
23, // effect3
|
||||
24, // bonus multiplier
|
||||
26, // PPM
|
||||
27, // value multiplier
|
||||
28, // resist dispel chance
|
||||
29, // crit damage bonus 2
|
||||
}
|
||||
|
||||
// result of a stat conversion from spell to raw stats on item
|
||||
type ConvItemStat struct {
|
||||
StatType int
|
||||
StatValue int
|
||||
Budget int
|
||||
}
|
||||
|
||||
// Spell Effect with max value for effect storage
|
||||
type SpellEffect struct {
|
||||
Effect int
|
||||
BasePoints int
|
||||
DieSides int
|
||||
CalculatedMax int
|
||||
}
|
||||
|
||||
type Spell struct {
|
||||
mysql.DbSpell
|
||||
Scaled bool
|
||||
ItemSpellSlot int
|
||||
}
|
||||
|
||||
func calcMaxValue(base int, sides int) int {
|
||||
if base < 0 {
|
||||
return base - sides
|
||||
}
|
||||
|
||||
return base + sides
|
||||
}
|
||||
|
||||
// get a List of the spell effects (not auras) that need to be scaled
|
||||
func (s Spell) GetSpellEffects() []SpellEffect {
|
||||
effects := make([]SpellEffect, 0)
|
||||
|
||||
effects = append(effects, SpellEffect{
|
||||
Effect: s.Effect1,
|
||||
BasePoints: s.EffectBasePoints1,
|
||||
DieSides: s.EffectDieSides1,
|
||||
CalculatedMax: calcMaxValue(s.EffectBasePoints1, s.EffectDieSides1),
|
||||
})
|
||||
|
||||
effects = append(effects, SpellEffect{
|
||||
Effect: s.Effect2,
|
||||
BasePoints: s.EffectBasePoints2,
|
||||
DieSides: s.EffectDieSides2,
|
||||
CalculatedMax: calcMaxValue(s.EffectBasePoints2, s.EffectDieSides2),
|
||||
})
|
||||
|
||||
effects = append(effects, SpellEffect{
|
||||
Effect: s.Effect3,
|
||||
BasePoints: s.EffectBasePoints3,
|
||||
DieSides: s.EffectDieSides3,
|
||||
CalculatedMax: calcMaxValue(s.EffectBasePoints3, s.EffectDieSides3),
|
||||
})
|
||||
|
||||
return effects
|
||||
}
|
||||
|
||||
// Get he effects and calculate the max value for the a
|
||||
func (s Spell) GetAuraEffects() []SpellEffect {
|
||||
effects := make([]SpellEffect, 0)
|
||||
|
||||
effects = append(effects, SpellEffect{
|
||||
Effect: s.EffectAura1,
|
||||
BasePoints: s.EffectBasePoints1,
|
||||
DieSides: s.EffectDieSides1,
|
||||
CalculatedMax: calcMaxValue(s.EffectBasePoints1, s.EffectDieSides1),
|
||||
})
|
||||
|
||||
effects = append(effects, SpellEffect{
|
||||
Effect: s.EffectAura2,
|
||||
BasePoints: s.EffectBasePoints2,
|
||||
DieSides: s.EffectDieSides2,
|
||||
CalculatedMax: calcMaxValue(s.EffectBasePoints2, s.EffectDieSides2),
|
||||
})
|
||||
|
||||
effects = append(effects, SpellEffect{
|
||||
Effect: s.EffectAura3,
|
||||
BasePoints: s.EffectBasePoints3,
|
||||
DieSides: s.EffectDieSides3,
|
||||
CalculatedMax: calcMaxValue(s.EffectBasePoints3, s.EffectDieSides3),
|
||||
})
|
||||
|
||||
return effects
|
||||
}
|
||||
|
||||
// this spell effect has stats or effects that need to be scaled
|
||||
func (s Spell) SpellEffectsNeedsScaled() bool {
|
||||
if s.Effect1 == 0 {
|
||||
return false
|
||||
}
|
||||
|
||||
needsScaled := false
|
||||
effects := s.GetSpellEffects()
|
||||
for _, e := range effects {
|
||||
|
||||
if !funk.Contains(SpellEffects, e.Effect) || e.Effect == 6 {
|
||||
continue
|
||||
}
|
||||
needsScaled = true
|
||||
}
|
||||
|
||||
return needsScaled
|
||||
}
|
||||
|
||||
// this aura effect has stats or effects that need to be scaled
|
||||
func (s Spell) AuraEffectNeedsScaled() bool {
|
||||
if s.EffectAura1 == 0 {
|
||||
return false
|
||||
}
|
||||
|
||||
for _, effect := range SpellAuraEffects {
|
||||
if s.EffectAura1 == effect || s.EffectAura2 == effect || s.EffectAura3 == effect {
|
||||
return true
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
func (s Spell) HasAuraEffect() bool {
|
||||
return s.EffectAura1 != 0 || s.EffectAura2 != 0 || s.EffectAura3 != 0
|
||||
}
|
||||
|
||||
func AuraEffectCanBeConv(effect int) bool {
|
||||
return funk.Contains(SpellAuraEffects, effect)
|
||||
}
|
||||
|
||||
// Lookup details about the effect and return the stat type -1 indicates not found
|
||||
func convertAuraEffect(effect int) int {
|
||||
if !funk.Contains(AuraEffectsStatMap, effect) {
|
||||
// log.Printf("effect %v not found in SpellEffectStatMap skipping", effect)
|
||||
return -1
|
||||
}
|
||||
|
||||
return AuraEffectsStatMap[effect]
|
||||
}
|
||||
|
||||
// Converts spell buffs to item stats making it easier to convert and normalize
|
||||
func (s Spell) ConvertToStats() ([]ConvItemStat, error) {
|
||||
stats := []ConvItemStat{}
|
||||
|
||||
if s.Effect1 == 0 && s.EffectAura1 == 0 {
|
||||
return stats, fmt.Errorf("spell does not have an effect1 or auraEffect1")
|
||||
}
|
||||
|
||||
effects := s.GetAuraEffects()
|
||||
|
||||
if s.ID == 9397 {
|
||||
log.Printf("Spell: %v AuraEffect1: %v AuraEffect2: %v AuraEffect3: %v", s.Name, s.EffectAura1, s.EffectAura2, s.EffectAura3)
|
||||
}
|
||||
|
||||
var seen []int
|
||||
for _, e := range effects {
|
||||
if !AuraEffectCanBeConv(e.Effect) {
|
||||
continue
|
||||
}
|
||||
|
||||
statId := convertAuraEffect(e.Effect)
|
||||
if statId == -1 {
|
||||
continue
|
||||
}
|
||||
|
||||
if funk.Contains(seen, statId) {
|
||||
continue
|
||||
}
|
||||
|
||||
// keep track if we have already seen this stat so we do not duplicate
|
||||
// Wotlk changed everything to spell power so might as well do the same in
|
||||
// scaling process.
|
||||
seen = append(seen, statId)
|
||||
statMod := float64(config.StatModifiers[statId])
|
||||
stats = append(stats, ConvItemStat{
|
||||
StatType: statId,
|
||||
StatValue: e.CalculatedMax,
|
||||
Budget: int(math.Abs(math.Ceil(float64(e.CalculatedMax) * statMod))),
|
||||
})
|
||||
}
|
||||
|
||||
// Handle special stat case where 189 is catch all for crit, dodge, parry, hit, haste, expertise
|
||||
if s.Effect1 != 0 && s.Effect1 == 6 && (s.EffectAura1 == 189 || s.EffectAura1 == 123) {
|
||||
// log.Printf("Special case for spell aura effect: %v", s.Description)
|
||||
statId := parseStatDesc(s.Description)
|
||||
// if statId == 0 {
|
||||
// // log.Printf("Could not determine stat for spell aura effect description: %v", s.Name)
|
||||
// }
|
||||
|
||||
calced := calcMaxValue(s.EffectBasePoints1, s.EffectDieSides1)
|
||||
// log.Printf("StatId: %v Calced: %v", statId, calced)
|
||||
stats = append(stats, ConvItemStat{
|
||||
StatType: statId,
|
||||
StatValue: calced,
|
||||
Budget: int(math.Abs(math.Ceil(float64(calced) * float64(config.StatModifiers[statId])))),
|
||||
})
|
||||
}
|
||||
|
||||
// if len(stats) == 0 {
|
||||
// // log.Printf("Failed to Convert Spell to Stats: %v AuraEffect1: %v AuraEffect2: %v AuraEffect3: %v", s.Name, s.EffectAura1, s.EffectAura2, s.EffectAura3)
|
||||
// } else {
|
||||
// // log.Printf("Converted Spell to Stats: %v AuraEffect1: %v AuraEffect2: %v AuraEffect3: %v", s.Name, s.EffectAura1, s.EffectAura2, s.EffectAura3)
|
||||
// }
|
||||
|
||||
return stats, nil
|
||||
}
|
||||
|
||||
// This spell can be converted fully into a stat and not needed on the item
|
||||
func (s Spell) CanBeConverted() bool {
|
||||
|
||||
// if there are any spell effects that are not aura effects, then it can be converted
|
||||
effects := s.GetSpellEffects()
|
||||
for _, e := range effects {
|
||||
if e.Effect != 0 && e.Effect != 6 {
|
||||
return false
|
||||
}
|
||||
}
|
||||
|
||||
// Unfortunately if there are any mixed effects for auras, it is too difficult to split those so just
|
||||
// bail out
|
||||
auras := s.GetAuraEffects()
|
||||
auraFlag := false
|
||||
for _, a := range auras {
|
||||
if a.Effect == 0 {
|
||||
continue
|
||||
}
|
||||
|
||||
if AuraEffectCanBeConv(a.Effect) {
|
||||
return true
|
||||
}
|
||||
}
|
||||
|
||||
return auraFlag
|
||||
}
|
||||
|
||||
// based on the description determine the stat to
|
||||
func parseStatDesc(desc string) int {
|
||||
if strings.Contains(desc, "critical strike") {
|
||||
return 32
|
||||
}
|
||||
|
||||
if strings.Contains(desc, "dodge") {
|
||||
return 13
|
||||
}
|
||||
|
||||
if strings.Contains(desc, "parry") {
|
||||
return 14
|
||||
}
|
||||
|
||||
if strings.Contains(desc, "hit rating") {
|
||||
return 31
|
||||
}
|
||||
|
||||
if strings.Contains(desc, "haste rating") {
|
||||
return 36
|
||||
}
|
||||
|
||||
if strings.Contains(desc, "expertise rating") {
|
||||
return 37
|
||||
}
|
||||
|
||||
if strings.Contains(desc, "defense rating") {
|
||||
return 12
|
||||
}
|
||||
|
||||
if strings.Contains(desc, "block rating") {
|
||||
return 15
|
||||
}
|
||||
|
||||
if strings.Contains(desc, "armor penetration") {
|
||||
return 44
|
||||
}
|
||||
|
||||
if strings.Contains(desc, "spell penetration") {
|
||||
return 47
|
||||
}
|
||||
|
||||
return 0
|
||||
}
|
||||
|
||||
// Scales a spell effect, means creating a new spell with the same effect but scaled to a new item level, then passing
|
||||
// back the new spellId, In order to be predictable I will use 30000000 for rare, 31000000 for epic, 32000000 for legendary
|
||||
// An example of this might on hit do $s1 nature damage over $d seconds. We would just scale the $s1 value
|
||||
// based on the formula below. This assumes that Blizzard has already balanced the spell bonus against the
|
||||
// stats on the item level and quality. This is a big assumption as the stats are not penalized
|
||||
// from having the extra damage. This could really create some unique sought after weapons that exploit this.
|
||||
// modified ratio ((s1 / existing iLevel) * newIlevel) * (0.20 Rare or 0.30 Epic or 0.4 for Legendary).
|
||||
func (s *Spell) ScaleSpell(fromItemLevel int, itemLevel int, itemQuality int) (int, error) {
|
||||
s.Scaled = false
|
||||
qualModifier := map[int]float64{
|
||||
3: 1.20,
|
||||
4: 1.30,
|
||||
5: 1.40,
|
||||
}
|
||||
|
||||
idBump := 30000000
|
||||
if itemQuality == 4 {
|
||||
idBump = 31000000
|
||||
}
|
||||
if itemQuality == 5 {
|
||||
idBump = 32000000
|
||||
}
|
||||
|
||||
// direct damage types
|
||||
dd := [...]int{2, 9, 10}
|
||||
|
||||
didScale := false
|
||||
// Causes direct damage
|
||||
if s.Effect1 != 0 && funk.Contains(dd, s.Effect1) {
|
||||
s.EffectBasePoints1 = int(float64(s.EffectBasePoints1) / float64(fromItemLevel) * float64(itemLevel) * qualModifier[itemQuality] * 2.5)
|
||||
didScale = true
|
||||
}
|
||||
if s.Effect2 != 0 && funk.Contains(dd, s.Effect1) {
|
||||
s.EffectBasePoints2 = int(float64(s.EffectBasePoints2) / float64(fromItemLevel) * float64(itemLevel) * qualModifier[itemQuality] * 2.5)
|
||||
didScale = true
|
||||
}
|
||||
|
||||
// Restores a Power / Mana
|
||||
if s.Effect1 != 0 && s.Effect1 == 30 {
|
||||
// skip anyhing else that is not mana as they are flat values
|
||||
if strings.Contains(s.Description, "Mana") || strings.Contains(s.Description, "mana") {
|
||||
s.EffectBasePoints1 = int(float64(s.EffectBasePoints1) / float64(fromItemLevel) * float64(itemLevel) * qualModifier[itemQuality])
|
||||
didScale = true
|
||||
}
|
||||
}
|
||||
|
||||
// Scales a stat buff
|
||||
if s.Effect1 != 0 && s.Effect1 == 35 {
|
||||
s.EffectBasePoints1 = int(float64(s.EffectBasePoints1) / float64(fromItemLevel) * float64(itemLevel) * qualModifier[itemQuality])
|
||||
didScale = true
|
||||
}
|
||||
if s.Effect1 != 0 && s.Effect2 == 35 {
|
||||
s.EffectBasePoints2 = int(float64(s.EffectBasePoints2) / float64(fromItemLevel) * float64(itemLevel) * qualModifier[itemQuality])
|
||||
didScale = true
|
||||
}
|
||||
|
||||
// Handle special aura effects
|
||||
if s.EffectAura1 != 0 && s.EffectAura1 == 3 && s.Effect1 == 6 {
|
||||
s.EffectBasePoints1 = int(float64(s.EffectBasePoints1) / float64(fromItemLevel) * float64(itemLevel) * qualModifier[itemQuality] * 2)
|
||||
didScale = true
|
||||
}
|
||||
|
||||
// Damage Shield Increase Scale due to HP curve
|
||||
if s.EffectAura1 != 0 && s.EffectAura1 == 15 && s.Effect1 == 6 {
|
||||
s.EffectBasePoints1 = int(float64(s.EffectBasePoints1) / float64(fromItemLevel) * float64(itemLevel) * qualModifier[itemQuality] * 1.50)
|
||||
didScale = true
|
||||
}
|
||||
|
||||
if !didScale {
|
||||
return 0, fmt.Errorf("did not qualify to be scaled in ScaleSpell %v (%v)", s.Name, s.ID)
|
||||
}
|
||||
s.Scaled = true
|
||||
return idBump + s.ID, nil
|
||||
}
|
||||
|
||||
// ForceScaleSpell is an enhanced version of ScaleSpell that scales ANY spell regardless of effect type.
|
||||
// It applies quality modifiers and special handling for different effect types, using a progression-based
|
||||
// scaling curve with diminishing returns for large item level differences.
|
||||
// The tier parameter (1-5) applies an additional modifier from GearTierModifiers plus a 5% bonus.
|
||||
// Also updates spell names to reflect new values when applicable.
|
||||
func (s *Spell) ForceScaleSpell(fromItemLevel int, toItemLevel int, itemQuality int, tier ...int) error {
|
||||
// Store original base point values before scaling
|
||||
// Add 1 to each value to account for the way WoW stores spell effect values
|
||||
// (the displayed value is often BasePoints+1)
|
||||
originalBasePoints1 := s.EffectBasePoints1 + 1
|
||||
originalBasePoints2 := s.EffectBasePoints2 + 1
|
||||
originalBasePoints3 := s.EffectBasePoints3 + 1
|
||||
// Get quality modifier from config package
|
||||
qualModifier, exists := config.QualityModifiers[itemQuality]
|
||||
if !exists {
|
||||
// Default to 1.0 if quality not found
|
||||
qualModifier = 1.0
|
||||
}
|
||||
|
||||
if itemQuality == 5 {
|
||||
qualModifier = 1.2 // Legendary
|
||||
} else {
|
||||
qualModifier = 1.0
|
||||
}
|
||||
tierModifier := 1.00
|
||||
|
||||
// Apply tier modifier if provided
|
||||
if len(tier) > 0 && tier[0] >= 1 && tier[0] <= 5 {
|
||||
// Get the tier modifier from config
|
||||
if mod, exists := config.GearTierModifiers[tier[0]]; exists {
|
||||
tierModifier *= mod // Apply tier modifier on top of base 5% bonus
|
||||
}
|
||||
}
|
||||
|
||||
// Apply tier modifier to quality modifier
|
||||
qualModifier *= tierModifier
|
||||
|
||||
// Calculate item level difference and ratio
|
||||
ilevelDiff := toItemLevel - fromItemLevel
|
||||
|
||||
// Use a simple linear scaling based on item level ratio
|
||||
// This provides a straightforward and predictable scaling that's easy to understand
|
||||
levelRatio := float64(toItemLevel) / float64(fromItemLevel)
|
||||
|
||||
// Effect type categorization
|
||||
directDamageEffects := [...]int{2, 9, 10} // School damage, % weapon damage, etc.
|
||||
statBuffEffects := [...]int{35, 29, 99, 124} // Apply stat, add flat stat, etc.
|
||||
periodEffects := [...]int{6, 77} // Apply aura, periodic trigger
|
||||
|
||||
// Scale Effect1
|
||||
if s.EffectBasePoints1 != 0 {
|
||||
// Skip scaling for percentage-based effects (buffs/debuffs)
|
||||
// Look for percentage indicators in spell description
|
||||
skipScaling := strings.Contains(s.Description, "$s1%") ||
|
||||
strings.Contains(s.Description, "$s1\\%") ||
|
||||
strings.Contains(s.Description, "by $s1%") ||
|
||||
// Common percentage-based aura effects that should not scale
|
||||
(s.EffectAura1 != 0 && (
|
||||
s.EffectAura1 == 33 || // Modify Movement Speed
|
||||
s.EffectAura1 == 31 || // Modify Stat (percentage)
|
||||
s.EffectAura1 == 52 || // Modify Damage Done (percentage)
|
||||
s.EffectAura1 == 79 || // Modify Resistance (percentage)
|
||||
s.EffectAura1 == 137)) // Modify Total Stat Percentage
|
||||
|
||||
if !skipScaling {
|
||||
effectMultiplier := 1.0
|
||||
|
||||
// Check for attack power and spell power in the description regardless of effect type
|
||||
if strings.Contains(s.Description, "attack power") ||
|
||||
strings.Contains(s.Description, "Attack Power") ||
|
||||
strings.Contains(s.Description, "spell power") ||
|
||||
strings.Contains(s.Description, "Spell Power") ||
|
||||
strings.Contains(s.Description, "healing") ||
|
||||
strings.Contains(s.Description, "Healing") {
|
||||
effectMultiplier = 2.0 // Higher multiplier for attack/spell power
|
||||
}
|
||||
|
||||
// Determine effect category and apply appropriate multiplier
|
||||
if s.Effect1 != 0 {
|
||||
// Direct damage effects scale more aggressively at higher item levels
|
||||
if funk.Contains(directDamageEffects, s.Effect1) {
|
||||
effectMultiplier = 2.5 + (float64(toItemLevel) * 0.1 * 0.005) // +0.5% per every 10 item levels
|
||||
}
|
||||
|
||||
// Flat Base Stat modifier for all other stats.
|
||||
if funk.Contains(statBuffEffects, s.Effect1) && effectMultiplier < 1.5 {
|
||||
effectMultiplier = 1.45
|
||||
}
|
||||
}
|
||||
|
||||
// Special handling for aura effects
|
||||
if s.EffectAura1 != 0 {
|
||||
// DOT effects (Aura 3: Periodic Damage)
|
||||
if s.EffectAura1 == 3 && funk.Contains(periodEffects, s.Effect1) {
|
||||
effectMultiplier = 2.5 + (float64(toItemLevel) * 0.1 * 0.005)
|
||||
|
||||
// Scale DOTs more with higher quality items
|
||||
if itemQuality >= 5 { // Legendary or higher
|
||||
effectMultiplier += 0.5
|
||||
}
|
||||
}
|
||||
|
||||
// HOT effects (Aura 8: Periodic Heal)
|
||||
if s.EffectAura1 == 8 && funk.Contains(periodEffects, s.Effect1) {
|
||||
effectMultiplier = 2.5 + (float64(toItemLevel) * 0.1 * 0.005)
|
||||
// Healing scales slightly higher than damage
|
||||
}
|
||||
|
||||
// Damage Shield effects (Aura 15)
|
||||
if s.EffectAura1 == 15 && funk.Contains(periodEffects, s.Effect1) {
|
||||
// Damage shields scale with item level difference
|
||||
effectMultiplier = 1.5 + (float64(toItemLevel) * 0.1 * 0.005)
|
||||
if effectMultiplier > 2.5 {
|
||||
effectMultiplier = 2.5 // Cap at 2.5x
|
||||
}
|
||||
}
|
||||
|
||||
// Proc chance effects (various auras)
|
||||
if s.ProcChance > 0 && s.ProcChance < 100 {
|
||||
// For proc effects, we might want to scale the effect more aggressively
|
||||
// since they don't happen all the time
|
||||
procFactor := 100.0 / float64(s.ProcChance) // Inverse of proc chance
|
||||
// Limit the proc factor to avoid excessive scaling
|
||||
if procFactor > 2.0 {
|
||||
procFactor = 2.0
|
||||
}
|
||||
effectMultiplier += math.Sqrt(procFactor) // Scale by square root of proc factor
|
||||
}
|
||||
}
|
||||
|
||||
// Special handling for mana restoration
|
||||
if s.Effect1 == 30 {
|
||||
if strings.Contains(s.Description, "Mana") || strings.Contains(s.Description, "mana") {
|
||||
// Mana effects scale with level but with diminishing returns
|
||||
effectMultiplier = 1.0 + (math.Log10(float64(ilevelDiff+1)) * 0.3)
|
||||
}
|
||||
}
|
||||
// Apply the scaling with the appropriate multiplier
|
||||
s.EffectBasePoints1 = int(float64(s.EffectBasePoints1) * levelRatio * qualModifier * effectMultiplier)
|
||||
}
|
||||
}
|
||||
|
||||
// Scale Effect2 with similar logic
|
||||
if s.EffectBasePoints2 != 0 {
|
||||
effectMultiplier := 1.0
|
||||
|
||||
// Check for attack power and spell power in the description regardless of effect type
|
||||
if strings.Contains(s.Description, "attack power") ||
|
||||
strings.Contains(s.Description, "Attack Power") ||
|
||||
strings.Contains(s.Description, "spell power") ||
|
||||
strings.Contains(s.Description, "Spell Power") ||
|
||||
strings.Contains(s.Description, "healing") ||
|
||||
strings.Contains(s.Description, "Healing") {
|
||||
effectMultiplier = 2.0 // Higher multiplier for attack/spell power
|
||||
}
|
||||
|
||||
// Determine effect category and apply appropriate multiplier
|
||||
if s.Effect2 != 0 {
|
||||
// Direct damage effects scale more aggressively at higher item levels
|
||||
if funk.Contains(directDamageEffects, s.Effect2) {
|
||||
// Scale damage more aggressively for higher item levels
|
||||
effectMultiplier = 2.5 + (float64(toItemLevel) * 0.1 * 0.005) // +0.5% per every 10 item levels
|
||||
}
|
||||
|
||||
// Flat Base Stat modifier for all other stats.
|
||||
if funk.Contains(statBuffEffects, s.Effect2) && effectMultiplier < 1.5 {
|
||||
effectMultiplier = 1.45
|
||||
}
|
||||
}
|
||||
|
||||
// Special handling for aura effects
|
||||
if s.EffectAura2 != 0 {
|
||||
// DOT effects (Aura 3: Periodic Damage)
|
||||
if s.EffectAura2 == 3 && funk.Contains(periodEffects, s.Effect2) {
|
||||
effectMultiplier = 2.5 + (float64(toItemLevel) * 0.1 * 0.005)
|
||||
|
||||
// Scale DOTs more with higher quality items
|
||||
if itemQuality >= 5 { // Legendary or higher
|
||||
effectMultiplier += 0.5
|
||||
}
|
||||
}
|
||||
|
||||
// HOT effects (Aura 8: Periodic Heal)
|
||||
if s.EffectAura2 == 8 && funk.Contains(periodEffects, s.Effect2) {
|
||||
effectMultiplier = 2.5 + (float64(toItemLevel) * 0.1 * 0.005)
|
||||
// Healing scales slightly higher than damage
|
||||
}
|
||||
|
||||
// Damage Shield effects (Aura 15)
|
||||
if s.EffectAura2 == 15 && funk.Contains(periodEffects, s.Effect2) {
|
||||
// Damage shields scale with item level difference
|
||||
effectMultiplier = 1.5 + (float64(toItemLevel) * 0.1 * 0.005)
|
||||
if effectMultiplier > 2.5 {
|
||||
effectMultiplier = 2.5 // Cap at 2.5x
|
||||
}
|
||||
}
|
||||
|
||||
// Proc chance effects (various auras)
|
||||
if s.ProcChance > 0 && s.ProcChance < 100 {
|
||||
// For proc effects, we might want to scale the effect more aggressively
|
||||
// since they don't happen all the time
|
||||
procFactor := 100.0 / float64(s.ProcChance) // Inverse of proc chance
|
||||
// Limit the proc factor to avoid excessive scaling
|
||||
if procFactor > 2.0 {
|
||||
procFactor = 2.0
|
||||
}
|
||||
effectMultiplier += math.Sqrt(procFactor) // Scale by square root of proc factor
|
||||
}
|
||||
}
|
||||
|
||||
// Special handling for mana restoration
|
||||
if s.Effect2 == 30 {
|
||||
if strings.Contains(s.Description, "Mana") || strings.Contains(s.Description, "mana") {
|
||||
// Mana effects scale with level but with diminishing returns
|
||||
effectMultiplier = 1.0 + (math.Log10(float64(ilevelDiff+1)) * 0.3)
|
||||
}
|
||||
}
|
||||
// Apply the scaling with the appropriate multiplier
|
||||
s.EffectBasePoints2 = int(float64(s.EffectBasePoints2) * levelRatio * qualModifier * effectMultiplier)
|
||||
}
|
||||
|
||||
// Scale Effect3 with similar logic
|
||||
if s.EffectBasePoints3 != 0 {
|
||||
effectMultiplier := 1.0
|
||||
|
||||
// Check for attack power and spell power in the description regardless of effect type
|
||||
if strings.Contains(s.Description, "attack power") ||
|
||||
strings.Contains(s.Description, "Attack Power") ||
|
||||
strings.Contains(s.Description, "spell power") ||
|
||||
strings.Contains(s.Description, "Spell Power") ||
|
||||
strings.Contains(s.Description, "healing") ||
|
||||
strings.Contains(s.Description, "Healing") {
|
||||
effectMultiplier = 2.0 // Higher multiplier for attack/spell power
|
||||
}
|
||||
|
||||
// Determine effect category and apply appropriate multiplier
|
||||
if s.Effect3 != 0 {
|
||||
// Direct damage effects scale more aggressively at higher item levels
|
||||
if funk.Contains(directDamageEffects, s.Effect3) {
|
||||
// Scale damage more aggressively for higher item levels
|
||||
effectMultiplier = 2.5 + (float64(toItemLevel) * 0.1 * 0.005) // +0.5% per every 10 item levels
|
||||
}
|
||||
|
||||
// Flat Base Stat modifier for all other stats.
|
||||
if funk.Contains(statBuffEffects, s.Effect3) && effectMultiplier < 1.5 {
|
||||
effectMultiplier = 1.45
|
||||
}
|
||||
}
|
||||
// Special handling for aura effects
|
||||
if s.EffectAura3 != 0 {
|
||||
// DOT effects (Aura 3: Periodic Damage)
|
||||
if s.EffectAura3 == 3 && funk.Contains(periodEffects, s.Effect3) {
|
||||
effectMultiplier = 2.5 + (float64(toItemLevel) * 0.1 * 0.005)
|
||||
|
||||
// Scale DOTs more with higher quality items
|
||||
if itemQuality >= 5 { // Legendary or higher
|
||||
effectMultiplier += 0.5
|
||||
}
|
||||
}
|
||||
|
||||
// HOT effects (Aura 8: Periodic Heal)
|
||||
if s.EffectAura3 == 8 && funk.Contains(periodEffects, s.Effect3) {
|
||||
effectMultiplier = 2.5 + (float64(toItemLevel) * 0.1 * 0.005)
|
||||
// Healing scales slightly higher than damage
|
||||
}
|
||||
|
||||
// Damage Shield effects (Aura 15)
|
||||
if s.EffectAura3 == 15 && funk.Contains(periodEffects, s.Effect3) {
|
||||
// Damage shields scale with item level difference
|
||||
effectMultiplier = 1.5 + (float64(toItemLevel) * 0.1 * 0.005)
|
||||
if effectMultiplier > 2.5 {
|
||||
effectMultiplier = 2.5 // Cap at 2.5x
|
||||
}
|
||||
}
|
||||
|
||||
// Proc chance effects (various auras)
|
||||
if s.ProcChance > 0 && s.ProcChance < 100 {
|
||||
// For proc effects, we might want to scale the effect more aggressively
|
||||
// since they don't happen all the time
|
||||
procFactor := 100.0 / float64(s.ProcChance) // Inverse of proc chance
|
||||
// Limit the proc factor to avoid excessive scaling
|
||||
if procFactor > 2.0 {
|
||||
procFactor = 2.0
|
||||
}
|
||||
effectMultiplier += math.Sqrt(procFactor) // Scale by square root of proc factor
|
||||
}
|
||||
}
|
||||
|
||||
// Special handling for mana restoration
|
||||
if s.Effect3 == 30 {
|
||||
if strings.Contains(s.Description, "Mana") || strings.Contains(s.Description, "mana") {
|
||||
// Mana effects scale with level but with diminishing returns
|
||||
effectMultiplier = 1.0 + (math.Log10(float64(ilevelDiff+1)) * 0.3)
|
||||
}
|
||||
}
|
||||
// Apply the scaling with the appropriate multiplier
|
||||
s.EffectBasePoints3 = int(float64(s.EffectBasePoints3) * levelRatio * qualModifier * effectMultiplier)
|
||||
}
|
||||
|
||||
// Update spell name with new values if it contains the old values
|
||||
// This helps keep the spell name in sync with the actual effect values
|
||||
newValues := []int{
|
||||
s.EffectBasePoints1 + 1, // Add 1 to match WoW's display format
|
||||
s.EffectBasePoints2 + 1,
|
||||
s.EffectBasePoints3 + 1,
|
||||
}
|
||||
|
||||
// Store the original name before any modifications
|
||||
originalName := s.Name
|
||||
|
||||
// Try different formats of the number that might appear in the name
|
||||
for i, oldValue := range []int{originalBasePoints1, originalBasePoints2, originalBasePoints3} {
|
||||
if oldValue <= 1 { // Skip if original value is 0 or 1 (likely not meaningful)
|
||||
continue
|
||||
}
|
||||
|
||||
newValue := newValues[i]
|
||||
if newValue <= 1 { // Skip if new value is 0 or 1 (likely not meaningful)
|
||||
continue
|
||||
}
|
||||
|
||||
// Skip if values are the same (no change needed)
|
||||
if oldValue == newValue {
|
||||
continue
|
||||
}
|
||||
|
||||
// Convert both old and new values to strings
|
||||
oldValueStr := fmt.Sprintf("%d", oldValue)
|
||||
newValueStr := fmt.Sprintf("%d", newValue)
|
||||
|
||||
// Only replace if the old value actually appears in the name
|
||||
if strings.Contains(s.Name, oldValueStr) {
|
||||
s.Name = strings.Replace(s.Name, oldValueStr, newValueStr, -1)
|
||||
//log.Printf("Updated ID %d spell name from '%s' to '%s' (replaced %s with %s)",
|
||||
// s.ID, originalName, s.Name, oldValueStr, newValueStr)
|
||||
}
|
||||
|
||||
// Also try with a plus sign (e.g., "+15" in name)
|
||||
oldValueWithPlus := "+" + oldValueStr
|
||||
newValueWithPlus := "+" + newValueStr
|
||||
if strings.Contains(s.Name, oldValueWithPlus) {
|
||||
s.Name = strings.Replace(s.Name, oldValueWithPlus, newValueWithPlus, -1)
|
||||
log.Printf("Updated spell name from '%s' to '%s' (replaced %s with %s)",
|
||||
originalName, s.Name, oldValueWithPlus, newValueWithPlus)
|
||||
}
|
||||
}
|
||||
|
||||
s.Scaled = true
|
||||
return nil
|
||||
}
|
||||
|
||||
func SpellToSql(spell Spell, quality int) string {
|
||||
|
||||
entryBump := 30000000
|
||||
if quality == 4 {
|
||||
entryBump = 31000000
|
||||
}
|
||||
if quality == 5 {
|
||||
entryBump = 32000000
|
||||
}
|
||||
|
||||
insert := fmt.Sprintf(`
|
||||
INSERT IGNORE INTO acore_world.spell_dbc (
|
||||
ID, Category, DispelType, Mechanic, Attributes, AttributesEx, AttributesEx2, AttributesEx3, AttributesEx4,
|
||||
AttributesEx5, AttributesEx6, AttributesEx7, ShapeshiftMask, unk_320_2, ShapeshiftExclude, unk_320_3, Targets,
|
||||
TargetCreatureType, RequiresSpellFocus, FacingCasterFlags, CasterAuraState, TargetAuraState, ExcludeCasterAuraState,
|
||||
ExcludeTargetAuraState, CasterAuraSpell, TargetAuraSpell, ExcludeCasterAuraSpell, ExcludeTargetAuraSpell, CastingTimeIndex,
|
||||
RecoveryTime, CategoryRecoveryTime, InterruptFlags, AuraInterruptFlags, ChannelInterruptFlags, ProcTypeMask, ProcChance,
|
||||
ProcCharges, MaxLevel, BaseLevel, SpellLevel, DurationIndex, PowerType, ManaCost, ManaCostPerLevel, ManaPerSecond,
|
||||
ManaPerSecondPerLevel, RangeIndex, Speed, ModalNextSpell, CumulativeAura, Totem_1, Totem_2, Reagent_1, Reagent_2, Reagent_3,
|
||||
Reagent_4, Reagent_5, Reagent_6, Reagent_7, Reagent_8, ReagentCount_1, ReagentCount_2, ReagentCount_3, ReagentCount_4,
|
||||
ReagentCount_5, ReagentCount_6, ReagentCount_7, ReagentCount_8, EquippedItemClass, EquippedItemSubclass, EquippedItemInvTypes,
|
||||
Effect_1, Effect_2, Effect_3, EffectDieSides_1, EffectDieSides_2, EffectDieSides_3, EffectRealPointsPerLevel_1,
|
||||
EffectRealPointsPerLevel_2, EffectRealPointsPerLevel_3, EffectBasePoints_1, EffectBasePoints_2, EffectBasePoints_3,
|
||||
EffectMechanic_1, EffectMechanic_2, EffectMechanic_3, ImplicitTargetA_1, ImplicitTargetA_2, ImplicitTargetA_3, ImplicitTargetB_1,
|
||||
ImplicitTargetB_2, ImplicitTargetB_3, EffectRadiusIndex_1, EffectRadiusIndex_2, EffectRadiusIndex_3, EffectAura_1,
|
||||
EffectAura_2, EffectAura_3, EffectAuraPeriod_1, EffectAuraPeriod_2, EffectAuraPeriod_3, EffectMultipleValue_1, EffectMultipleValue_2,
|
||||
EffectMultipleValue_3, EffectChainTargets_1, EffectChainTargets_2, EffectChainTargets_3, EffectItemType_1, EffectItemType_2,
|
||||
EffectItemType_3, EffectMiscValue_1, EffectMiscValue_2, EffectMiscValue_3, EffectMiscValueB_1, EffectMiscValueB_2, EffectMiscValueB_3,
|
||||
EffectTriggerSpell_1, EffectTriggerSpell_2, EffectTriggerSpell_3, EffectPointsPerCombo_1, EffectPointsPerCombo_2, EffectPointsPerCombo_3,
|
||||
EffectSpellClassMaskA_1, EffectSpellClassMaskA_2, EffectSpellClassMaskA_3, EffectSpellClassMaskB_1, EffectSpellClassMaskB_2,
|
||||
EffectSpellClassMaskB_3, EffectSpellClassMaskC_1, EffectSpellClassMaskC_2, EffectSpellClassMaskC_3, SpellVisualID_1, SpellVisualID_2,
|
||||
SpellIconID, ActiveIconID, SpellPriority, Name_Lang_enUS, Name_Lang_enGB, Name_Lang_koKR, Name_Lang_frFR, Name_Lang_deDE,
|
||||
Name_Lang_enCN, Name_Lang_zhCN, Name_Lang_enTW, Name_Lang_zhTW, Name_Lang_esES, Name_Lang_esMX, Name_Lang_ruRU, Name_Lang_ptPT,
|
||||
Name_Lang_ptBR, Name_Lang_itIT, Name_Lang_Unk, Name_Lang_Mask, NameSubtext_Lang_enUS, NameSubtext_Lang_enGB, NameSubtext_Lang_koKR,
|
||||
NameSubtext_Lang_frFR, NameSubtext_Lang_deDE, NameSubtext_Lang_enCN, NameSubtext_Lang_zhCN, NameSubtext_Lang_enTW, NameSubtext_Lang_zhTW,
|
||||
NameSubtext_Lang_esES, NameSubtext_Lang_esMX, NameSubtext_Lang_ruRU, NameSubtext_Lang_ptPT, NameSubtext_Lang_ptBR, NameSubtext_Lang_itIT,
|
||||
NameSubtext_Lang_Unk, NameSubtext_Lang_Mask, Description_Lang_enUS, Description_Lang_enGB, Description_Lang_koKR, Description_Lang_frFR,
|
||||
Description_Lang_deDE, Description_Lang_enCN, Description_Lang_zhCN, Description_Lang_enTW, Description_Lang_zhTW, Description_Lang_esES,
|
||||
Description_Lang_esMX, Description_Lang_ruRU, Description_Lang_ptPT, Description_Lang_ptBR, Description_Lang_itIT, Description_Lang_Unk,
|
||||
Description_Lang_Mask, AuraDescription_Lang_enUS, AuraDescription_Lang_enGB, AuraDescription_Lang_koKR, AuraDescription_Lang_frFR,
|
||||
AuraDescription_Lang_deDE, AuraDescription_Lang_enCN, AuraDescription_Lang_zhCN, AuraDescription_Lang_enTW, AuraDescription_Lang_zhTW,
|
||||
AuraDescription_Lang_esES, AuraDescription_Lang_esMX, AuraDescription_Lang_ruRU, AuraDescription_Lang_ptPT, AuraDescription_Lang_ptBR,
|
||||
AuraDescription_Lang_itIT, AuraDescription_Lang_Unk, AuraDescription_Lang_Mask, ManaCostPct, StartRecoveryCategory, StartRecoveryTime,
|
||||
MaxTargetLevel, SpellClassSet, SpellClassMask_1, SpellClassMask_2, SpellClassMask_3, MaxTargets, DefenseType, PreventionType, StanceBarOrder,
|
||||
EffectChainAmplitude_1, EffectChainAmplitude_2, EffectChainAmplitude_3, MinFactionID, MinReputation, RequiredAuraVision, RequiredTotemCategoryID_1,
|
||||
RequiredTotemCategoryID_2, RequiredAreasID, SchoolMask, RuneCostID, SpellMissileID, PowerDisplayID, EffectBonusMultiplier_1, EffectBonusMultiplier_2,
|
||||
EffectBonusMultiplier_3, SpellDescriptionVariableID, SpellDifficultyID
|
||||
) SELECT
|
||||
ID + %v, Category, DispelType, Mechanic, Attributes, AttributesEx, AttributesEx2, AttributesEx3, AttributesEx4,
|
||||
AttributesEx5, AttributesEx6, AttributesEx7, ShapeshiftMask, unk_320_2, ShapeshiftExclude, unk_320_3, Targets,
|
||||
TargetCreatureType, RequiresSpellFocus, FacingCasterFlags, CasterAuraState, TargetAuraState, ExcludeCasterAuraState,
|
||||
ExcludeTargetAuraState, CasterAuraSpell, TargetAuraSpell, ExcludeCasterAuraSpell, ExcludeTargetAuraSpell, CastingTimeIndex,
|
||||
RecoveryTime, CategoryRecoveryTime, InterruptFlags, AuraInterruptFlags, ChannelInterruptFlags, ProcTypeMask, ProcChance,
|
||||
ProcCharges, MaxLevel, BaseLevel, SpellLevel, DurationIndex, PowerType, ManaCost, ManaCostPerLevel, ManaPerSecond,
|
||||
ManaPerSecondPerLevel, RangeIndex, Speed, ModalNextSpell, CumulativeAura, Totem_1, Totem_2, Reagent_1, Reagent_2, Reagent_3,
|
||||
Reagent_4, Reagent_5, Reagent_6, Reagent_7, Reagent_8, ReagentCount_1, ReagentCount_2, ReagentCount_3, ReagentCount_4,
|
||||
ReagentCount_5, ReagentCount_6, ReagentCount_7, ReagentCount_8, EquippedItemClass, EquippedItemSubclass, EquippedItemInvTypes,
|
||||
Effect_1, Effect_2, Effect_3, EffectDieSides_1, EffectDieSides_2, EffectDieSides_3, EffectRealPointsPerLevel_1,
|
||||
EffectRealPointsPerLevel_2, EffectRealPointsPerLevel_3, EffectBasePoints_1, EffectBasePoints_2, EffectBasePoints_3,
|
||||
EffectMechanic_1, EffectMechanic_2, EffectMechanic_3, ImplicitTargetA_1, ImplicitTargetA_2, ImplicitTargetA_3, ImplicitTargetB_1,
|
||||
ImplicitTargetB_2, ImplicitTargetB_3, EffectRadiusIndex_1, EffectRadiusIndex_2, EffectRadiusIndex_3, EffectAura_1,
|
||||
EffectAura_2, EffectAura_3, EffectAuraPeriod_1, EffectAuraPeriod_2, EffectAuraPeriod_3, EffectMultipleValue_1, EffectMultipleValue_2,
|
||||
EffectMultipleValue_3, EffectChainTargets_1, EffectChainTargets_2, EffectChainTargets_3, EffectItemType_1, EffectItemType_2,
|
||||
EffectItemType_3, EffectMiscValue_1, EffectMiscValue_2, EffectMiscValue_3, EffectMiscValueB_1, EffectMiscValueB_2, EffectMiscValueB_3,
|
||||
EffectTriggerSpell_1, EffectTriggerSpell_2, EffectTriggerSpell_3, EffectPointsPerCombo_1, EffectPointsPerCombo_2, EffectPointsPerCombo_3,
|
||||
EffectSpellClassMaskA_1, EffectSpellClassMaskA_2, EffectSpellClassMaskA_3, EffectSpellClassMaskB_1, EffectSpellClassMaskB_2,
|
||||
EffectSpellClassMaskB_3, EffectSpellClassMaskC_1, EffectSpellClassMaskC_2, EffectSpellClassMaskC_3, SpellVisualID_1, SpellVisualID_2,
|
||||
SpellIconID, ActiveIconID, SpellPriority, Name_Lang_enUS, Name_Lang_enGB, Name_Lang_koKR, Name_Lang_frFR, Name_Lang_deDE,
|
||||
Name_Lang_enCN, Name_Lang_zhCN, Name_Lang_enTW, Name_Lang_zhTW, Name_Lang_esES, Name_Lang_esMX, Name_Lang_ruRU, Name_Lang_ptPT,
|
||||
Name_Lang_ptBR, Name_Lang_itIT, Name_Lang_Unk, Name_Lang_Mask, NameSubtext_Lang_enUS, NameSubtext_Lang_enGB, NameSubtext_Lang_koKR,
|
||||
NameSubtext_Lang_frFR, NameSubtext_Lang_deDE, NameSubtext_Lang_enCN, NameSubtext_Lang_zhCN, NameSubtext_Lang_enTW, NameSubtext_Lang_zhTW,
|
||||
NameSubtext_Lang_esES, NameSubtext_Lang_esMX, NameSubtext_Lang_ruRU, NameSubtext_Lang_ptPT, NameSubtext_Lang_ptBR, NameSubtext_Lang_itIT,
|
||||
NameSubtext_Lang_Unk, NameSubtext_Lang_Mask, Description_Lang_enUS, Description_Lang_enGB, Description_Lang_koKR, Description_Lang_frFR,
|
||||
Description_Lang_deDE, Description_Lang_enCN, Description_Lang_zhCN, Description_Lang_enTW, Description_Lang_zhTW, Description_Lang_esES,
|
||||
Description_Lang_esMX, Description_Lang_ruRU, Description_Lang_ptPT, Description_Lang_ptBR, Description_Lang_itIT, Description_Lang_Unk,
|
||||
Description_Lang_Mask, AuraDescription_Lang_enUS, AuraDescription_Lang_enGB, AuraDescription_Lang_koKR, AuraDescription_Lang_frFR,
|
||||
AuraDescription_Lang_deDE, AuraDescription_Lang_enCN, AuraDescription_Lang_zhCN, AuraDescription_Lang_enTW, AuraDescription_Lang_zhTW,
|
||||
AuraDescription_Lang_esES, AuraDescription_Lang_esMX, AuraDescription_Lang_ruRU, AuraDescription_Lang_ptPT, AuraDescription_Lang_ptBR,
|
||||
AuraDescription_Lang_itIT, AuraDescription_Lang_Unk, AuraDescription_Lang_Mask, ManaCostPct, StartRecoveryCategory, StartRecoveryTime,
|
||||
MaxTargetLevel, SpellClassSet, SpellClassMask_1, SpellClassMask_2, SpellClassMask_3, MaxTargets, DefenseType, PreventionType, StanceBarOrder,
|
||||
EffectChainAmplitude_1, EffectChainAmplitude_2, EffectChainAmplitude_3, MinFactionID, MinReputation, RequiredAuraVision, RequiredTotemCategoryID_1,
|
||||
RequiredTotemCategoryID_2, RequiredAreasID, SchoolMask, RuneCostID, SpellMissileID, PowerDisplayID, EffectBonusMultiplier_1, EffectBonusMultiplier_2,
|
||||
EffectBonusMultiplier_3, SpellDescriptionVariableID, SpellDifficultyID
|
||||
from spell_dbc as src WHERE src.ID = %v;`, entryBump, spell.ID)
|
||||
|
||||
update := fmt.Sprintf(`
|
||||
UPDATE acore_world.spell_dbc
|
||||
SET EffectBasePoints_1 = %v, EffectBasePoints_2 = %v
|
||||
WHERE ID = %v;`, spell.EffectBasePoints1, spell.EffectBasePoints2, entryBump+spell.ID)
|
||||
|
||||
return fmt.Sprintf("\n %s \n %s \n", insert, update)
|
||||
}
|
||||
60
internal/spells/spells_test.go
Normal file
60
internal/spells/spells_test.go
Normal file
@@ -0,0 +1,60 @@
|
||||
package spells
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
"github.com/araxiaonline/endgame-item-generator/internal/db/mysql"
|
||||
)
|
||||
|
||||
func TestCanBeConverted(t *testing.T) {
|
||||
tests := []struct {
|
||||
name string
|
||||
spell Spell
|
||||
expected bool
|
||||
}{
|
||||
{
|
||||
name: "Spell with non-aura effect",
|
||||
spell: Spell{
|
||||
DbSpell: mysql.DbSpell{
|
||||
Effect1: 1,
|
||||
},
|
||||
},
|
||||
expected: false,
|
||||
},
|
||||
{
|
||||
name: "Spell with aura effect that can be converted",
|
||||
spell: Spell{
|
||||
DbSpell: mysql.DbSpell{
|
||||
EffectAura1: 8,
|
||||
},
|
||||
},
|
||||
expected: true,
|
||||
},
|
||||
{
|
||||
name: "Spell with mixed effects",
|
||||
spell: Spell{
|
||||
DbSpell: mysql.DbSpell{
|
||||
Effect1: 1,
|
||||
EffectAura1: 8,
|
||||
},
|
||||
},
|
||||
expected: false,
|
||||
},
|
||||
{
|
||||
name: "Spell with no effects",
|
||||
spell: Spell{
|
||||
DbSpell: mysql.DbSpell{},
|
||||
},
|
||||
expected: false,
|
||||
},
|
||||
}
|
||||
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
result := tt.spell.CanBeConverted()
|
||||
if result != tt.expected {
|
||||
t.Errorf("expected %v, got %v", tt.expected, result)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
349
internal/spells/thematic.go
Normal file
349
internal/spells/thematic.go
Normal file
@@ -0,0 +1,349 @@
|
||||
package spells
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"log"
|
||||
"strings"
|
||||
|
||||
"github.com/araxiaonline/endgame-item-generator/internal/db/mysql"
|
||||
)
|
||||
|
||||
// SpellTheme represents different magical themes for spell assignment
|
||||
type SpellTheme int
|
||||
|
||||
const (
|
||||
ThemeNone SpellTheme = iota
|
||||
ThemeFrost
|
||||
ThemeFire
|
||||
ThemeNature
|
||||
ThemeShadow
|
||||
ThemeArcane
|
||||
ThemeHoly
|
||||
)
|
||||
|
||||
// String returns the string representation of a SpellTheme
|
||||
func (t SpellTheme) String() string {
|
||||
switch t {
|
||||
case ThemeFrost:
|
||||
return "Frost"
|
||||
case ThemeFire:
|
||||
return "Fire"
|
||||
case ThemeNature:
|
||||
return "Nature"
|
||||
case ThemeShadow:
|
||||
return "Shadow"
|
||||
case ThemeArcane:
|
||||
return "Arcane"
|
||||
case ThemeHoly:
|
||||
return "Holy"
|
||||
default:
|
||||
return "None"
|
||||
}
|
||||
}
|
||||
|
||||
// ThematicSpellAssigner handles assignment of thematic spells to items
|
||||
type ThematicSpellAssigner struct {
|
||||
db *mysql.MySqlDb
|
||||
}
|
||||
|
||||
// NewThematicSpellAssigner creates a new thematic spell assigner
|
||||
func NewThematicSpellAssigner(db *mysql.MySqlDb) *ThematicSpellAssigner {
|
||||
return &ThematicSpellAssigner{db: db}
|
||||
}
|
||||
|
||||
// ShouldHaveProc determines if an item should have a proc spell based on its properties
|
||||
func (tsa *ThematicSpellAssigner) ShouldHaveProc(itemClass, itemSubclass, itemLevel, quality int, itemName string) bool {
|
||||
log.Printf("DEBUG: ShouldHaveProc - Class: %d, Subclass: %d, Level: %d, Quality: %d, Name: %s",
|
||||
itemClass, itemSubclass, itemLevel, quality, itemName)
|
||||
|
||||
// Weapons should have procs
|
||||
if itemClass == 2 {
|
||||
log.Printf("DEBUG: Item is a weapon (class 2)")
|
||||
// Higher quality items more likely to have procs
|
||||
if quality >= 3 && itemLevel >= 40 {
|
||||
log.Printf("DEBUG: Weapon qualifies - quality %d >= 3 and level %d >= 40", quality, itemLevel)
|
||||
return true
|
||||
} else {
|
||||
log.Printf("DEBUG: Weapon does not qualify - quality %d < 3 or level %d < 40", quality, itemLevel)
|
||||
}
|
||||
}
|
||||
|
||||
// Trinkets should have procs
|
||||
if itemClass == 4 && itemSubclass == 0 {
|
||||
log.Printf("DEBUG: Item is a trinket - qualifies for proc")
|
||||
return true
|
||||
}
|
||||
|
||||
// Jewelry with thematic names
|
||||
if itemClass == 4 && (itemSubclass == 1 || itemSubclass == 2) { // Neck, Ring
|
||||
theme := tsa.DetectThemeFromName(itemName)
|
||||
if theme != ThemeNone {
|
||||
log.Printf("DEBUG: Jewelry with theme %s - qualifies for proc", theme.String())
|
||||
return true
|
||||
}
|
||||
}
|
||||
|
||||
log.Printf("DEBUG: Item does not qualify for proc")
|
||||
return false
|
||||
}
|
||||
|
||||
// DetectThemeFromName analyzes item name and description to determine magical theme
|
||||
func (tsa *ThematicSpellAssigner) DetectThemeFromName(itemName string) SpellTheme {
|
||||
name := strings.ToLower(itemName)
|
||||
|
||||
// Frost theme keywords - spells like Frostbolt, Frost Nova, Ice Lance
|
||||
frostKeywords := []string{
|
||||
"frost", "cold", "ice", "frozen", "chill", "winter", "arctic", "glacial",
|
||||
"coldrage", "frostbite", "icicle", "blizzard", "freeze", "shiver", "crystal",
|
||||
"permafrost", "hoarfrost", "rimefang", "icecrown", "northrend", "wintergrasp",
|
||||
"frostmourne", "sindragosa", "arthas", "lich", "undead", "scourge",
|
||||
}
|
||||
|
||||
// Fire theme keywords - spells like Fireball, Flame Strike, Pyroblast
|
||||
fireKeywords := []string{
|
||||
"fire", "flame", "burn", "ember", "inferno", "molten", "volcanic",
|
||||
"blazing", "scorching", "flaming", "ignite", "pyre", "magma", "lava",
|
||||
"sulfuron", "ragnaros", "flamewaker", "firelands", "phoenix", "immolate",
|
||||
"conflagrate", "incinerate", "combustion", "pyroblast", "scorch",
|
||||
}
|
||||
|
||||
// Nature theme keywords - spells like Lightning Bolt, Earth Shock, Entangling Roots
|
||||
natureKeywords := []string{
|
||||
"nature", "earth", "storm", "lightning", "thunder", "wind", "leaf",
|
||||
"thorn", "root", "growth", "poison", "venom", "toxic", "acid", "druid",
|
||||
"shaman", "elemental", "totem", "spirit", "wolf", "bear", "cat", "tree",
|
||||
"hurricane", "typhoon", "earthquake", "rockbiter", "windfury", "stormstrike",
|
||||
"maelstrom", "chain", "healing", "rejuvenation", "regrowth", "lifebloom",
|
||||
}
|
||||
|
||||
// Shadow theme keywords - spells like Shadow Bolt, Drain Life, Fear
|
||||
shadowKeywords := []string{
|
||||
"shadow", "dark", "void", "curse", "doom", "death", "soul", "spirit",
|
||||
"nightmare", "corruption", "plague", "blight", "necro", "warlock", "priest",
|
||||
"undead", "bone", "skull", "grave", "tomb", "crypt", "wraith", "specter",
|
||||
"banshee", "lich", "drain", "siphon", "vampiric", "life", "mana", "burn",
|
||||
"fear", "horror", "terror", "agony", "torment", "suffering", "pain",
|
||||
}
|
||||
|
||||
// Arcane theme keywords - spells like Arcane Missiles, Polymorph, Counterspell
|
||||
arcaneKeywords := []string{
|
||||
"arcane", "magic", "mystic", "enchant", "spell", "mana", "ethereal",
|
||||
"astral", "cosmic", "temporal", "dimensional", "mage", "wizard", "sorcerer",
|
||||
"intellect", "wisdom", "knowledge", "study", "tome", "grimoire", "staff",
|
||||
"orb", "crystal", "gem", "power", "energy", "force", "teleport", "portal",
|
||||
"polymorph", "counterspell", "dispel", "silence", "interrupt",
|
||||
}
|
||||
|
||||
// Holy theme keywords - spells like Heal, Flash of Light, Consecration
|
||||
holyKeywords := []string{
|
||||
"holy", "divine", "blessed", "sacred", "light", "radiant", "celestial",
|
||||
"righteous", "pure", "sanctified", "hallowed", "paladin", "priest", "cleric",
|
||||
"angel", "seraph", "cherub", "heaven", "paradise", "salvation", "redemption",
|
||||
"consecration", "blessing", "grace", "mercy", "faith", "devotion", "prayer",
|
||||
"heal", "cure", "restore", "renew", "resurrect", "revive", "sanctuary",
|
||||
}
|
||||
|
||||
// Check each theme
|
||||
for _, keyword := range frostKeywords {
|
||||
if strings.Contains(name, keyword) {
|
||||
return ThemeFrost
|
||||
}
|
||||
}
|
||||
|
||||
for _, keyword := range fireKeywords {
|
||||
if strings.Contains(name, keyword) {
|
||||
return ThemeFire
|
||||
}
|
||||
}
|
||||
|
||||
for _, keyword := range natureKeywords {
|
||||
if strings.Contains(name, keyword) {
|
||||
return ThemeNature
|
||||
}
|
||||
}
|
||||
|
||||
for _, keyword := range shadowKeywords {
|
||||
if strings.Contains(name, keyword) {
|
||||
return ThemeShadow
|
||||
}
|
||||
}
|
||||
|
||||
for _, keyword := range arcaneKeywords {
|
||||
if strings.Contains(name, keyword) {
|
||||
return ThemeArcane
|
||||
}
|
||||
}
|
||||
|
||||
for _, keyword := range holyKeywords {
|
||||
if strings.Contains(name, keyword) {
|
||||
return ThemeHoly
|
||||
}
|
||||
}
|
||||
|
||||
return ThemeNone
|
||||
}
|
||||
|
||||
// FindThematicSpell finds an appropriate spell for the given theme
|
||||
func (tsa *ThematicSpellAssigner) FindThematicSpell(theme SpellTheme, itemClass, itemSubclass int) (int, error) {
|
||||
log.Printf("Finding thematic spell for theme: %s, class: %d, subclass: %d", theme.String(), itemClass, itemSubclass)
|
||||
|
||||
// First, try to find existing scaled spells (31000000+)
|
||||
scaledSpellId, err := tsa.findScaledThematicSpell(theme, itemClass, itemSubclass)
|
||||
if err == nil && scaledSpellId > 0 {
|
||||
log.Printf("Found existing scaled spell: %d for theme %s", scaledSpellId, theme.String())
|
||||
return scaledSpellId, nil
|
||||
}
|
||||
|
||||
// If no scaled spell found, look in spell_dbc for base spells
|
||||
baseSpellId, err := tsa.findBaseThematicSpell(theme, itemClass, itemSubclass)
|
||||
if err == nil && baseSpellId > 0 {
|
||||
log.Printf("Found base spell: %d for theme %s", baseSpellId, theme.String())
|
||||
return baseSpellId, nil
|
||||
}
|
||||
|
||||
return 0, fmt.Errorf("no suitable spell found for theme %s", theme.String())
|
||||
}
|
||||
|
||||
// findScaledThematicSpell looks for existing scaled spells (31000000+) that match the theme
|
||||
func (tsa *ThematicSpellAssigner) findScaledThematicSpell(theme SpellTheme, itemClass, itemSubclass int) (int, error) {
|
||||
// Define spell pools for each theme (existing scaled spells starting from 31000000)
|
||||
// These would be spells that have already been scaled by the system
|
||||
scaledSpellPools := map[SpellTheme][]int{
|
||||
ThemeFrost: {
|
||||
// Start with high-priority frost spells for weapons/trinkets
|
||||
31013439, // Scaled Frostbolt (damage + slow)
|
||||
31012737, // Scaled Frost Armor (defensive)
|
||||
31021401, // Scaled Frost Nova (AoE slow)
|
||||
},
|
||||
ThemeFire: {
|
||||
// Fire damage spells
|
||||
31013140, // Scaled Fireball (direct damage)
|
||||
31008413, // Scaled Fire Nova (AoE damage)
|
||||
31011564, // Scaled Flame Strike (ground effect)
|
||||
},
|
||||
ThemeNature: {
|
||||
// Nature/Lightning spells
|
||||
31000421, // Scaled Lightning Bolt (instant damage)
|
||||
31008050, // Scaled Earth Shock (damage + interrupt)
|
||||
31010414, // Scaled Entangling Roots (root effect)
|
||||
},
|
||||
ThemeShadow: {
|
||||
// Shadow/Dark magic spells
|
||||
31000980, // Scaled Shadow Bolt (shadow damage)
|
||||
31007648, // Scaled Drain Life (damage + heal)
|
||||
31011671, // Scaled Shadow Word: Pain (DoT)
|
||||
},
|
||||
ThemeArcane: {
|
||||
// Arcane magic spells
|
||||
31005143, // Scaled Arcane Missiles (channeled damage)
|
||||
31001953, // Scaled Blink (teleport)
|
||||
31000118, // Scaled Polymorph (crowd control)
|
||||
},
|
||||
ThemeHoly: {
|
||||
// Holy/Light spells
|
||||
31000139, // Scaled Heal (direct healing)
|
||||
31010060, // Scaled Flash of Light (fast heal)
|
||||
31001244, // Scaled Divine Favor (buff)
|
||||
},
|
||||
}
|
||||
|
||||
spells, exists := scaledSpellPools[theme]
|
||||
if !exists || len(spells) == 0 {
|
||||
return 0, fmt.Errorf("no scaled spells available for theme %s", theme.String())
|
||||
}
|
||||
|
||||
// For weapons, prefer damage spells; for trinkets/jewelry, prefer utility
|
||||
if itemClass == 2 { // Weapons
|
||||
// Return first damage spell (they're ordered by preference)
|
||||
return spells[0], nil
|
||||
}
|
||||
|
||||
// For trinkets/jewelry, prefer utility spells (later in list)
|
||||
if len(spells) > 1 {
|
||||
return spells[len(spells)-1], nil
|
||||
}
|
||||
|
||||
return spells[0], nil
|
||||
}
|
||||
|
||||
// findBaseThematicSpell looks in spell_dbc for base spells that match the theme
|
||||
func (tsa *ThematicSpellAssigner) findBaseThematicSpell(theme SpellTheme, itemClass, itemSubclass int) (int, error) {
|
||||
// Define base spell pools for each theme
|
||||
baseSpellPools := map[SpellTheme][]int{
|
||||
ThemeFrost: {
|
||||
13439, // Frostbolt
|
||||
21401, // Frost Nova
|
||||
12737, // Frost Armor
|
||||
11113, // Blast Wave (Frost)
|
||||
},
|
||||
ThemeFire: {
|
||||
13140, // Fireball
|
||||
8413, // Fire Nova
|
||||
11564, // Flame Strike
|
||||
11129, // Combustion
|
||||
},
|
||||
ThemeNature: {
|
||||
421, // Lightning Bolt
|
||||
8050, // Earth Shock
|
||||
10414, // Entangling Roots
|
||||
16689, // Nature's Grasp
|
||||
},
|
||||
ThemeShadow: {
|
||||
980, // Shadow Bolt
|
||||
7648, // Drain Life
|
||||
11671, // Shadow Word: Pain
|
||||
18265, // Siphon Soul
|
||||
},
|
||||
ThemeArcane: {
|
||||
5143, // Arcane Missiles
|
||||
1953, // Blink
|
||||
118, // Polymorph
|
||||
12051, // Evocation
|
||||
},
|
||||
ThemeHoly: {
|
||||
139, // Heal
|
||||
1244, // Divine Favor
|
||||
10060, // Flash of Light
|
||||
10308, // Hammer of Justice
|
||||
},
|
||||
}
|
||||
|
||||
spells, exists := baseSpellPools[theme]
|
||||
if !exists || len(spells) == 0 {
|
||||
return 0, fmt.Errorf("no base spells available for theme %s", theme.String())
|
||||
}
|
||||
|
||||
// Verify spell exists in database
|
||||
for _, spellId := range spells {
|
||||
_, err := tsa.db.GetSpell(spellId)
|
||||
if err == nil {
|
||||
return spellId, nil
|
||||
}
|
||||
}
|
||||
|
||||
return 0, fmt.Errorf("no valid base spells found for theme %s", theme.String())
|
||||
}
|
||||
|
||||
// AssignThematicSpell assigns a thematic spell to an item if appropriate
|
||||
func (tsa *ThematicSpellAssigner) AssignThematicSpell(itemEntry, itemClass, itemSubclass, itemLevel, quality int, itemName string) (int, error) {
|
||||
// Check if item should have a proc
|
||||
if !tsa.ShouldHaveProc(itemClass, itemSubclass, itemLevel, quality, itemName) {
|
||||
return 0, fmt.Errorf("item does not qualify for proc assignment")
|
||||
}
|
||||
|
||||
// Detect theme from name
|
||||
theme := tsa.DetectThemeFromName(itemName)
|
||||
if theme == ThemeNone {
|
||||
// For weapons without clear theme, don't assign a spell
|
||||
return 0, fmt.Errorf("no clear theme detected for item: %s", itemName)
|
||||
}
|
||||
|
||||
// Find appropriate spell
|
||||
spellId, err := tsa.FindThematicSpell(theme, itemClass, itemSubclass)
|
||||
if err != nil {
|
||||
return 0, fmt.Errorf("failed to find thematic spell: %v", err)
|
||||
}
|
||||
|
||||
log.Printf("Assigned spell %d (theme: %s) to item %s (%d)", spellId, theme.String(), itemName, itemEntry)
|
||||
return spellId, nil
|
||||
}
|
||||
751
main.go
751
main.go
@@ -1,28 +1,560 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"encoding/csv"
|
||||
"flag"
|
||||
"fmt"
|
||||
"io"
|
||||
"log"
|
||||
"math/rand"
|
||||
"os"
|
||||
"strconv"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/araxiaonline/endgame-item-generator/internal/config"
|
||||
"github.com/araxiaonline/endgame-item-generator/internal/db/mysql"
|
||||
"github.com/araxiaonline/endgame-item-generator/internal/items"
|
||||
"github.com/araxiaonline/endgame-item-generator/internal/spells"
|
||||
|
||||
"github.com/araxiaonline/endgame-item-generator/models"
|
||||
_ "github.com/go-sql-driver/mysql"
|
||||
"github.com/joho/godotenv"
|
||||
)
|
||||
|
||||
func main() {
|
||||
// ItemScaler handles generic item scaling operations
|
||||
type ItemScaler struct {
|
||||
db *mysql.MySqlDb
|
||||
debug bool
|
||||
itemLevel int
|
||||
quality int
|
||||
phase int
|
||||
catchup float64
|
||||
spellAssigner *spells.ThematicSpellAssigner
|
||||
templateManager *items.StatTemplateManager
|
||||
}
|
||||
|
||||
// ScalingResult holds the result of item scaling
|
||||
type ScalingResult struct {
|
||||
Item *items.Item
|
||||
ReferenceItem *items.Item
|
||||
Success bool
|
||||
Errors []string
|
||||
Warnings []string
|
||||
SpellSQL []string // SQL statements for scaled spells
|
||||
}
|
||||
|
||||
// InputSource defines how items are provided to the scaler
|
||||
type InputSource interface {
|
||||
GetItems() ([]mysql.DbItem, error)
|
||||
GetName() string
|
||||
}
|
||||
|
||||
// EntryListSource scales items from a list of entry IDs
|
||||
type EntryListSource struct {
|
||||
Entries []int
|
||||
DB *mysql.MySqlDb
|
||||
}
|
||||
|
||||
func (e *EntryListSource) GetItems() ([]mysql.DbItem, error) {
|
||||
var items []mysql.DbItem
|
||||
for _, entry := range e.Entries {
|
||||
item, err := e.DB.GetItem(entry)
|
||||
if err != nil {
|
||||
log.Printf("Failed to get item %d: %v", entry, err)
|
||||
continue
|
||||
}
|
||||
items = append(items, item)
|
||||
}
|
||||
return items, nil
|
||||
}
|
||||
|
||||
func (e *EntryListSource) GetName() string {
|
||||
return fmt.Sprintf("Entry List (%d items)", len(e.Entries))
|
||||
}
|
||||
|
||||
// CSVSource scales items from a CSV file with entry IDs
|
||||
type CSVSource struct {
|
||||
FilePath string
|
||||
DB *mysql.MySqlDb
|
||||
}
|
||||
|
||||
func (c *CSVSource) GetItems() ([]mysql.DbItem, error) {
|
||||
file, err := os.Open(c.FilePath)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to open CSV file: %v", err)
|
||||
}
|
||||
defer file.Close()
|
||||
|
||||
reader := csv.NewReader(file)
|
||||
records, err := reader.ReadAll()
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to read CSV: %v", err)
|
||||
}
|
||||
|
||||
var items []mysql.DbItem
|
||||
for i, record := range records {
|
||||
if i == 0 && strings.ToLower(record[0]) == "entry" {
|
||||
continue // Skip header row
|
||||
}
|
||||
|
||||
if len(record) == 0 {
|
||||
continue
|
||||
}
|
||||
|
||||
entry, err := strconv.Atoi(record[0])
|
||||
if err != nil {
|
||||
log.Printf("Invalid entry ID in CSV row %d: %s", i+1, record[0])
|
||||
continue
|
||||
}
|
||||
|
||||
item, err := c.DB.GetItem(entry)
|
||||
if err != nil {
|
||||
log.Printf("Failed to get item %d from CSV: %v", entry, err)
|
||||
continue
|
||||
}
|
||||
items = append(items, item)
|
||||
}
|
||||
return items, nil
|
||||
}
|
||||
|
||||
func (c *CSVSource) GetName() string {
|
||||
return fmt.Sprintf("CSV File: %s", c.FilePath)
|
||||
}
|
||||
|
||||
// SQLQuerySource scales items from a custom SQL query
|
||||
type SQLQuerySource struct {
|
||||
Query string
|
||||
DB *mysql.MySqlDb
|
||||
}
|
||||
|
||||
func (s *SQLQuerySource) GetItems() ([]mysql.DbItem, error) {
|
||||
// For now, use GetRarePlusItems as a fallback since GetItemsByQuery doesn't exist
|
||||
// This can be extended later to support custom queries
|
||||
return s.DB.GetRarePlusItems(0, 0)
|
||||
}
|
||||
|
||||
func (s *SQLQuerySource) GetName() string {
|
||||
return "Custom SQL Query (using GetRarePlusItems)"
|
||||
}
|
||||
|
||||
// MapItemsSource scales items from map/boss/gameobject data (like Molten Core)
|
||||
type MapItemsSource struct {
|
||||
MapID int
|
||||
BossEntries []int
|
||||
GameObjectEntries []int
|
||||
DB *mysql.MySqlDb
|
||||
}
|
||||
|
||||
func (m *MapItemsSource) GetItems() ([]mysql.DbItem, error) {
|
||||
return m.DB.GetBossMapItems(m.MapID, m.BossEntries, m.GameObjectEntries, 0, 0)
|
||||
}
|
||||
|
||||
func (m *MapItemsSource) GetName() string {
|
||||
return fmt.Sprintf("Map %d Items", m.MapID)
|
||||
}
|
||||
|
||||
func NewItemScaler(db *mysql.MySqlDb, debug bool, itemLevel, quality, phase int, catchup float64) *ItemScaler {
|
||||
return &ItemScaler{
|
||||
db: db,
|
||||
debug: debug,
|
||||
itemLevel: itemLevel,
|
||||
quality: quality,
|
||||
phase: phase,
|
||||
catchup: catchup,
|
||||
spellAssigner: spells.NewThematicSpellAssigner(db),
|
||||
templateManager: items.NewStatTemplateManager(debug),
|
||||
}
|
||||
}
|
||||
|
||||
// ScaleItem performs the core scaling logic extracted from raid-gear/main.go
|
||||
func (s *ItemScaler) ScaleItem(dbItem mysql.DbItem) ScalingResult {
|
||||
result := ScalingResult{
|
||||
Success: false,
|
||||
Errors: []string{},
|
||||
Warnings: []string{},
|
||||
SpellSQL: []string{},
|
||||
}
|
||||
|
||||
// Create item from database item
|
||||
item := items.ItemFromDbItem(dbItem)
|
||||
|
||||
// Set quality if not already epic/legendary
|
||||
if *item.Quality < 4 {
|
||||
*item.Quality = s.quality
|
||||
}
|
||||
|
||||
// Check if item should have a thematic spell assigned
|
||||
if s.debug {
|
||||
log.Printf("Checking if %s should have thematic spell assigned", item.Name)
|
||||
}
|
||||
|
||||
if s.shouldAssignThematicSpell(item) {
|
||||
if s.debug {
|
||||
log.Printf("Item %s qualifies for thematic spell assignment", item.Name)
|
||||
}
|
||||
err := s.assignThematicSpell(&item)
|
||||
if err != nil {
|
||||
if s.debug {
|
||||
log.Printf("Failed to assign thematic spell to %s: %v", item.Name, err)
|
||||
}
|
||||
} else {
|
||||
if s.debug {
|
||||
log.Printf("Successfully assigned thematic spell to %s", item.Name)
|
||||
}
|
||||
}
|
||||
} else {
|
||||
if s.debug {
|
||||
log.Printf("Item %s does not qualify for thematic spell assignment", item.Name)
|
||||
}
|
||||
}
|
||||
|
||||
// Get item class type for reference item matching
|
||||
classType := item.GetClassUserType()
|
||||
|
||||
if s.debug {
|
||||
log.Printf("Scaling item: %s (Entry: %d) - Class: %d, Subclass: %d, ClassType: %d",
|
||||
item.Name, item.Entry, *item.Class, *item.Subclass, classType)
|
||||
}
|
||||
|
||||
var referenceItem items.Item
|
||||
|
||||
if s.phase == 0 {
|
||||
// Phase 0: Use simple stat templates instead of complex reference matching
|
||||
s.templateManager.ApplySimpleStatTemplate(&item)
|
||||
if s.debug {
|
||||
log.Printf("Using simple stat template for phase 0")
|
||||
}
|
||||
} else {
|
||||
// Phase 1+: Find reference items and use reference item scaling
|
||||
referenceItems, err := s.findReferenceItems(&item)
|
||||
if err != nil {
|
||||
result.Errors = append(result.Errors, fmt.Sprintf("Failed to find reference items: %v", err))
|
||||
return result
|
||||
}
|
||||
|
||||
if len(referenceItems) == 0 {
|
||||
result.Errors = append(result.Errors, "No compatible reference items found")
|
||||
result.Warnings = append(result.Warnings, "Manual review required - no reference items available")
|
||||
return result
|
||||
}
|
||||
|
||||
// Select random reference item
|
||||
referenceItem = referenceItems[rand.Intn(len(referenceItems))]
|
||||
result.ReferenceItem = &referenceItem
|
||||
|
||||
// Apply stats from reference item
|
||||
item.ApplyStats(referenceItem)
|
||||
}
|
||||
item.ScaleItemWithPhase(s.itemLevel, s.quality, s.phase)
|
||||
|
||||
// Apply tier modifiers if phase is specified
|
||||
if s.phase > 0 || s.catchup != 1.0 {
|
||||
item.ApplyTierModifiersWithCatchup(s.phase, s.catchup)
|
||||
}
|
||||
|
||||
// Collect spell SQL for any scaled spells
|
||||
for _, spell := range item.Spells {
|
||||
if spell.Scaled {
|
||||
spellSQL := spells.SpellToSql(spell, s.quality)
|
||||
result.SpellSQL = append(result.SpellSQL, spellSQL)
|
||||
if s.debug {
|
||||
log.Printf("Generated SQL for scaled spell: %s (ID: %d)", spell.Name, spell.ID)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if s.debug {
|
||||
if s.phase == 0 {
|
||||
log.Printf("Successfully scaled %s using simple stat template", item.Name)
|
||||
} else {
|
||||
log.Printf("Successfully scaled %s using reference item %s", item.Name, referenceItem.Name)
|
||||
}
|
||||
}
|
||||
|
||||
result.Item = &item
|
||||
result.Success = true
|
||||
return result
|
||||
}
|
||||
|
||||
// shouldAssignThematicSpell determines if an item should get a thematic spell
|
||||
func (s *ItemScaler) shouldAssignThematicSpell(item items.Item) bool {
|
||||
if s.debug {
|
||||
log.Printf("DEBUG: shouldAssignThematicSpell - checking item %s", item.Name)
|
||||
log.Printf("DEBUG: SpellId1: %v, SpellId2: %v, SpellId3: %v",
|
||||
item.SpellId1, item.SpellId2, item.SpellId3)
|
||||
}
|
||||
|
||||
// Check if item already has spells
|
||||
if item.SpellId1 != nil && *item.SpellId1 != 0 {
|
||||
if s.debug {
|
||||
log.Printf("DEBUG: Item already has spell in slot 1: %d", *item.SpellId1)
|
||||
}
|
||||
return false
|
||||
}
|
||||
if item.SpellId2 != nil && *item.SpellId2 != 0 {
|
||||
if s.debug {
|
||||
log.Printf("DEBUG: Item already has spell in slot 2: %d", *item.SpellId2)
|
||||
}
|
||||
return false
|
||||
}
|
||||
if item.SpellId3 != nil && *item.SpellId3 != 0 {
|
||||
if s.debug {
|
||||
log.Printf("DEBUG: Item already has spell in slot 3: %d", *item.SpellId3)
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
if s.debug {
|
||||
log.Printf("DEBUG: Item has no existing spells, checking if it should have a proc")
|
||||
}
|
||||
|
||||
// Use the thematic spell assigner to determine eligibility
|
||||
return s.spellAssigner.ShouldHaveProc(*item.Class, *item.Subclass, *item.ItemLevel, *item.Quality, item.Name)
|
||||
}
|
||||
|
||||
// assignThematicSpell assigns a thematic spell to an item
|
||||
func (s *ItemScaler) assignThematicSpell(item *items.Item) error {
|
||||
spellId, err := s.spellAssigner.AssignThematicSpell(item.Entry, *item.Class, *item.Subclass, *item.ItemLevel, *item.Quality, item.Name)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// Assign to first available spell slot
|
||||
if item.SpellId1 == nil || *item.SpellId1 == 0 {
|
||||
*item.SpellId1 = spellId
|
||||
*item.SpellTrigger1 = 2 // Chance on hit
|
||||
if s.debug {
|
||||
log.Printf("Assigned spell %d to %s in slot 1", spellId, item.Name)
|
||||
}
|
||||
} else if item.SpellId2 == nil || *item.SpellId2 == 0 {
|
||||
*item.SpellId2 = spellId
|
||||
*item.SpellTrigger2 = 2 // Chance on hit
|
||||
if s.debug {
|
||||
log.Printf("Assigned spell %d to %s in slot 2", spellId, item.Name)
|
||||
}
|
||||
} else if item.SpellId3 == nil || *item.SpellId3 == 0 {
|
||||
*item.SpellId3 = spellId
|
||||
*item.SpellTrigger3 = 2 // Chance on hit
|
||||
if s.debug {
|
||||
log.Printf("Assigned spell %d to %s in slot 3", spellId, item.Name)
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// findReferenceItems uses the sophisticated reference matching logic from raid-gear
|
||||
func (s *ItemScaler) findReferenceItems(item *items.Item) ([]items.Item, error) {
|
||||
classType := item.GetClassUserType()
|
||||
|
||||
// Handle subclass mapping for weapons (from raid-gear logic)
|
||||
subclassToUse := *item.Subclass
|
||||
if *item.Subclass == 8 {
|
||||
subclassToUse = 1 // two handed axe instead of sword
|
||||
}
|
||||
|
||||
// Get high-level reference items
|
||||
highLevelItems, err := s.db.GetRaidPhase1Items(*item.Class, subclassToUse, 0, 0)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to get reference items: %v", err)
|
||||
}
|
||||
|
||||
// Filter items by class type AND inventory type compatibility
|
||||
var compatibleChoices []items.Item
|
||||
var classOnlyChoices []items.Item
|
||||
var anyWeaponChoices []items.Item
|
||||
|
||||
for _, highLevelItem := range highLevelItems {
|
||||
refItem := items.ItemFromDbItem(highLevelItem)
|
||||
refItem.ScaleItem(*refItem.ItemLevel, *item.Quality)
|
||||
refClassType := refItem.GetClassUserType()
|
||||
|
||||
// Check both class type and inventory type compatibility
|
||||
classMatch := refClassType == classType
|
||||
invMatch := (item.InventoryType != nil && refItem.InventoryType != nil &&
|
||||
*item.InventoryType == *refItem.InventoryType)
|
||||
|
||||
if classMatch && invMatch {
|
||||
// Perfect match - both class type and inventory type
|
||||
compatibleChoices = append(compatibleChoices, refItem)
|
||||
} else if classMatch {
|
||||
// Class type match only - good fallback
|
||||
classOnlyChoices = append(classOnlyChoices, refItem)
|
||||
} else if *item.Class == 2 && *refItem.Class == 2 {
|
||||
// Any weapon as last resort for weapons
|
||||
anyWeaponChoices = append(anyWeaponChoices, refItem)
|
||||
}
|
||||
}
|
||||
|
||||
if s.debug {
|
||||
log.Printf("Reference items found - Perfect: %d, Class-only: %d, Any-weapon: %d",
|
||||
len(compatibleChoices), len(classOnlyChoices), len(anyWeaponChoices))
|
||||
}
|
||||
|
||||
// Return best available match
|
||||
if len(compatibleChoices) > 0 {
|
||||
return compatibleChoices, nil
|
||||
} else if len(classOnlyChoices) > 0 {
|
||||
if s.debug {
|
||||
log.Printf("Using class-only match for %s", item.Name)
|
||||
}
|
||||
return classOnlyChoices, nil
|
||||
} else if len(anyWeaponChoices) > 0 {
|
||||
if s.debug {
|
||||
log.Printf("Using any-weapon fallback for %s", item.Name)
|
||||
}
|
||||
return anyWeaponChoices, nil
|
||||
}
|
||||
|
||||
return compatibleChoices, nil
|
||||
}
|
||||
|
||||
// printScalingComparison shows before/after comparison
|
||||
func printScalingComparison(original, scaled *items.Item, reference *items.Item) {
|
||||
fmt.Printf("\n=== ITEM SCALING: %s (Entry: %d) ===\n", original.Name, original.Entry)
|
||||
if reference != nil {
|
||||
fmt.Printf("Reference Item: %s (Entry: %d)\n", reference.Name, reference.Entry)
|
||||
}
|
||||
|
||||
// Show key stats comparison
|
||||
fmt.Printf("Item Level: %d → %d\n", getItemLevel(original), getItemLevel(scaled))
|
||||
fmt.Printf("Quality: %d → %d\n", *original.Quality, *scaled.Quality)
|
||||
|
||||
// Show stat changes
|
||||
originalStats := extractStats(original)
|
||||
scaledStats := extractStats(scaled)
|
||||
|
||||
fmt.Printf("Stats Changes:\n")
|
||||
allStats := make(map[int]bool)
|
||||
for stat := range originalStats {
|
||||
allStats[stat] = true
|
||||
}
|
||||
for stat := range scaledStats {
|
||||
allStats[stat] = true
|
||||
}
|
||||
|
||||
for statType := range allStats {
|
||||
originalValue := originalStats[statType]
|
||||
scaledValue := scaledStats[statType]
|
||||
|
||||
if originalValue != scaledValue {
|
||||
statName := getStatName(statType)
|
||||
fmt.Printf(" %s: %d → %d\n", statName, originalValue, scaledValue)
|
||||
}
|
||||
}
|
||||
fmt.Printf("=====================================\n\n")
|
||||
}
|
||||
|
||||
// Helper functions
|
||||
func getItemLevel(item *items.Item) int {
|
||||
if item.ItemLevel != nil {
|
||||
return *item.ItemLevel
|
||||
}
|
||||
return 0
|
||||
}
|
||||
|
||||
func extractStats(item *items.Item) map[int]int {
|
||||
stats := make(map[int]int)
|
||||
for i := 1; i <= 8; i++ {
|
||||
statType := getStatType(item, i)
|
||||
statValue := getStatValue(item, i)
|
||||
if statType != nil && statValue != nil && *statType > 0 && *statValue > 0 {
|
||||
stats[*statType] = *statValue
|
||||
}
|
||||
}
|
||||
return stats
|
||||
}
|
||||
|
||||
func getStatType(item *items.Item, index int) *int {
|
||||
switch index {
|
||||
case 1:
|
||||
return item.StatType1
|
||||
case 2:
|
||||
return item.StatType2
|
||||
case 3:
|
||||
return item.StatType3
|
||||
case 4:
|
||||
return item.StatType4
|
||||
case 5:
|
||||
return item.StatType5
|
||||
case 6:
|
||||
return item.StatType6
|
||||
case 7:
|
||||
return item.StatType7
|
||||
case 8:
|
||||
return item.StatType8
|
||||
default:
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
func getStatValue(item *items.Item, index int) *int {
|
||||
switch index {
|
||||
case 1:
|
||||
return item.StatValue1
|
||||
case 2:
|
||||
return item.StatValue2
|
||||
case 3:
|
||||
return item.StatValue3
|
||||
case 4:
|
||||
return item.StatValue4
|
||||
case 5:
|
||||
return item.StatValue5
|
||||
case 6:
|
||||
return item.StatValue6
|
||||
case 7:
|
||||
return item.StatValue7
|
||||
case 8:
|
||||
return item.StatValue8
|
||||
default:
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
func getStatName(statType int) string {
|
||||
if name, exists := config.StatModifierNames[statType]; exists {
|
||||
return name
|
||||
}
|
||||
return fmt.Sprintf("Unknown(%d)", statType)
|
||||
}
|
||||
|
||||
func parseIntList(s string) []int {
|
||||
if s == "" {
|
||||
return []int{}
|
||||
}
|
||||
|
||||
parts := strings.Split(s, ",")
|
||||
var result []int
|
||||
for _, part := range parts {
|
||||
if num, err := strconv.Atoi(strings.TrimSpace(part)); err == nil {
|
||||
result = append(result, num)
|
||||
}
|
||||
}
|
||||
return result
|
||||
}
|
||||
|
||||
func main() {
|
||||
rand.Seed(time.Now().UnixNano())
|
||||
log.SetFlags(log.LstdFlags | log.Lshortfile)
|
||||
godotenv.Load()
|
||||
models.Connect()
|
||||
|
||||
debug := flag.Bool("debug", false, "Enable verbose logging inside generator")
|
||||
itemLevel := flag.Int("ilvl", 305, "Specify the item level to start scaling from, expansion and difficulty modifiers scale up.")
|
||||
difficulty := flag.Int("difficulty", 3, "set the difficulty of the dungeon, defaults to 3 (mythic) 4 (legendary) 5 (ascendant)")
|
||||
levelUp := flag.Bool("levelUp", false, "Boss items require higher +1 level to equip, defaults to false")
|
||||
baselevel := flag.Int("baselevel", 80, "set the base level for items to be used, defaults to 80 this is required for levelUp flag")
|
||||
// Command line flags
|
||||
debug := flag.Bool("debug", false, "Enable verbose logging")
|
||||
itemLevel := flag.Int("item-level", 325, "Target item level for scaling")
|
||||
quality := flag.Int("quality", 4, "Target quality (4=Epic, 5=Legendary)")
|
||||
phase := flag.Int("phase", 0, "Tier phase for modifiers (0=no tier bonus, 1-5=tier levels)")
|
||||
catchup := flag.Float64("catchup", 1.0, "Catchup bonus multiplier (1.0=no bonus, 1.5=50% bonus)")
|
||||
baseLevel := flag.Int("base-level", 80, "Base level requirement for items")
|
||||
difficulty := flag.Int("difficulty", 3, "Difficulty level (3=Mythic, 4=Legendary, 5=Ascendant)")
|
||||
outputSQL := flag.Bool("sql", false, "Output SQL statements")
|
||||
|
||||
// Input source flags
|
||||
entries := flag.String("entries", "", "Comma-separated list of entry IDs")
|
||||
csvFile := flag.String("csv", "", "CSV file with entry IDs")
|
||||
sqlQuery := flag.String("query", "", "Custom SQL query to get items")
|
||||
mapID := flag.Int("map-id", 0, "Map ID for boss/gameobject items")
|
||||
bossEntries := flag.String("boss-entries", "", "Comma-separated boss entry IDs")
|
||||
gameObjectEntries := flag.String("gameobject-entries", "", "Comma-separated gameobject entry IDs")
|
||||
|
||||
flag.Parse()
|
||||
|
||||
@@ -32,119 +564,138 @@ func main() {
|
||||
log.SetOutput(io.Discard)
|
||||
}
|
||||
|
||||
if difficulty == nil || *difficulty < 3 || *difficulty > 5 {
|
||||
log.Fatal("difficulty must be between 3-5")
|
||||
// Connect to database
|
||||
mysqlDb, err := mysql.Connect(&mysql.MySqlConfig{
|
||||
Host: os.Getenv("DB_HOST"),
|
||||
User: os.Getenv("DB_USER"),
|
||||
Password: os.Getenv("DB_PASSWORD"),
|
||||
Database: os.Getenv("DB_NAME"),
|
||||
})
|
||||
if err != nil {
|
||||
log.Fatal("Failed to connect to database:", err)
|
||||
}
|
||||
|
||||
// Determine input source
|
||||
var source InputSource
|
||||
sourceCount := 0
|
||||
|
||||
if *entries != "" {
|
||||
entryList := parseIntList(*entries)
|
||||
source = &EntryListSource{Entries: entryList, DB: mysqlDb}
|
||||
sourceCount++
|
||||
}
|
||||
|
||||
if *csvFile != "" {
|
||||
source = &CSVSource{FilePath: *csvFile, DB: mysqlDb}
|
||||
sourceCount++
|
||||
}
|
||||
|
||||
if *sqlQuery != "" {
|
||||
source = &SQLQuerySource{Query: *sqlQuery, DB: mysqlDb}
|
||||
sourceCount++
|
||||
}
|
||||
|
||||
if *mapID > 0 {
|
||||
source = &MapItemsSource{
|
||||
MapID: *mapID,
|
||||
BossEntries: parseIntList(*bossEntries),
|
||||
GameObjectEntries: parseIntList(*gameObjectEntries),
|
||||
DB: mysqlDb,
|
||||
}
|
||||
sourceCount++
|
||||
}
|
||||
|
||||
if sourceCount == 0 {
|
||||
fmt.Println("Error: No input source specified. Use one of:")
|
||||
fmt.Println(" --entries \"1234,5678\"")
|
||||
fmt.Println(" --csv items.csv")
|
||||
fmt.Println(" --query \"SELECT * FROM item_template WHERE ...\"")
|
||||
fmt.Println(" --map-id 409 --boss-entries \"11502\" --gameobject-entries \"179703\"")
|
||||
os.Exit(1)
|
||||
}
|
||||
|
||||
// main loop
|
||||
dungeons, err := models.DB.GetDungeons(-1)
|
||||
if sourceCount > 1 {
|
||||
fmt.Println("Error: Only one input source can be specified at a time")
|
||||
os.Exit(1)
|
||||
}
|
||||
|
||||
// Initialize scaler
|
||||
scaler := NewItemScaler(mysqlDb, *debug, *itemLevel, *quality, *phase, *catchup)
|
||||
|
||||
// Get items from source
|
||||
dbItems, err := source.GetItems()
|
||||
if err != nil {
|
||||
log.Panicf("failed to get dungeons for expansion %v error: %v", 0, err)
|
||||
log.Fatal("Failed to get items from source:", err)
|
||||
}
|
||||
|
||||
for _, dungeon := range dungeons {
|
||||
fmt.Printf("🔧 Generic Item Scaler\n")
|
||||
fmt.Printf("Source: %s\n", source.GetName())
|
||||
fmt.Printf("Target: Item Level %d, Quality %d, Phase %d, Catchup %.1fx\n", *itemLevel, *quality, *phase, *catchup)
|
||||
fmt.Printf("Processing %d items...\n\n", len(dbItems))
|
||||
|
||||
log.Printf("+++++Dungeon: %s ID: %v level %v \n", dungeon.Name, dungeon.Id, dungeon.Level)
|
||||
|
||||
bosses, err := models.DB.GetBosses(dungeon.Id)
|
||||
// Initialize SQL output if requested
|
||||
var sqlFile *os.File
|
||||
if *outputSQL {
|
||||
sqlFile, err = os.Create("scaled_items.sql")
|
||||
if err != nil {
|
||||
log.Fatal("failed to get bosses")
|
||||
log.Fatal("Failed to create SQL output file:", err)
|
||||
}
|
||||
defer sqlFile.Close()
|
||||
|
||||
// Determine the scale value of the item based on expansion and dungeon level
|
||||
scaleValue := *itemLevel
|
||||
endGameDung := false
|
||||
if dungeon.Level == 60 {
|
||||
scaleValue += 10
|
||||
endGameDung = true
|
||||
}
|
||||
sqlFile.WriteString("-- Generic Item Scaler Output\n")
|
||||
sqlFile.WriteString(fmt.Sprintf("-- Generated: %s\n", time.Now().Format("2006-01-02 15:04:05")))
|
||||
sqlFile.WriteString(fmt.Sprintf("-- Item Level: %d, Quality: %d, Phase: %d, Catchup: %.1fx\n\n", *itemLevel, *quality, *phase, *catchup))
|
||||
}
|
||||
|
||||
if dungeon.ExpansionId == 1 && dungeon.Level <= 70 {
|
||||
scaleValue += 3
|
||||
}
|
||||
// Process items
|
||||
successCount := 0
|
||||
for i, dbItem := range dbItems {
|
||||
fmt.Printf("[%d/%d] Processing: %s (Entry: %d)\n", i+1, len(dbItems), dbItem.Name, dbItem.Entry)
|
||||
|
||||
if dungeon.ExpansionId == 1 && dungeon.Level == 70 {
|
||||
scaleValue += 12
|
||||
endGameDung = true
|
||||
}
|
||||
// Store original for comparison
|
||||
originalItem := items.ItemFromDbItem(dbItem)
|
||||
|
||||
if dungeon.ExpansionId == 2 && dungeon.Level <= 80 {
|
||||
scaleValue += 4
|
||||
}
|
||||
result := scaler.ScaleItem(dbItem)
|
||||
|
||||
if dungeon.ExpansionId == 2 && dungeon.Level == 80 {
|
||||
scaleValue += 15
|
||||
endGameDung = true
|
||||
}
|
||||
if result.Success {
|
||||
successCount++
|
||||
fmt.Printf("✅ Successfully scaled %s\n", result.Item.Name)
|
||||
|
||||
// Apply difficuly modifiers for gear scale
|
||||
// mythic: Bosses-Epic Gear (Purple) drops and Rare (Blue) for random drops (BOE)
|
||||
// legendary: Bosses-Epic Gear (Purple) drops and Epic (Purple) for random drops (BOE)
|
||||
// ascendant: Bosses-Legendary Gear (Yellow) drops and Epic (Purple) for random drops (BOE)
|
||||
var bossQuality int
|
||||
var boeQuality int
|
||||
// Show comparison
|
||||
printScalingComparison(&originalItem, result.Item, result.ReferenceItem)
|
||||
|
||||
if *difficulty == 4 {
|
||||
bossQuality = 4
|
||||
boeQuality = 4
|
||||
} else if *difficulty == 5 {
|
||||
bossQuality = 5
|
||||
boeQuality = 4
|
||||
// Output SQL if requested
|
||||
if *outputSQL && sqlFile != nil {
|
||||
// Write item SQL
|
||||
sqlStatement := items.ItemToSql(*result.Item, *baseLevel, *difficulty, true)
|
||||
sqlFile.WriteString(sqlStatement + "\n")
|
||||
|
||||
// Write spell SQL for any scaled spells
|
||||
for _, spellSQL := range result.SpellSQL {
|
||||
sqlFile.WriteString(spellSQL + "\n")
|
||||
}
|
||||
}
|
||||
} else {
|
||||
bossQuality = 4
|
||||
boeQuality = 3
|
||||
}
|
||||
|
||||
for _, boss := range bosses {
|
||||
|
||||
items, err := models.DB.GetBossLoot(boss.Entry)
|
||||
log.Printf("++++++++++ Boss: %s Entry: %v has %v items\n", boss.Name, boss.Entry, len(items))
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
continue
|
||||
fmt.Printf("❌ Failed to scale %s\n", dbItem.Name)
|
||||
for _, errMsg := range result.Errors {
|
||||
fmt.Printf(" Error: %s\n", errMsg)
|
||||
}
|
||||
|
||||
for _, item := range items {
|
||||
|
||||
_, error := item.ScaleItem(scaleValue, bossQuality)
|
||||
if error != nil {
|
||||
log.Printf("Failed to scale item: %v", error)
|
||||
continue
|
||||
}
|
||||
|
||||
fmt.Printf("\n-- Item %v Entry: %v ItemLevel %v \n", item.Name, item.Entry, *item.ItemLevel)
|
||||
if *levelUp && endGameDung {
|
||||
fmt.Print(ItemToSql(item, *baselevel+1, *difficulty))
|
||||
} else {
|
||||
fmt.Print(ItemToSql(item, *baselevel, *difficulty))
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
items2, err := models.DB.GetAddlDungeonDrops(dungeon.Id)
|
||||
if err != nil {
|
||||
log.Printf("failed to get additional loot for dungeon %v - err: %v", dungeon.Id, err)
|
||||
for _, warning := range result.Warnings {
|
||||
fmt.Printf("⚠️ Warning: %s\n", warning)
|
||||
}
|
||||
|
||||
for _, item := range items2 {
|
||||
|
||||
// reduce item level of dungeon random drops since they are not boss fights
|
||||
adjScaleValue := scaleValue - 4
|
||||
|
||||
_, error := item.ScaleItem(adjScaleValue, boeQuality)
|
||||
if error != nil {
|
||||
log.Printf("Failed to scale item: %v", error)
|
||||
continue
|
||||
}
|
||||
|
||||
fmt.Printf("\n-- Item %v Entry: %v ItemLevel %v \n", item.Name, item.Entry, *item.ItemLevel)
|
||||
fmt.Print(ItemToSql(item, *baselevel, *difficulty))
|
||||
|
||||
}
|
||||
log.Printf("++++++++++ AdditionalLoot Count: %v\n", len(items2))
|
||||
fmt.Println()
|
||||
}
|
||||
|
||||
defer models.DB.Close()
|
||||
// Print summary
|
||||
fmt.Printf("🏆 Scaling Summary:\n")
|
||||
fmt.Printf("Total Items: %d\n", len(dbItems))
|
||||
fmt.Printf("Successful: %d\n", successCount)
|
||||
fmt.Printf("Failed: %d\n", len(dbItems)-successCount)
|
||||
fmt.Printf("Success Rate: %.1f%%\n", float64(successCount)/float64(len(dbItems))*100)
|
||||
|
||||
if *outputSQL {
|
||||
fmt.Printf("SQL Output: scaled_items.sql\n")
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,27 +0,0 @@
|
||||
package models
|
||||
|
||||
import (
|
||||
"os"
|
||||
|
||||
_ "github.com/go-sql-driver/mysql"
|
||||
"github.com/jmoiron/sqlx"
|
||||
)
|
||||
|
||||
type Database struct {
|
||||
client *sqlx.DB
|
||||
}
|
||||
|
||||
var DB Database
|
||||
|
||||
func Connect() {
|
||||
var connString string = os.Getenv("DB_USER") + ":" + os.Getenv("DB_PASSWORD") + "@tcp(" + os.Getenv("DB_HOST") + ")/" + os.Getenv("DB_NAME")
|
||||
var err error
|
||||
DB.client, err = sqlx.Open("mysql", connString)
|
||||
if err != nil {
|
||||
panic(err.Error())
|
||||
}
|
||||
}
|
||||
|
||||
func (db Database) Close() {
|
||||
db.client.Close()
|
||||
}
|
||||
@@ -1,106 +0,0 @@
|
||||
package models
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
|
||||
"github.com/araxiaonline/endgame-item-generator/utils"
|
||||
_ "github.com/go-sql-driver/mysql"
|
||||
_ "github.com/jmoiron/sqlx"
|
||||
)
|
||||
|
||||
type Boss struct {
|
||||
Entry int
|
||||
Name string
|
||||
ScriptName string `db:"ScriptName"`
|
||||
ExperienceModifier int `db:"ExperienceModifier"`
|
||||
}
|
||||
|
||||
func (db Database) GetBosses(mapId int) ([]Boss, error) {
|
||||
|
||||
if mapId == 0 {
|
||||
return nil, errors.New("mapId cannot be 0")
|
||||
}
|
||||
|
||||
bosses := []Boss{}
|
||||
var sql string
|
||||
|
||||
// 540 is pre-classic dungeons so XP Multiplier is best way to determine bosses / rare mobs
|
||||
if mapId < 540 {
|
||||
sql = `
|
||||
SELECT ct.entry, ct.name, ct.ScriptName, ct.ExperienceModifier from acore_world.creature c
|
||||
JOIN acore_world.creature_template ct ON(c.id1 = ct.entry) WHERE map = ? and ExperienceModifier >= 2;
|
||||
`
|
||||
} else {
|
||||
sql = `
|
||||
SELECT ct.entry, ct.name, ct.ScriptName, ct.ExperienceModifier from acore_world.creature c
|
||||
JOIN acore_world.creature_template ct ON(c.id1 = ct.entry) WHERE map = ? and ct.ScriptName Like 'boss_%'
|
||||
`
|
||||
}
|
||||
|
||||
err := db.client.Select(&bosses, sql, mapId)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return bosses, nil
|
||||
}
|
||||
|
||||
func (db Database) GetBossLoot(bossId int) ([]Item, error) {
|
||||
if bossId == 0 {
|
||||
return nil, errors.New("bossId cannot be 0")
|
||||
}
|
||||
|
||||
// This will first find items that are not in the reference boss loot table
|
||||
items := []Item{}
|
||||
sql := `
|
||||
SELECT ` + utils.GetItemFields("") + `
|
||||
from acore_world.item_template
|
||||
where
|
||||
entry in
|
||||
(SELECT item from acore_world.creature_loot_template where entry = ? and GroupId != 0 and Reference = 0)
|
||||
and Quality > 2
|
||||
`
|
||||
|
||||
udb := db.client.Unsafe()
|
||||
err := udb.Select(&items, sql, bossId)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// Get all the boss reference items now
|
||||
var references []int
|
||||
sql = `
|
||||
SELECT reference
|
||||
FROM acore_world.creature_loot_template
|
||||
WHERE entry = ? AND Reference != 0
|
||||
`
|
||||
err = db.client.Select(&references, sql, bossId)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to get references: %v sql %s", err, sql)
|
||||
}
|
||||
|
||||
if len(references) == 0 {
|
||||
return items, nil
|
||||
}
|
||||
|
||||
refItems := []Item{}
|
||||
|
||||
// For each reference we now need to get the items and add them to the items slice
|
||||
for _, ref := range references {
|
||||
sql = `
|
||||
SELECT ` + utils.GetItemFields("it") + `
|
||||
FROM acore_world.reference_loot_template rlt
|
||||
JOIN acore_world.item_template it ON rlt.Item = it.entry
|
||||
WHERE rlt.Entry = ? and it.Quality > 2 and it.StatsCount > 0
|
||||
`
|
||||
err = db.client.Select(&refItems, sql, ref)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to get ref items: %v sql %s", err, sql)
|
||||
}
|
||||
|
||||
items = append(items, refItems...)
|
||||
}
|
||||
|
||||
return items, nil
|
||||
}
|
||||
700
models/items.go
700
models/items.go
@@ -1,700 +0,0 @@
|
||||
package models
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"log"
|
||||
"math"
|
||||
"math/rand/v2"
|
||||
"reflect"
|
||||
|
||||
"github.com/araxiaonline/endgame-item-generator/utils"
|
||||
)
|
||||
|
||||
/**
|
||||
* For details about values of item int values use link below
|
||||
* @link https://www.azerothcore.org/wiki/item_template
|
||||
*/
|
||||
type Item struct {
|
||||
Entry int
|
||||
Name string
|
||||
DisplayId int `db:"displayid"`
|
||||
Quality *int
|
||||
ItemLevel *int `db:"ItemLevel"`
|
||||
Class *int
|
||||
Subclass *int
|
||||
Armor *int `db:"armor"`
|
||||
Material *int `db:"material"`
|
||||
InventoryType *int `db:"inventoryType"`
|
||||
AllowableClass *int `db:"allowableClass"`
|
||||
AllowableRace *int `db:"allowableRace"`
|
||||
RequiredSkill *int `db:"requiredSkill"`
|
||||
RequiredLevel *int `db:"requiredLevel"`
|
||||
Durability *int `db:"MaxDurability"`
|
||||
MinDmg1 *int `db:"dmg_min1"`
|
||||
MaxDmg1 *int `db:"dmg_max1"`
|
||||
MinDmg2 *int `db:"dmg_min2"`
|
||||
MaxDmg2 *int `db:"dmg_max2"`
|
||||
DmgType1 *int `db:"dmg_type1"`
|
||||
DmgType2 *int `db:"dmg_type2"`
|
||||
Delay *float64
|
||||
Sheath *int
|
||||
StatsCount *int `db:"statsCount"`
|
||||
StatType1 *int `db:"stat_type1"`
|
||||
StatValue1 *int `db:"stat_value1"`
|
||||
StatType2 *int `db:"stat_type2"`
|
||||
StatValue2 *int `db:"stat_value2"`
|
||||
StatType3 *int `db:"stat_type3"`
|
||||
StatValue3 *int `db:"stat_value3"`
|
||||
StatType4 *int `db:"stat_type4"`
|
||||
StatValue4 *int `db:"stat_value4"`
|
||||
StatType5 *int `db:"stat_type5"`
|
||||
StatValue5 *int `db:"stat_value5"`
|
||||
StatType6 *int `db:"stat_type6"`
|
||||
StatValue6 *int `db:"stat_value6"`
|
||||
StatType7 *int `db:"stat_type7"`
|
||||
StatValue7 *int `db:"stat_value7"`
|
||||
StatType8 *int `db:"stat_type8"`
|
||||
StatValue8 *int `db:"stat_value8"`
|
||||
StatType9 *int `db:"stat_type9"`
|
||||
StatValue9 *int `db:"stat_value9"`
|
||||
StatType10 *int `db:"stat_type10"`
|
||||
StatValue10 *int `db:"stat_value10"`
|
||||
SpellId1 *int `db:"spellid_1"`
|
||||
SpellId2 *int `db:"spellid_2"`
|
||||
SpellId3 *int `db:"spellid_3"`
|
||||
SpellTrigger1 *int `db:"spelltrigger_1"`
|
||||
SpellTrigger2 *int `db:"spelltrigger_2"`
|
||||
SpellTrigger3 *int `db:"spelltrigger_3"`
|
||||
StatsMap map[int]*ItemStat
|
||||
ConvStatCount int
|
||||
Spells []Spell
|
||||
}
|
||||
|
||||
// Use for storing item stats for all stats that will be scaled.
|
||||
type ItemStat struct {
|
||||
Value int
|
||||
Percent float64
|
||||
Type string
|
||||
AdjValue float64
|
||||
}
|
||||
|
||||
var InvTypeModifiers = map[int]float64{
|
||||
1: 0.813, // Head
|
||||
2: 1.0, // Neck
|
||||
3: 0.75, // Shoulder
|
||||
5: 1.0, // Chest
|
||||
6: 0.562, // Waist
|
||||
7: 0.875, // Legs
|
||||
8: 0.688, // Feet
|
||||
9: 0.437, // Wrists
|
||||
10: 0.625, // Hands
|
||||
11: 1.0, // Finger
|
||||
13: 0.42, // One-Hand (not to confuse with Off-Hand = 22)
|
||||
14: 0.56, // Shield (class = armor, not weapon even if in weapon slot)
|
||||
15: 0.32, // Ranged (Bows) (see also Ranged right = 26)
|
||||
16: 0.56, // Back
|
||||
17: 1.0, // Two-Hand
|
||||
18: 1.0, // Bag (assuming same as Chest for simplicity)
|
||||
19: 1.0, // Tabard (assuming same as Chest for simplicity)
|
||||
20: 1.0, // Robe (see also Chest = 5)
|
||||
21: 1.0, // Main hand
|
||||
22: 0.42, // Off Hand weapons (see also One-Hand = 13)
|
||||
23: 0.56, // Held in Off-Hand (class = armor, not weapon even if in weapon slot)
|
||||
24: 1.0, // Ammo (assuming same as Chest for simplicity)
|
||||
25: 0.32, // Thrown
|
||||
26: 0.32, // Ranged right (Wands, Guns) (see also Ranged = 15)
|
||||
27: 1.0, // Quiver (assuming same as Chest for simplicity)
|
||||
}
|
||||
|
||||
var QualityModifiers = map[int]float64{
|
||||
0: 1.0, // Common
|
||||
1: 1.1, // Uncommon
|
||||
2: 1.2, // Rare
|
||||
3: 1.3, // Epic
|
||||
4: 1.5, // Legendary
|
||||
5: 1.7, // Artifact
|
||||
}
|
||||
|
||||
var MaterialModifiers = map[int]float64{
|
||||
1: 1.2, // Cloth
|
||||
2: 2.2, // Leather
|
||||
3: 4.75, // Mail
|
||||
4: 9.0, // Plate
|
||||
6: 20.0, // Plate
|
||||
}
|
||||
|
||||
var StatModifiers = map[int]float64{
|
||||
0: 1.0, // ITEM_MOD_MANA
|
||||
1: 1.0, // ITEM_MOD_HEALTH
|
||||
3: 1.0, // ITEM_MOD_AGILITY
|
||||
4: 1.0, // ITEM_MOD_STRENGTH
|
||||
5: 1.0, // ITEM_MOD_INTELLECT
|
||||
6: 1.0, // ITEM_MOD_SPIRIT
|
||||
7: 1.0, // ITEM_MOD_STAMINA
|
||||
12: 1.0, // ITEM_MOD_DEFENSE_SKILL_RATING
|
||||
13: 1.0, // ITEM_MOD_DODGE_RATING
|
||||
14: 1.0, // ITEM_MOD_PARRY_RATING
|
||||
15: 1.0, // ITEM_MOD_BLOCK_RATING
|
||||
16: 1.0, // ITEM_MOD_HIT_MELEE_RATING
|
||||
17: 1.0, // ITEM_MOD_HIT_RANGED_RATING
|
||||
18: 1.0, // ITEM_MOD_HIT_SPELL_RATING
|
||||
19: 1.0, // ITEM_MOD_CRIT_MELEE_RATING
|
||||
20: 1.0, // ITEM_MOD_CRIT_RANGED_RATING
|
||||
21: 1.0, // ITEM_MOD_CRIT_SPELL_RATING
|
||||
22: 1.0, // ITEM_MOD_HIT_TAKEN_MELEE_RATING
|
||||
23: 1.0, // ITEM_MOD_HIT_TAKEN_RANGED_RATING
|
||||
24: 1.0, // ITEM_MOD_HIT_TAKEN_SPELL_RATING
|
||||
25: 1.0, // ITEM_MOD_CRIT_TAKEN_MELEE_RATING
|
||||
26: 1.0, // ITEM_MOD_CRIT_TAKEN_RANGED_RATING
|
||||
27: 1.0, // ITEM_MOD_CRIT_TAKEN_SPELL_RATING
|
||||
28: 1.0, // ITEM_MOD_HASTE_MELEE_RATING
|
||||
29: 1.0, // ITEM_MOD_HASTE_RANGED_RATING
|
||||
30: 1.0, // ITEM_MOD_HASTE_SPELL_RATING
|
||||
31: 1.0, // ITEM_MOD_HIT_RATING
|
||||
32: 1.0, // ITEM_MOD_CRIT_RATING
|
||||
33: 1.0, // ITEM_MOD_HIT_TAKEN_RATING
|
||||
34: 1.0, // ITEM_MOD_CRIT_TAKEN_RATING
|
||||
35: 1.0, // ITEM_MOD_RESILIENCE_RATING
|
||||
36: 1.0, // ITEM_MOD_HASTE_RATING
|
||||
37: 1.0, // ITEM_MOD_EXPERTISE_RATING
|
||||
38: 0.5, // ITEM_MOD_ATTACK_POWER
|
||||
39: 0.5, // ITEM_MOD_RANGED_ATTACK_POWER
|
||||
40: 0.5, // ITEM_MOD_FERAL_ATTACK_POWER (not used as of 3.3)
|
||||
41: 0.5, // ITEM_MOD_SPELL_HEALING_DONE
|
||||
42: 0.5, // ITEM_MOD_SPELL_DAMAGE_DONE
|
||||
43: 2.5, // ITEM_MOD_MANA_REGENERATION
|
||||
44: 1.0, // ITEM_MOD_ARMOR_PENETRATION_RATING
|
||||
45: 0.5, // ITEM_MOD_SPELL_POWER
|
||||
46: 1.0, // ITEM_MOD_HEALTH_REGEN
|
||||
47: 2.0, // ITEM_MOD_SPELL_PENETRATION
|
||||
48: 0.65, // ITEM_MOD_BLOCK_VALUE
|
||||
}
|
||||
|
||||
func (item Item) GetPrimaryStat() (int, int, error) {
|
||||
var primaryStat int64
|
||||
var primaryVal int64
|
||||
|
||||
values := reflect.ValueOf(item)
|
||||
for i := 1; i < 11; i++ {
|
||||
statType := values.FieldByName(fmt.Sprintf("StatType%v", i)).Elem().Int()
|
||||
// first check if the stat type is not in the primary stats str, agi, intellect, spirit, stamina
|
||||
if statType < 3 || statType > 7 {
|
||||
continue
|
||||
}
|
||||
|
||||
statValue := values.FieldByName(fmt.Sprintf("StatValue%v", i)).Elem().Int()
|
||||
if statValue > primaryVal {
|
||||
primaryVal = statValue
|
||||
primaryStat = statType
|
||||
}
|
||||
}
|
||||
|
||||
return int(primaryStat), int(primaryVal), nil
|
||||
}
|
||||
|
||||
func (i Item) GetDpsModifier() (float64, error) {
|
||||
if i.Subclass == nil {
|
||||
return 0, fmt.Errorf("subclass on the item is not set")
|
||||
}
|
||||
|
||||
if i.Quality == nil {
|
||||
return 0, fmt.Errorf("quality is not set")
|
||||
}
|
||||
|
||||
typeModifier := 0.0
|
||||
// Is a One-Handed Weapon
|
||||
if *i.Subclass == 0 || *i.Subclass == 4 || *i.Subclass == 13 || *i.Subclass == 15 || *i.Subclass == 7 {
|
||||
typeModifier = 0.64
|
||||
}
|
||||
|
||||
// Is a Two-Handed Weapon
|
||||
if *i.Subclass == 1 || *i.Subclass == 5 || *i.Subclass == 6 || *i.Subclass == 8 || *i.Subclass == 10 || *i.Subclass == 17 {
|
||||
typeModifier = 0.80
|
||||
}
|
||||
|
||||
// Ranged Weapons
|
||||
if *i.Subclass == 2 || *i.Subclass == 3 || *i.Subclass == 16 || *i.Subclass == 18 {
|
||||
typeModifier = 0.70
|
||||
}
|
||||
|
||||
// Wands
|
||||
if *i.Subclass == 19 {
|
||||
typeModifier = 0.70
|
||||
}
|
||||
|
||||
qualityModifier := 1.0
|
||||
|
||||
// Add the quality modifier for the DPS calculation
|
||||
if *i.Quality == 2 {
|
||||
qualityModifier = 1.25
|
||||
}
|
||||
if *i.Quality == 3 {
|
||||
qualityModifier = 1.38
|
||||
}
|
||||
if *i.Quality == 4 {
|
||||
qualityModifier = 1.5
|
||||
}
|
||||
|
||||
if typeModifier == 0 {
|
||||
return 0, fmt.Errorf("Item subclass is not a weapon %v", *i.Subclass)
|
||||
}
|
||||
|
||||
return (qualityModifier * typeModifier), nil
|
||||
}
|
||||
|
||||
// Get the current expected DPS of the item bsed on the min and max damage and delay
|
||||
func (item Item) GetDPS() (float64, error) {
|
||||
|
||||
if item.MinDmg1 == nil || item.MaxDmg1 == nil {
|
||||
return 0, fmt.Errorf("MinDmg1 or MaxDmg1 is not set")
|
||||
}
|
||||
|
||||
if item.Delay == nil {
|
||||
return 0, fmt.Errorf("delay is not set")
|
||||
}
|
||||
|
||||
dps := math.Round((float64(*item.MinDmg1+*item.MaxDmg1)/2.0)/float64(*item.Delay/1000)*100) / 100
|
||||
return dps, nil
|
||||
}
|
||||
|
||||
// Scales and items dps damage numbers based on a desired item level.
|
||||
func (item *Item) ScaleDPS(level int) (float64, error) {
|
||||
if item.ItemLevel == nil {
|
||||
return 0, fmt.Errorf("ItemLevel is not set")
|
||||
}
|
||||
|
||||
if item.Delay == nil {
|
||||
return 0, fmt.Errorf("delay is not set")
|
||||
}
|
||||
|
||||
modifier, err := item.GetDpsModifier()
|
||||
if err != nil {
|
||||
log.Fatalf("Error getting DPS modifier: %v", err)
|
||||
return 0.0, err
|
||||
}
|
||||
|
||||
dps := modifier * float64(level)
|
||||
adjDps := (dps * (*item.Delay / 1000) / 100)
|
||||
|
||||
//(((Y8*Y4)/100))*((100 - Y5)) Forumula from Weapon Item Genertor
|
||||
minimum := adjDps * float64(100-(rand.IntN(15)+22))
|
||||
maximum := adjDps * float64(100+(rand.IntN(15)+22))
|
||||
|
||||
// If the weapon has secondary damage, scale that as well based on the ratio of the primary damage
|
||||
if item.MinDmg2 != nil && item.MaxDmg2 != nil {
|
||||
ratioMin := float64(*item.MinDmg2) / float64(*item.MinDmg1)
|
||||
ratioMax := float64(*item.MaxDmg2) / float64(*item.MaxDmg1)
|
||||
minimum2 := int(ratioMin * float64(minimum))
|
||||
maximum2 := int(ratioMax * float64(maximum))
|
||||
|
||||
item.MinDmg2 = &minimum2
|
||||
item.MaxDmg2 = &maximum2
|
||||
|
||||
// In order to balance the original scale of the secondary damage from primary
|
||||
minimum = minimum - float64(minimum2)*0.75
|
||||
maximum = maximum - float64(maximum2)*0.75
|
||||
|
||||
}
|
||||
|
||||
// item.MinDmg1 = &minimum
|
||||
var min int = int(minimum)
|
||||
var max int = int(maximum)
|
||||
item.MinDmg1 = &min
|
||||
item.MaxDmg1 = &max
|
||||
|
||||
return dps, nil
|
||||
}
|
||||
|
||||
func (d Database) GetItem(entry int) (Item, error) {
|
||||
if entry == 0 {
|
||||
return Item{}, fmt.Errorf("entry cannot be 0")
|
||||
}
|
||||
|
||||
item := Item{}
|
||||
sql := "SELECT " + utils.GetItemFields("") + " FROM item_template WHERE entry = ?"
|
||||
err := d.client.Get(&item, sql, entry)
|
||||
if err != nil {
|
||||
return Item{}, err
|
||||
}
|
||||
|
||||
return item, nil
|
||||
}
|
||||
|
||||
// Create a Map of stat percentages based on the current stat and how budgets are caluated
|
||||
func (item Item) GetStatPercents(spellStats []ConvItemStat) map[int]*ItemStat {
|
||||
|
||||
statMap := make(map[int]*ItemStat)
|
||||
statBudget := 0.0
|
||||
|
||||
values := reflect.ValueOf(item)
|
||||
for i := 1; i < 11; i++ {
|
||||
var statValue = values.FieldByName(fmt.Sprintf("StatValue%v", i)).Elem().Int()
|
||||
var statType = values.FieldByName(fmt.Sprintf("StatType%v", i)).Elem().Int()
|
||||
if statValue == 0 {
|
||||
continue
|
||||
}
|
||||
|
||||
adjValue := float64(statValue) / StatModifiers[int(statType)]
|
||||
statBudget += adjValue
|
||||
statMap[int(statType)] = &ItemStat{
|
||||
Value: int(statValue),
|
||||
Percent: 0.0,
|
||||
Type: "Item",
|
||||
AdjValue: adjValue,
|
||||
}
|
||||
}
|
||||
|
||||
// Calculate the total budget for the spell stats if we have some
|
||||
for _, spellStat := range spellStats {
|
||||
statBudget += float64(spellStat.Budget)
|
||||
statMap[spellStat.StatType] = &ItemStat{
|
||||
Value: spellStat.StatValue,
|
||||
Percent: 0.0,
|
||||
Type: "Spell",
|
||||
AdjValue: float64(spellStat.Budget),
|
||||
}
|
||||
}
|
||||
|
||||
// Combine all stats and calculate percentages for each stat
|
||||
for statId, stat := range statMap {
|
||||
statMap[statId].Percent = math.Round(float64(stat.AdjValue)/statBudget*100) / 100
|
||||
}
|
||||
|
||||
return statMap
|
||||
}
|
||||
|
||||
// get an array of all the spells set on the item
|
||||
func (item *Item) GetSpells() ([]Spell, error) {
|
||||
// dont reload for the same item .
|
||||
if len(item.Spells) > 0 {
|
||||
return item.Spells, nil
|
||||
}
|
||||
|
||||
spells := []Spell{}
|
||||
values := reflect.ValueOf(item)
|
||||
for i := 1; i < 4; i++ {
|
||||
spellId := values.Elem().FieldByName(fmt.Sprintf("SpellId%v", i)).Elem().Int()
|
||||
if spellId == 0 {
|
||||
continue
|
||||
}
|
||||
|
||||
if spellId == -1 {
|
||||
continue
|
||||
}
|
||||
|
||||
spell, err := DB.GetSpell(int(spellId))
|
||||
if err != nil {
|
||||
log.Printf("failed to get the spell: %v error: %v", spellId, err)
|
||||
continue
|
||||
}
|
||||
|
||||
spells = append(spells, spell)
|
||||
}
|
||||
item.Spells = spells
|
||||
return spells, nil
|
||||
}
|
||||
|
||||
func (item *Item) GetNonStatSpells() ([]Spell, error) {
|
||||
nonStatSpells := []Spell{}
|
||||
for i := 1; i < 4; i++ {
|
||||
spellId, err := item.GetField(fmt.Sprintf("SpellId%v", i))
|
||||
|
||||
if err != nil {
|
||||
log.Printf("Failed to get spell id %v", i)
|
||||
continue
|
||||
}
|
||||
|
||||
if spellId == 0 {
|
||||
continue
|
||||
}
|
||||
spell, err := DB.GetSpell(spellId)
|
||||
if err != nil {
|
||||
log.Printf("Failed to get spell %v", spellId)
|
||||
continue
|
||||
}
|
||||
|
||||
// Need to handle extended spell casts basically when a spell casts another spell and the base points are there
|
||||
// instead of with the item itself.
|
||||
// Can just create a new spell with base points, type and remove triggerspell and see what happens?
|
||||
// For now just skip anything not in our list.
|
||||
if spell.EffectAura1 == 42 || spell.EffectAura2 == 42 || spell.EffectAura3 == 42 {
|
||||
continue
|
||||
}
|
||||
|
||||
spell.ItemSpellSlot = i
|
||||
nonStatSpells = append(nonStatSpells, spell)
|
||||
}
|
||||
return nonStatSpells, nil
|
||||
}
|
||||
|
||||
// Stat Formula scaler
|
||||
// Ceiling of ((ItemLevel * QualityModifier * ItemTypeModifier)^1.7095 * %ofStats) ^ (1/1.7095)) / StatModifier
|
||||
// i.e) Green Strength Helmet (((100 * 1.1 * 1.0)^1.705) * 1)^(1/1.7095) / 1.0 = 110 Strength on item
|
||||
func (item *Item) ScaleItem(itemLevel int, itemQuality int) (bool, error) {
|
||||
var allSpellStats []ConvItemStat
|
||||
if item.ItemLevel == nil {
|
||||
return false, errors.New("field itemLevel is not set")
|
||||
}
|
||||
|
||||
if item.Quality == nil {
|
||||
return false, errors.New("field quality is not set")
|
||||
}
|
||||
|
||||
fromItemLevel := *item.ItemLevel
|
||||
*item.ItemLevel = itemLevel
|
||||
|
||||
// if an item quality is being forced than use it intead
|
||||
if itemQuality != 0 {
|
||||
*item.Quality = itemQuality
|
||||
}
|
||||
|
||||
log.Printf("Scaling item %v %v to item level %v and quality %v", item.Name, item.Entry, itemLevel, *item.Quality)
|
||||
|
||||
// Get all the spell Stats on the item we can convert
|
||||
spells, err := item.GetSpells()
|
||||
if err != nil {
|
||||
log.Printf("Failed to get spells for item: %v", err)
|
||||
return false, err
|
||||
}
|
||||
|
||||
for i := 0; i < len(spells); i++ {
|
||||
|
||||
log.Printf("Spell %v (%v) Effect %v AuraEffect %v Spell Desc: %v basePoints %v", spells[i].Name, spells[i].ID, spells[i].Effect1, spells[i].EffectAura1, spells[i].Description, spells[i].EffectBasePoints1)
|
||||
|
||||
convStats, err := spells[i].ConvertToStats()
|
||||
if err != nil {
|
||||
log.Printf("Failed to convert spell to stats: %v for spell %v", err, spells[i].Name)
|
||||
continue
|
||||
}
|
||||
|
||||
if len(convStats) != 0 {
|
||||
item.UpdateField(fmt.Sprintf("SpellId%v", i+1), 0)
|
||||
}
|
||||
|
||||
allSpellStats = append(allSpellStats, convStats...)
|
||||
}
|
||||
|
||||
allStats := item.GetStatPercents(allSpellStats)
|
||||
for statId, stat := range allStats {
|
||||
origValue := stat.Value
|
||||
|
||||
stat.Value = scaleStat(itemLevel, *item.InventoryType, *item.Quality, stat.Percent, StatModifiers[statId])
|
||||
|
||||
log.Printf(">>>>>> Scaled : StatId: %v Type: %s Orig: %v - New Value: %v Percent: %v", statId, stat.Type, origValue, stat.Value, stat.Percent)
|
||||
}
|
||||
|
||||
item.addStats(allStats)
|
||||
*item.StatsCount = len(allStats)
|
||||
|
||||
// Scale Armor Stats
|
||||
if *item.Class == 4 && *item.Armor > 0 {
|
||||
preArmor := *item.Armor
|
||||
*item.Armor = int(math.Ceil(float64(itemLevel) * QualityModifiers[*item.Quality] * MaterialModifiers[*item.Subclass]))
|
||||
|
||||
log.Printf("New Armor: %v scaled up from previous armor %v material is %v", *item.Armor, preArmor, *item.Material)
|
||||
}
|
||||
|
||||
// If the item is a weapon scale the DPS
|
||||
if *item.Class == 2 && *item.MinDmg1 > 0 {
|
||||
predps, err := item.GetDPS()
|
||||
if err != nil {
|
||||
log.Printf("Failed to get DPS: %v", err)
|
||||
}
|
||||
|
||||
dps, err := item.ScaleDPS(itemLevel)
|
||||
if err != nil {
|
||||
log.Printf("Failed to scale DPS: %v", err)
|
||||
return false, err
|
||||
}
|
||||
log.Printf("DPS: %.1f scaled up from previous dps %v", dps, predps)
|
||||
}
|
||||
|
||||
item.cleanSpells()
|
||||
|
||||
// Item is scaled now we have to determine if there are additional spell effects that need scaled.
|
||||
// this will be as simple as possible as the effects will just be a percentage of the item stats.
|
||||
// This could lead to some OP weapons that will need tuned down later. But for now, we will just scale at a
|
||||
// An example of this might on hit do $s1 nature damage over $d seconds. We would just scale the $s1 value
|
||||
// based on the formula below. This assumes that Blizzard has already balanced the spell bonus against the
|
||||
// stats on the item level and quality. This is a big assumption as the stats are not penalized
|
||||
// from having the extra damage. This could really create some unique sought after weapons that exploit this.
|
||||
// modified ratio ((s1 / existing iLevel) * newIlevel) * (0.20 Rare or 0.30 Epic or 0.4 for Legendary).
|
||||
|
||||
otherSpells, err := item.GetNonStatSpells()
|
||||
if err != nil {
|
||||
log.Printf("failed to get non stat spells: %v", err)
|
||||
}
|
||||
|
||||
log.Printf("\n\n\n -------------------- COUNT OF other spells %v \n\n", len(otherSpells))
|
||||
|
||||
item.Spells = []Spell{}
|
||||
// Spells that can not be scaled into stats must get new spells scaled and created
|
||||
for _, spell := range otherSpells {
|
||||
log.Printf(" --^^^^^^--------SPELL --- Spell %v (%v) Effect %v AuraEffect %v Spell Desc: %v basePoints %v", spell.Name, spell.ID, spell.Effect1, spell.EffectAura1, spell.Description, spell.EffectBasePoints1)
|
||||
newId, err := spell.ScaleSpell(fromItemLevel, itemLevel, *item.Quality)
|
||||
if err != nil {
|
||||
log.Printf("Failed to scale spell: %v, Spell %v", err, spell.ID)
|
||||
continue
|
||||
}
|
||||
|
||||
if newId == 0 {
|
||||
log.Printf("Failed to scale spell: %v, Spell %v", err, spell.ID)
|
||||
continue
|
||||
}
|
||||
|
||||
item.UpdateField(fmt.Sprintf("SpellId%v", spell.ItemSpellSlot), newId)
|
||||
item.Spells = append(item.Spells, spell)
|
||||
|
||||
log.Printf(" --SCALED---SPELL --- Spell %v (%v) Effect %v AuraEffect %v Spell Desc: %v basePoints %v", spell.Name, spell.ID, spell.Effect1, spell.EffectAura1, spell.Description, spell.EffectBasePoints1)
|
||||
}
|
||||
|
||||
return true, nil
|
||||
|
||||
}
|
||||
|
||||
func (item *Item) GetField(fieldName string) (int, error) {
|
||||
itemValue := reflect.ValueOf(item).Elem()
|
||||
field := itemValue.FieldByName(fieldName)
|
||||
if !field.IsValid() {
|
||||
return 0, fmt.Errorf("failed to find field %s", fieldName)
|
||||
}
|
||||
|
||||
switch field.Kind() {
|
||||
case reflect.Ptr:
|
||||
if field.IsNil() {
|
||||
return 0, fmt.Errorf("field %s is nil", fieldName)
|
||||
}
|
||||
return int(field.Elem().Int()), nil
|
||||
default:
|
||||
return 0, fmt.Errorf("field %s is not a pointer", fieldName)
|
||||
}
|
||||
}
|
||||
|
||||
// Updates a dynamic field on the item struct useful for stat replacements or spells
|
||||
func (item *Item) UpdateField(fieldName string, value int) {
|
||||
itemValue := reflect.ValueOf(item).Elem()
|
||||
field := itemValue.FieldByName(fieldName)
|
||||
if !field.IsValid() {
|
||||
log.Printf("failed to find field %s", fieldName)
|
||||
return
|
||||
}
|
||||
|
||||
switch field.Kind() {
|
||||
case reflect.Ptr:
|
||||
newValue := reflect.ValueOf(&value)
|
||||
field.Set(newValue)
|
||||
default:
|
||||
}
|
||||
}
|
||||
|
||||
func (item *Item) emptyStats() {
|
||||
*item.StatType1 = 0
|
||||
*item.StatValue1 = 0
|
||||
*item.StatType2 = 0
|
||||
*item.StatValue2 = 0
|
||||
*item.StatType3 = 0
|
||||
*item.StatValue3 = 0
|
||||
*item.StatType4 = 0
|
||||
*item.StatValue4 = 0
|
||||
*item.StatType5 = 0
|
||||
*item.StatValue5 = 0
|
||||
*item.StatType6 = 0
|
||||
*item.StatValue6 = 0
|
||||
*item.StatType7 = 0
|
||||
*item.StatValue7 = 0
|
||||
*item.StatType8 = 0
|
||||
*item.StatValue8 = 0
|
||||
*item.StatType9 = 0
|
||||
*item.StatValue9 = 0
|
||||
*item.StatType10 = 0
|
||||
*item.StatValue10 = 0
|
||||
}
|
||||
|
||||
// Cleans up spells from the item that have been converted to stats and leaves only the ones that are not
|
||||
func (item *Item) cleanSpells() {
|
||||
for i := 1; i < 3; i++ {
|
||||
currentId, err := item.GetField(fmt.Sprintf("SpellId%v", i))
|
||||
|
||||
log.Printf("Checking spell id %v - value %v", i, currentId)
|
||||
if err != nil {
|
||||
log.Printf("ERROR: Failed to get spell id %v err: %v", i, err)
|
||||
continue
|
||||
}
|
||||
|
||||
// if there no spellId set then check the next one if it is set move it and clear it
|
||||
if currentId == 0 {
|
||||
nextSpellId, err := item.GetField(fmt.Sprintf("SpellId%v", i+1))
|
||||
if err != nil {
|
||||
log.Printf("ERROR: Failed to get spell id %v err: %v", i+1, err)
|
||||
}
|
||||
|
||||
if nextSpellId != 0 {
|
||||
item.UpdateField(fmt.Sprintf("SpellId%v", i), nextSpellId)
|
||||
item.UpdateField(fmt.Sprintf("SpellId%v", i+1), 0)
|
||||
log.Printf("Moved spell %v to %v to replace removed spell", nextSpellId, i)
|
||||
continue
|
||||
}
|
||||
|
||||
continue
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
func (item *Item) addStats(stats map[int]*ItemStat) {
|
||||
item.emptyStats()
|
||||
i := 1
|
||||
|
||||
// itemValue := reflect.ValueOf(item).Elem() // Get value of underlying struct
|
||||
|
||||
for statId, stat := range stats {
|
||||
if i > 10 {
|
||||
break
|
||||
}
|
||||
|
||||
statTypeField := fmt.Sprintf("StatType%d", i)
|
||||
statValueField := fmt.Sprintf("StatValue%d", i)
|
||||
|
||||
// MP5 adjustment
|
||||
if statId == 43 {
|
||||
stat.Value = int(math.Round(float64(stat.Value) * 0.5))
|
||||
}
|
||||
|
||||
if statId == 12 {
|
||||
stat.Value = int(math.Round(float64(stat.Value) * 0.5))
|
||||
}
|
||||
|
||||
if statId == 12 {
|
||||
stat.Value = int(math.Round(float64(stat.Value) * 0.75))
|
||||
}
|
||||
|
||||
if statId == 13 {
|
||||
stat.Value = int(math.Round(float64(stat.Value) * 0.65))
|
||||
}
|
||||
|
||||
if statId == 31 {
|
||||
stat.Value = int(math.Round(float64(stat.Value) * 0.55))
|
||||
}
|
||||
|
||||
// Update the item with new stats from scaling
|
||||
item.UpdateField(statTypeField, statId)
|
||||
item.UpdateField(statValueField, stat.Value)
|
||||
|
||||
// Get the stats for logging purposes
|
||||
// tmpType, _ := item.GetField(statTypeField)
|
||||
// tmpStat, _ := item.GetField(statValueField)
|
||||
// log.Printf("Updated %s to %v, %s to %v", statTypeField, tmpType, statValueField, tmpStat)
|
||||
|
||||
i++
|
||||
}
|
||||
}
|
||||
|
||||
// Scale formula ((ItemLevel * QualityModifier * ItemTypeModifier)^1.7095 * %ofStats) ^ (1/1.7095)) / StatModifier
|
||||
func scaleStat(itemLevel int, itemType int, itemQuality int, percOfStat float64, statModifier float64) int {
|
||||
scaledUp := math.Pow((float64(itemLevel)*QualityModifiers[itemQuality]*InvTypeModifiers[itemType]), 1.7095) * percOfStat
|
||||
|
||||
// leaving modifier off for now but not changing signature in case I need to add it back
|
||||
_ = statModifier
|
||||
return int(math.Ceil(math.Pow(scaledUp, 1/1.7095))) // normalized
|
||||
}
|
||||
466
models/spells.go
466
models/spells.go
@@ -1,466 +0,0 @@
|
||||
package models
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"log"
|
||||
"math"
|
||||
"strconv"
|
||||
"strings"
|
||||
|
||||
"github.com/araxiaonline/endgame-item-generator/utils"
|
||||
"github.com/thoas/go-funk"
|
||||
)
|
||||
|
||||
// list of spell effects that require scaling
|
||||
var SpellEffects = [...]int{
|
||||
2, // School Damage
|
||||
6, // AppyAura
|
||||
9, // HealthLeech
|
||||
10, // Heal
|
||||
30, // Restores Mana
|
||||
35, // Apply Area Aura
|
||||
}
|
||||
|
||||
// list of spell aura effects that require scaling
|
||||
var SpellAuraEffects = [...]int{
|
||||
3, // DOT
|
||||
8, // HOT
|
||||
13, // Modifies Spell Damage Done
|
||||
15, // Modifies Damage Shield
|
||||
22, // Modifies Resistance
|
||||
34, // Modifies HEalth
|
||||
85, // Modifies Mana Regen
|
||||
99, // Modifies Attack Power
|
||||
124, // Modifies Range Attack Power
|
||||
135, // Modifies Healing Done
|
||||
189, // Modifies Critical Strike
|
||||
}
|
||||
|
||||
var AuraEffectsStatMap = map[int]int{
|
||||
8: 46,
|
||||
13: 45,
|
||||
85: 43,
|
||||
99: 38,
|
||||
124: 38,
|
||||
135: 45,
|
||||
}
|
||||
|
||||
// Usually in EffectMiscValueA to describe what the Aura modifies
|
||||
var SpellModifiers = [...]int{
|
||||
0, // damage
|
||||
1, // duration
|
||||
2, // threat
|
||||
3, // effect1
|
||||
4, // charges
|
||||
5, // range
|
||||
6, // radius
|
||||
7, // crit chance
|
||||
8, // all effects
|
||||
9, // No pushback
|
||||
10, // Cast Time
|
||||
11, // CD
|
||||
12, // effect2
|
||||
13, // ignore armor
|
||||
14, // cost
|
||||
15, // crit damage bonus
|
||||
16, // resist miss chance
|
||||
17, // jump targets
|
||||
18, // Chance of success
|
||||
19, // Amplitude
|
||||
20, // Dmg multiplier
|
||||
21, // GCD
|
||||
22, // DoT
|
||||
23, // effect3
|
||||
24, // bonus multiplier
|
||||
26, // PPM
|
||||
27, // value multiplier
|
||||
28, // resist dispel chance
|
||||
29, // crit damage bonus 2
|
||||
}
|
||||
|
||||
// result of a stat conversion from spell to raw stats on item
|
||||
type ConvItemStat struct {
|
||||
StatType int
|
||||
StatValue int
|
||||
Budget int
|
||||
}
|
||||
|
||||
// Spell Effect with max value for effect storage
|
||||
type SpellEffect struct {
|
||||
Effect int
|
||||
BasePoints int
|
||||
DieSides int
|
||||
CalculatedMax int
|
||||
}
|
||||
|
||||
// DB Mapping from spell_dbc
|
||||
type Spell struct {
|
||||
ID int `db:"ID"`
|
||||
Name string `db:"Name_Lang_enUS"`
|
||||
Description string `db:"Description_Lang_enUS"`
|
||||
AuraDescription string `db:"AuraDescription_Lang_enUS"`
|
||||
ProcChance int `db:"ProcChance"`
|
||||
SpellLevel int `db:"SpellLevel"`
|
||||
Effect1 int `db:"Effect_1"`
|
||||
Effect2 int `db:"Effect_2"`
|
||||
Effect3 int `db:"Effect_3"`
|
||||
EffectDieSides1 int `db:"EffectDieSides_1"`
|
||||
EffectDieSides2 int `db:"EffectDieSides_2"`
|
||||
EffectDieSides3 int `db:"EffectDieSides_3"`
|
||||
EffectRealPointsPerLevel1 int `db:"EffectRealPointsPerLevel_1"`
|
||||
EffectRealPointsPerLevel2 int `db:"EffectRealPointsPerLevel_2"`
|
||||
EffectRealPointsPerLevel3 int `db:"EffectRealPointsPerLevel_3"`
|
||||
EffectBasePoints1 int `db:"EffectBasePoints_1"`
|
||||
EffectBasePoints2 int `db:"EffectBasePoints_2"`
|
||||
EffectBasePoints3 int `db:"EffectBasePoints_3"`
|
||||
EffectAura1 int `db:"EffectAura_1"`
|
||||
EffectAura2 int `db:"EffectAura_2"`
|
||||
EffectAura3 int `db:"EffectAura_3"`
|
||||
EffectBonusMultiplier1 int `db:"EffectBonusMultiplier_1"`
|
||||
EffectBonusMultiplier2 int `db:"EffectBonusMultiplier_2"`
|
||||
EffectBonusMultiplier3 int `db:"EffectBonusMultiplier_3"`
|
||||
ItemSpellSlot int
|
||||
Scaled bool
|
||||
}
|
||||
|
||||
func (db Database) GetSpell(id int) (Spell, error) {
|
||||
|
||||
if id == 0 {
|
||||
return Spell{}, fmt.Errorf("id cannot be 0")
|
||||
}
|
||||
|
||||
spell := Spell{}
|
||||
sql := "SELECT " + utils.GetSpellFields() + " FROM `spell_dbc` WHERE ID = ? -- " + strconv.Itoa(id)
|
||||
|
||||
err := db.client.Get(&spell, sql, id)
|
||||
if err != nil {
|
||||
return Spell{}, fmt.Errorf("failed to get spell: %v", err)
|
||||
}
|
||||
|
||||
return spell, nil
|
||||
}
|
||||
|
||||
func calcMaxValue(base int, sides int) int {
|
||||
if base < 0 {
|
||||
return base - sides
|
||||
}
|
||||
|
||||
return base + sides
|
||||
}
|
||||
|
||||
// get a List of the spell effects (not auras) that need to be scaled
|
||||
func (s Spell) GetSpellEffects() []SpellEffect {
|
||||
effects := make([]SpellEffect, 0)
|
||||
|
||||
effects = append(effects, SpellEffect{
|
||||
Effect: s.Effect1,
|
||||
BasePoints: s.EffectBasePoints1,
|
||||
DieSides: s.EffectDieSides1,
|
||||
CalculatedMax: calcMaxValue(s.EffectBasePoints1, s.EffectDieSides1),
|
||||
})
|
||||
|
||||
effects = append(effects, SpellEffect{
|
||||
Effect: s.Effect2,
|
||||
BasePoints: s.EffectBasePoints2,
|
||||
DieSides: s.EffectDieSides2,
|
||||
CalculatedMax: calcMaxValue(s.EffectBasePoints2, s.EffectDieSides2),
|
||||
})
|
||||
|
||||
effects = append(effects, SpellEffect{
|
||||
Effect: s.Effect3,
|
||||
BasePoints: s.EffectBasePoints3,
|
||||
DieSides: s.EffectDieSides3,
|
||||
CalculatedMax: calcMaxValue(s.EffectBasePoints3, s.EffectDieSides3),
|
||||
})
|
||||
|
||||
return effects
|
||||
}
|
||||
|
||||
// Get he effects and calculate the max value for the a
|
||||
func (s Spell) GetAuraEffects() []SpellEffect {
|
||||
effects := make([]SpellEffect, 0)
|
||||
|
||||
effects = append(effects, SpellEffect{
|
||||
Effect: s.EffectAura1,
|
||||
BasePoints: s.EffectBasePoints1,
|
||||
DieSides: s.EffectDieSides1,
|
||||
CalculatedMax: calcMaxValue(s.EffectBasePoints1, s.EffectDieSides1),
|
||||
})
|
||||
|
||||
effects = append(effects, SpellEffect{
|
||||
Effect: s.EffectAura2,
|
||||
BasePoints: s.EffectBasePoints2,
|
||||
DieSides: s.EffectDieSides2,
|
||||
CalculatedMax: calcMaxValue(s.EffectBasePoints2, s.EffectDieSides2),
|
||||
})
|
||||
|
||||
effects = append(effects, SpellEffect{
|
||||
Effect: s.EffectAura3,
|
||||
BasePoints: s.EffectBasePoints3,
|
||||
DieSides: s.EffectDieSides3,
|
||||
CalculatedMax: calcMaxValue(s.EffectBasePoints3, s.EffectDieSides3),
|
||||
})
|
||||
|
||||
return effects
|
||||
}
|
||||
|
||||
// this spell effect has stats or effects that need to be scaled
|
||||
func (s Spell) SpellEffectsNeedsScaled() bool {
|
||||
if s.Effect1 == 0 {
|
||||
return false
|
||||
}
|
||||
|
||||
needsScaled := false
|
||||
effects := s.GetSpellEffects()
|
||||
for _, e := range effects {
|
||||
|
||||
if !funk.Contains(SpellEffects, e.Effect) || e.Effect == 6 {
|
||||
continue
|
||||
}
|
||||
needsScaled = true
|
||||
}
|
||||
|
||||
return needsScaled
|
||||
}
|
||||
|
||||
// this aura effect has stats or effects that need to be scaled
|
||||
func (s Spell) AuraEffectNeedsScaled() bool {
|
||||
if s.EffectAura1 == 0 {
|
||||
return false
|
||||
}
|
||||
|
||||
for _, effect := range SpellAuraEffects {
|
||||
if s.EffectAura1 == effect || s.EffectAura2 == effect || s.EffectAura3 == effect {
|
||||
return true
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
func (s Spell) HasAuraEffect() bool {
|
||||
return s.EffectAura1 != 0 || s.EffectAura2 != 0 || s.EffectAura3 != 0
|
||||
}
|
||||
|
||||
func AuraEffectCanBeConv(effect int) bool {
|
||||
statMods := [...]int{8, 13, 22, 34, 85, 99, 124, 135, 189}
|
||||
return funk.Contains(statMods, effect)
|
||||
}
|
||||
|
||||
// Lookup details about the effect and return the stat type -1 indicates not found
|
||||
func convertAuraEffect(effect int) int {
|
||||
if !funk.Contains(AuraEffectsStatMap, effect) {
|
||||
log.Printf("effect %v not found in SpellEffectStatMap skipping", effect)
|
||||
return -1
|
||||
}
|
||||
|
||||
return AuraEffectsStatMap[effect]
|
||||
}
|
||||
|
||||
// Converts spell buffs to item stats making it easier to convert and normalize
|
||||
func (s Spell) ConvertToStats() ([]ConvItemStat, error) {
|
||||
stats := []ConvItemStat{}
|
||||
|
||||
if s.Effect1 == 0 && s.EffectAura1 == 0 {
|
||||
return stats, fmt.Errorf("spell does not have an effect1 or auraEffect1")
|
||||
}
|
||||
|
||||
effects := s.GetAuraEffects()
|
||||
|
||||
if s.ID == 9397 {
|
||||
log.Printf("Spell: %v AuraEffect1: %v AuraEffect2: %v AuraEffect3: %v", s.Name, s.EffectAura1, s.EffectAura2, s.EffectAura3)
|
||||
|
||||
}
|
||||
var seen []int
|
||||
for _, e := range effects {
|
||||
if !AuraEffectCanBeConv(e.Effect) {
|
||||
continue
|
||||
}
|
||||
|
||||
statId := convertAuraEffect(e.Effect)
|
||||
if statId == -1 {
|
||||
continue
|
||||
}
|
||||
|
||||
if funk.Contains(seen, statId) {
|
||||
continue
|
||||
}
|
||||
|
||||
// keep track if we have already seen this stat so we do not duplicate
|
||||
// Wotlk changed everything to spell power so might as well do the same in
|
||||
// scaling process.
|
||||
seen = append(seen, statId)
|
||||
statMod := float64(StatModifiers[statId])
|
||||
stats = append(stats, ConvItemStat{
|
||||
StatType: statId,
|
||||
StatValue: e.CalculatedMax,
|
||||
Budget: int(math.Abs(math.Ceil(float64(e.CalculatedMax) * statMod))),
|
||||
})
|
||||
}
|
||||
|
||||
// Handle special stat case where 189 is catch all for crit, dodge, parry, hit, haste, expertise
|
||||
if s.Effect1 != 0 && s.Effect1 == 6 && (s.EffectAura1 == 189 || s.EffectAura1 == 123) {
|
||||
log.Printf("Special case for spell aura effect: %v", s.Description)
|
||||
statId := parseStatDesc(s.Description)
|
||||
if statId == 0 {
|
||||
log.Printf("Could not determine stat for spell aura effect description: %v", s.Name)
|
||||
}
|
||||
|
||||
calced := calcMaxValue(s.EffectBasePoints1, s.EffectDieSides1)
|
||||
log.Printf("StatId: %v Calced: %v", statId, calced)
|
||||
stats = append(stats, ConvItemStat{
|
||||
StatType: statId,
|
||||
StatValue: calced,
|
||||
Budget: int(math.Abs(math.Ceil(float64(calced) * float64(StatModifiers[statId])))),
|
||||
})
|
||||
}
|
||||
|
||||
return stats, nil
|
||||
}
|
||||
|
||||
// This spell can be converted fully into a stat and not needed on the item
|
||||
func (s Spell) CanBeConverted() bool {
|
||||
|
||||
// if there are any spell effects that are not aura effects, then it can be converted
|
||||
effects := s.GetSpellEffects()
|
||||
for _, e := range effects {
|
||||
if e.Effect != 0 && e.Effect != 6 {
|
||||
return false
|
||||
}
|
||||
}
|
||||
|
||||
// Unfortunately if there are any mixed effects for auras, it is too difficult to split those so just
|
||||
// bail out
|
||||
auras := s.GetAuraEffects()
|
||||
auraFlag := false
|
||||
for _, a := range auras {
|
||||
if a.Effect == 0 {
|
||||
continue
|
||||
}
|
||||
|
||||
if AuraEffectCanBeConv(a.Effect) {
|
||||
return true
|
||||
}
|
||||
}
|
||||
|
||||
return auraFlag
|
||||
}
|
||||
|
||||
// based on the description determine the stat to
|
||||
func parseStatDesc(desc string) int {
|
||||
if strings.Contains(desc, "critical strike") {
|
||||
return 32
|
||||
}
|
||||
|
||||
if strings.Contains(desc, "dodge") {
|
||||
return 13
|
||||
}
|
||||
|
||||
if strings.Contains(desc, "parry") {
|
||||
return 14
|
||||
}
|
||||
|
||||
if strings.Contains(desc, "hit rating") {
|
||||
return 31
|
||||
}
|
||||
|
||||
if strings.Contains(desc, "haste rating") {
|
||||
return 36
|
||||
}
|
||||
|
||||
if strings.Contains(desc, "expertise rating") {
|
||||
return 37
|
||||
}
|
||||
|
||||
if strings.Contains(desc, "defense rating") {
|
||||
return 12
|
||||
}
|
||||
|
||||
if strings.Contains(desc, "block rating") {
|
||||
return 15
|
||||
}
|
||||
|
||||
if strings.Contains(desc, "armor penetration") {
|
||||
return 44
|
||||
}
|
||||
|
||||
if strings.Contains(desc, "spell penetration") {
|
||||
return 47
|
||||
}
|
||||
|
||||
return 0
|
||||
}
|
||||
|
||||
// Scales a spell effect, means creating a new spell with the same effect but scaled to a new item level, then passing
|
||||
// back the new spellId, In order to be predictable I will use 30000000 for rare, 31000000 for epic, 32000000 for legendary
|
||||
// An example of this might on hit do $s1 nature damage over $d seconds. We would just scale the $s1 value
|
||||
// based on the formula below. This assumes that Blizzard has already balanced the spell bonus against the
|
||||
// stats on the item level and quality. This is a big assumption as the stats are not penalized
|
||||
// from having the extra damage. This could really create some unique sought after weapons that exploit this.
|
||||
// modified ratio ((s1 / existing iLevel) * newIlevel) * (0.20 Rare or 0.30 Epic or 0.4 for Legendary).
|
||||
func (s *Spell) ScaleSpell(fromItemLevel int, itemLevel int, itemQuality int) (int, error) {
|
||||
s.Scaled = false
|
||||
qualModifier := map[int]float64{
|
||||
3: 1.20,
|
||||
4: 1.30,
|
||||
5: 1.40,
|
||||
}
|
||||
|
||||
idBump := 30000000
|
||||
if itemQuality == 4 {
|
||||
idBump = 31000000
|
||||
}
|
||||
if itemQuality == 5 {
|
||||
idBump = 32000000
|
||||
}
|
||||
|
||||
// direct damage types
|
||||
dd := [...]int{2, 9, 10}
|
||||
|
||||
didScale := false
|
||||
// Causes direct damage
|
||||
if s.Effect1 != 0 && funk.Contains(dd, s.Effect1) {
|
||||
s.EffectBasePoints1 = int(float64(s.EffectBasePoints1) / float64(fromItemLevel) * float64(itemLevel) * qualModifier[itemQuality] * 2.5)
|
||||
didScale = true
|
||||
}
|
||||
if s.Effect2 != 0 && funk.Contains(dd, s.Effect1) {
|
||||
s.EffectBasePoints2 = int(float64(s.EffectBasePoints2) / float64(fromItemLevel) * float64(itemLevel) * qualModifier[itemQuality] * 2.5)
|
||||
didScale = true
|
||||
}
|
||||
|
||||
// Restores a Power / Mana
|
||||
if s.Effect1 != 0 && s.Effect1 == 30 {
|
||||
// skip anyhing else that is not mana as they are flat values
|
||||
if strings.Contains(s.Description, "Mana") || strings.Contains(s.Description, "mana") {
|
||||
s.EffectBasePoints1 = int(float64(s.EffectBasePoints1) / float64(fromItemLevel) * float64(itemLevel) * qualModifier[itemQuality])
|
||||
didScale = true
|
||||
}
|
||||
}
|
||||
|
||||
// Scales a stat buff
|
||||
if s.Effect1 != 0 && s.Effect1 == 35 {
|
||||
s.EffectBasePoints1 = int(float64(s.EffectBasePoints1) / float64(fromItemLevel) * float64(itemLevel) * qualModifier[itemQuality])
|
||||
didScale = true
|
||||
}
|
||||
if s.Effect1 != 0 && s.Effect2 == 35 {
|
||||
s.EffectBasePoints2 = int(float64(s.EffectBasePoints2) / float64(fromItemLevel) * float64(itemLevel) * qualModifier[itemQuality])
|
||||
didScale = true
|
||||
}
|
||||
|
||||
// Handle special aura effects
|
||||
if s.EffectAura1 != 0 && s.EffectAura1 == 3 && s.Effect1 == 6 {
|
||||
s.EffectBasePoints1 = int(float64(s.EffectBasePoints1) / float64(fromItemLevel) * float64(itemLevel) * qualModifier[itemQuality] * 2)
|
||||
didScale = true
|
||||
}
|
||||
|
||||
// Damage Shield Increase Scale due to HP curve
|
||||
if s.EffectAura1 != 0 && s.EffectAura1 == 15 && s.Effect1 == 6 {
|
||||
s.EffectBasePoints1 = int(float64(s.EffectBasePoints1) / float64(fromItemLevel) * float64(itemLevel) * qualModifier[itemQuality] * 1.50)
|
||||
didScale = true
|
||||
}
|
||||
|
||||
if !didScale {
|
||||
return 0, fmt.Errorf("did not qualify to be scaled in ScaleSpell %v (%v)", s.Name, s.ID)
|
||||
}
|
||||
s.Scaled = true
|
||||
return idBump + s.ID, nil
|
||||
}
|
||||
7
spells-list.txt
Normal file
7
spells-list.txt
Normal file
@@ -0,0 +1,7 @@
|
||||
19451 - Frenzy - fast attack / damage (major)
|
||||
25516 - Aura of Command - regen, attack speed, dmg (minor)
|
||||
14538 - Aural Shock (reduce casting speed by 35%) (major)
|
||||
|
||||
Grievous Bite
|
||||
67719 Frost Fever = deals frost damage and reduces attack speed
|
||||
Aura of Anger - Shadow damage over time
|
||||
@@ -1,61 +0,0 @@
|
||||
package utils
|
||||
|
||||
func GetItemFields(prefix string) string {
|
||||
pre := ""
|
||||
if prefix != "" {
|
||||
pre = prefix + "."
|
||||
}
|
||||
|
||||
return `
|
||||
` + pre + `entry, ` + pre + `name, ` + pre + `displayid,
|
||||
quality, ItemLevel, class, subclass, inventoryType,
|
||||
allowableClass, allowableRace,
|
||||
armor,material,
|
||||
requiredSkill, requiredLevel,
|
||||
dmg_min1, dmg_max1,
|
||||
dmg_min2,dmg_max2,
|
||||
dmg_type1, dmg_type2,
|
||||
delay, sheath, MaxDurability,
|
||||
statsCount,
|
||||
stat_type1, stat_value1,
|
||||
stat_type2, stat_value2,
|
||||
stat_type3, stat_value3,
|
||||
stat_type4, stat_value4,
|
||||
stat_type5, stat_value5,
|
||||
stat_type6, stat_value6,
|
||||
stat_type7, stat_value7,
|
||||
stat_type8, stat_value8,
|
||||
stat_type9, stat_value9,
|
||||
stat_type10, stat_value10,
|
||||
spellid_1, spellid_2, spellid_3,
|
||||
spelltrigger_1, spelltrigger_2, spelltrigger_3`
|
||||
}
|
||||
|
||||
func GetSpellFields() string {
|
||||
return `
|
||||
ID,
|
||||
Name_Lang_enUS,
|
||||
Description_Lang_enUS,
|
||||
AuraDescription_Lang_enUS,
|
||||
ProcChance,
|
||||
SpellLevel,
|
||||
Effect_1,
|
||||
Effect_2,
|
||||
Effect_3,
|
||||
EffectDieSides_1,
|
||||
EffectDieSides_2,
|
||||
EffectDieSides_3,
|
||||
EffectRealPointsPerLevel_1,
|
||||
EffectRealPointsPerLevel_2,
|
||||
EffectRealPointsPerLevel_3,
|
||||
EffectBasePoints_1,
|
||||
EffectBasePoints_2,
|
||||
EffectBasePoints_3,
|
||||
EffectAura_1,
|
||||
EffectAura_2,
|
||||
EffectAura_3,
|
||||
EffectBonusMultiplier_1,
|
||||
EffectBonusMultiplier_2,
|
||||
EffectBonusMultiplier_3
|
||||
`
|
||||
}
|
||||
174
wow-item-scaler-web/README.md
Normal file
174
wow-item-scaler-web/README.md
Normal file
@@ -0,0 +1,174 @@
|
||||
# WoW Item Scaler Web Frontend
|
||||
|
||||
A beautiful World of Warcraft-themed web interface for scaling items using your existing Go backend.
|
||||
|
||||
## Features
|
||||
|
||||
- **Immersive WoW-styled UI** with layered backgrounds, magical particle effects, and authentic textures
|
||||
- **Modern visual effects** including animated glowing elements, parallax backgrounds, and fantasy decorations
|
||||
- **Multiple input methods**:
|
||||
- Single item by entry ID
|
||||
- Comma-separated list of entry IDs
|
||||
- Search by item name with dropdown selection
|
||||
- **Visual item comparison** showing before/after scaling
|
||||
- **Wowhead integration** for item images and tooltips
|
||||
- **Responsive design** that works on desktop and mobile
|
||||
- **Export functionality** for SQL and copy-to-clipboard
|
||||
|
||||
## Dependencies & Libraries Used
|
||||
|
||||
### External CDN Libraries
|
||||
1. **Tailwind CSS** (`https://cdn.tailwindcss.com`)
|
||||
- Utility-first CSS framework
|
||||
- Used for responsive layouts, spacing, and utility classes
|
||||
- No build process required
|
||||
|
||||
2. **Wowhead Power** (`https://wow.zamimg.com/widgets/power.js`)
|
||||
- Official Wowhead tooltips and item integration
|
||||
- Provides item images and tooltip functionality
|
||||
- Authentic WoW item data
|
||||
|
||||
3. **Google Fonts**
|
||||
- **Cinzel**: Elegant serif font for body text and UI elements
|
||||
- **Uncial Antiqua**: Fantasy/medieval font for titles and headings
|
||||
- Provides authentic WoW-like typography
|
||||
|
||||
### Custom Theme System
|
||||
- **Custom CSS Variables** for consistent WoW color scheme
|
||||
- **Modular component classes** (`.wow-panel`, `.wow-button`, etc.)
|
||||
- **Quality-based item coloring** (epic purple, legendary orange)
|
||||
- **Animated effects** and hover states
|
||||
|
||||
## Setup
|
||||
|
||||
1. Open `index.html` in a web browser
|
||||
2. Update the backend URL in `js/item-scaler.js` (line 4) to match your Go backend server
|
||||
3. Ensure your backend provides these API endpoints:
|
||||
- `POST /api/scale-items` - Scale items with parameters
|
||||
- `GET /api/search-items?q=query` - Search items by name
|
||||
- `POST /api/export-sql` - Export scaled items as SQL
|
||||
|
||||
## Backend API Expected Format
|
||||
|
||||
### Scale Items Request
|
||||
```json
|
||||
{
|
||||
"itemLevel": 325,
|
||||
"phase": 1,
|
||||
"quality": 4,
|
||||
"catchup": 1.5,
|
||||
"entries": [19019, 19103, 17076]
|
||||
}
|
||||
```
|
||||
|
||||
### Scale Items Response
|
||||
```json
|
||||
{
|
||||
"items": [
|
||||
{
|
||||
"success": true,
|
||||
"entryId": 19019,
|
||||
"original": {
|
||||
"entry": 19019,
|
||||
"name": "Thunderfury, Blessed Blade of the Windseeker",
|
||||
"quality": 5,
|
||||
"itemLevel": 80,
|
||||
"stats": { "Stamina": 15, "Agility": 5 }
|
||||
},
|
||||
"scaled": {
|
||||
"entry": 19019,
|
||||
"name": "Thunderfury, Blessed Blade of the Windseeker",
|
||||
"quality": 5,
|
||||
"itemLevel": 325,
|
||||
"stats": { "Stamina": 45, "Agility": 15 }
|
||||
},
|
||||
"referenceItem": {
|
||||
"name": "Some Reference Item",
|
||||
"entry": 12345
|
||||
}
|
||||
}
|
||||
],
|
||||
"summary": {
|
||||
"total": 1,
|
||||
"successful": 1,
|
||||
"failed": 0,
|
||||
"successRate": "100.0"
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### Search Items Response
|
||||
```json
|
||||
[
|
||||
{
|
||||
"entry": 19019,
|
||||
"name": "Thunderfury, Blessed Blade of the Windseeker",
|
||||
"quality": 5
|
||||
}
|
||||
]
|
||||
```
|
||||
|
||||
## File Structure
|
||||
|
||||
```
|
||||
wow-item-scaler-web/
|
||||
├── index.html # Main HTML file with CDN dependencies
|
||||
├── css/
|
||||
│ └── wow-theme.css # Complete WoW theme styles (8.4KB)
|
||||
├── js/
|
||||
│ ├── wow-theme.js # Theme utilities and UI components (9.8KB)
|
||||
│ └── item-scaler.js # Main application logic and API calls (12KB)
|
||||
└── README.md # This documentation
|
||||
```
|
||||
|
||||
## Technical Details
|
||||
|
||||
### CSS Architecture
|
||||
- **CSS Custom Properties** for theme consistency
|
||||
- **Component-based styling** with `.wow-` prefixed classes
|
||||
- **Layered background system** with multiple gradients, textures, and particle effects
|
||||
- **Animated decorative elements** including glowing gems, magical sparkles, and pulsing effects
|
||||
- **Responsive breakpoints** for mobile compatibility
|
||||
- **Advanced visual effects** using pure CSS (no external images required)
|
||||
|
||||
### JavaScript Architecture
|
||||
- **Class-based ES6 modules** for organization
|
||||
- **Event-driven architecture** for user interactions
|
||||
- **LocalStorage integration** for user preferences
|
||||
- **Error handling** with user-friendly notifications
|
||||
|
||||
### Browser Compatibility
|
||||
- Modern browsers with ES6+ support
|
||||
- Chrome, Firefox, Safari, Edge
|
||||
- Mobile browsers (responsive design)
|
||||
|
||||
## Customization
|
||||
|
||||
### Backend URL
|
||||
Update the `backendUrl` in `js/item-scaler.js`:
|
||||
```javascript
|
||||
this.backendUrl = 'http://your-backend-server:8080';
|
||||
```
|
||||
|
||||
### Styling
|
||||
The WoW theme can be customized in `css/wow-theme.css`. Key variables:
|
||||
```css
|
||||
:root {
|
||||
--wow-gold: #ffd100; /* Primary accent color */
|
||||
--wow-blue: #0084ff; /* Rare item color */
|
||||
--wow-purple: #a335ee; /* Epic item color */
|
||||
--wow-orange: #ff8000; /* Legendary item color */
|
||||
--wow-bg-dark: #0a0a0a; /* Primary background */
|
||||
--wow-bg-panel: #1a1a1a; /* Panel background */
|
||||
}
|
||||
```
|
||||
|
||||
### Item Icons
|
||||
Item icons are loaded from Wowhead. Enhance the `getItemIcon()` function in `wow-theme.js` with your own icon mapping logic.
|
||||
|
||||
## No Build Process Required
|
||||
This is a pure frontend application that runs directly in the browser:
|
||||
- No bundlers (Webpack, Vite, etc.)
|
||||
- No transpilation needed
|
||||
- No package.json or npm install
|
||||
- Just open `index.html` and go!
|
||||
772
wow-item-scaler-web/css/wow-theme.css
Normal file
772
wow-item-scaler-web/css/wow-theme.css
Normal file
@@ -0,0 +1,772 @@
|
||||
/* Araxia Online - Wrath of the Lich King Theme */
|
||||
:root {
|
||||
--araxia-primary: #11111f; /* Deep navy from Araxia */
|
||||
--araxia-text: #f8f8ff; /* Ghost white from Araxia */
|
||||
--wotlk-ice-blue: #4fc3f7; /* Frost blue accent */
|
||||
--wotlk-ice-light: #81d4fa; /* Light ice blue */
|
||||
--wotlk-ice-dark: #0288d1; /* Dark ice blue */
|
||||
--wotlk-frost: #b3e5fc; /* Frost white-blue */
|
||||
--wotlk-shadow: #1a237e; /* Deep shadow blue */
|
||||
--wow-purple: #a335ee; /* Epic purple (unchanged) */
|
||||
--wow-orange: #ff8000; /* Legendary orange (unchanged) */
|
||||
--wow-green: #1eff00; /* Uncommon green (unchanged) */
|
||||
--wow-red: #ff0000; /* Error red (unchanged) */
|
||||
--wow-bg-dark: var(--araxia-primary);
|
||||
--wow-bg-panel: #1e1e3f; /* Slightly lighter navy */
|
||||
--wow-bg-card: #252547; /* Card background - navy tinted */
|
||||
--wow-border: #4fc3f7; /* Ice blue borders */
|
||||
--wow-border-primary: var(--wotlk-ice-blue);
|
||||
--wow-text-primary: var(--araxia-text);
|
||||
--wow-text-secondary: var(--wotlk-frost);
|
||||
--wow-text-muted: #7986cb; /* Muted ice blue */
|
||||
}
|
||||
|
||||
/* Background with Araxia/WotLK ice-themed layers and mage imagery */
|
||||
/* Body and main container for sticky footer */
|
||||
body.wow-bg {
|
||||
min-height: 100vh;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
background:
|
||||
/* Frost crystal pattern overlay */
|
||||
radial-gradient(circle at 25% 25%, rgba(79, 195, 247, 0.06) 0%, transparent 50%),
|
||||
radial-gradient(circle at 75% 75%, rgba(129, 212, 250, 0.04) 0%, transparent 50%),
|
||||
radial-gradient(circle at 50% 10%, rgba(26, 35, 126, 0.05) 0%, transparent 60%),
|
||||
/* CSS-based frost/ice landscape simulation */
|
||||
radial-gradient(ellipse at 30% 20%, rgba(179, 229, 252, 0.1) 0%, transparent 40%),
|
||||
radial-gradient(ellipse at 70% 80%, rgba(26, 35, 126, 0.08) 0%, transparent 50%),
|
||||
/* Mountain/landscape silhouettes */
|
||||
linear-gradient(180deg,
|
||||
transparent 0%,
|
||||
transparent 60%,
|
||||
rgba(79, 195, 247, 0.05) 65%,
|
||||
rgba(129, 212, 250, 0.08) 75%,
|
||||
rgba(17, 17, 31, 0.3) 85%,
|
||||
rgba(37, 37, 71, 0.6) 100%
|
||||
),
|
||||
/* Enhanced CSS frost landscape simulation */
|
||||
conic-gradient(from 180deg at 20% 30%,
|
||||
rgba(79, 195, 247, 0.1) 0deg,
|
||||
rgba(26, 35, 126, 0.05) 60deg,
|
||||
rgba(179, 229, 252, 0.08) 120deg,
|
||||
rgba(79, 195, 247, 0.1) 180deg,
|
||||
rgba(26, 35, 126, 0.05) 240deg,
|
||||
rgba(179, 229, 252, 0.08) 300deg,
|
||||
rgba(79, 195, 247, 0.1) 360deg
|
||||
),
|
||||
/* Iceberg/mountain silhouette effect */
|
||||
radial-gradient(ellipse 800px 400px at 30% 100%,
|
||||
rgba(37, 37, 71, 0.4) 0%,
|
||||
rgba(79, 195, 247, 0.1) 40%,
|
||||
transparent 70%
|
||||
),
|
||||
radial-gradient(ellipse 600px 300px at 70% 100%,
|
||||
rgba(26, 35, 126, 0.3) 0%,
|
||||
rgba(129, 212, 250, 0.08) 50%,
|
||||
transparent 80%
|
||||
),
|
||||
/* Local images with proper sizing and color filtering */
|
||||
url('images/wotlk-bg1.jpg'),
|
||||
url('images/wotlk-bg2.jpg'),
|
||||
url('images/icecrown-bg.jpg'),
|
||||
/* Theme matching overlay for images */
|
||||
linear-gradient(45deg,
|
||||
rgba(17, 17, 31, 0.85) 0%,
|
||||
rgba(30, 30, 63, 0.88) 25%,
|
||||
rgba(17, 17, 31, 0.85) 50%,
|
||||
rgba(37, 37, 71, 0.88) 75%,
|
||||
rgba(17, 17, 31, 0.85) 100%
|
||||
),
|
||||
/* Base Araxia navy gradient */
|
||||
linear-gradient(135deg, var(--araxia-primary) 0%, #1e1e3f 30%, var(--araxia-primary) 60%, #252547 100%),
|
||||
/* Ice crystal texture pattern */
|
||||
repeating-linear-gradient(
|
||||
30deg,
|
||||
transparent,
|
||||
transparent 3px,
|
||||
rgba(79, 195, 247, 0.015) 3px,
|
||||
rgba(79, 195, 247, 0.015) 6px
|
||||
),
|
||||
repeating-linear-gradient(
|
||||
-30deg,
|
||||
transparent,
|
||||
transparent 3px,
|
||||
rgba(129, 212, 250, 0.01) 3px,
|
||||
rgba(129, 212, 250, 0.01) 6px
|
||||
);
|
||||
background-attachment: fixed;
|
||||
background-size:
|
||||
1000px 1000px,
|
||||
800px 800px,
|
||||
600px 600px,
|
||||
1200px 800px,
|
||||
800px 600px,
|
||||
cover,
|
||||
cover,
|
||||
cover,
|
||||
cover,
|
||||
cover,
|
||||
/* Image sizing with proper aspect ratio maintenance */
|
||||
cover,
|
||||
cover,
|
||||
cover,
|
||||
cover,
|
||||
cover,
|
||||
6px 6px,
|
||||
6px 6px;
|
||||
background-position:
|
||||
center,
|
||||
center,
|
||||
center,
|
||||
center top,
|
||||
center bottom,
|
||||
center,
|
||||
center,
|
||||
center,
|
||||
center,
|
||||
center,
|
||||
/* Image positioning for best visual impact */
|
||||
center center,
|
||||
left center,
|
||||
right center,
|
||||
center,
|
||||
center,
|
||||
center,
|
||||
center;
|
||||
background-repeat: no-repeat;
|
||||
color: var(--wow-text-primary);
|
||||
font-family: 'Cinzel', serif;
|
||||
position: relative;
|
||||
/* Color adjustment filter for better theme matching */
|
||||
filter: hue-rotate(-10deg) saturate(1.1) brightness(0.95);
|
||||
}
|
||||
|
||||
/* Main content area that pushes footer down */
|
||||
main {
|
||||
flex: 1;
|
||||
}
|
||||
|
||||
/* Add subtle frost animated effects */
|
||||
.wow-bg::before {
|
||||
content: '';
|
||||
position: fixed;
|
||||
top: 0;
|
||||
left: 0;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
background:
|
||||
radial-gradient(circle at 20% 20%, rgba(79, 195, 247, 0.03) 0%, transparent 30%),
|
||||
radial-gradient(circle at 80% 80%, rgba(129, 212, 250, 0.02) 0%, transparent 40%),
|
||||
radial-gradient(circle at 60% 60%, rgba(26, 35, 126, 0.02) 0%, transparent 50%);
|
||||
animation: wow-frost-glow 12s ease-in-out infinite alternate;
|
||||
pointer-events: none;
|
||||
z-index: -1;
|
||||
}
|
||||
|
||||
@keyframes wow-frost-glow {
|
||||
0% { opacity: 0.4; transform: scale(1) rotate(0deg); }
|
||||
100% { opacity: 0.8; transform: scale(1.03) rotate(0.5deg); }
|
||||
}
|
||||
|
||||
/* Header with Araxia/WotLK ice theme */
|
||||
.wow-header {
|
||||
background:
|
||||
/* Frost border pattern */
|
||||
linear-gradient(90deg, transparent 0%, rgba(79, 195, 247, 0.15) 20%, rgba(79, 195, 247, 0.25) 50%, rgba(79, 195, 247, 0.15) 80%, transparent 100%),
|
||||
/* Ice texture */
|
||||
linear-gradient(180deg, #252547 0%, #1e1e3f 20%, #2a2a52 40%, #1e1e3f 60%, #252547 100%),
|
||||
/* Crystal-like pattern */
|
||||
repeating-linear-gradient(45deg, transparent, transparent 1px, rgba(79, 195, 247, 0.03) 1px, rgba(79, 195, 247, 0.03) 2px);
|
||||
border-image: linear-gradient(90deg, transparent, var(--wotlk-ice-blue), transparent) 1;
|
||||
position: relative;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.wow-header::before {
|
||||
content: '';
|
||||
position: absolute;
|
||||
top: 0;
|
||||
left: 0;
|
||||
right: 0;
|
||||
height: 2px;
|
||||
background: linear-gradient(90deg, transparent, var(--wotlk-ice-blue), transparent);
|
||||
box-shadow: 0 0 5px rgba(79, 195, 247, 0.4);
|
||||
}
|
||||
|
||||
.wow-header::after {
|
||||
content: '';
|
||||
position: absolute;
|
||||
bottom: 0;
|
||||
left: 50%;
|
||||
transform: translateX(-50%);
|
||||
width: 200px;
|
||||
height: 3px;
|
||||
background: linear-gradient(90deg, transparent, var(--wotlk-ice-blue), var(--wotlk-ice-light), var(--wotlk-ice-blue), transparent);
|
||||
box-shadow: 0 0 15px rgba(79, 195, 247, 0.6);
|
||||
}
|
||||
|
||||
.wow-logo-container {
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.araxia-logo {
|
||||
max-width: 120px;
|
||||
height: auto;
|
||||
filter: drop-shadow(0 0 10px rgba(79, 195, 247, 0.4));
|
||||
transition: all 0.3s ease;
|
||||
}
|
||||
|
||||
.araxia-logo:hover {
|
||||
filter: drop-shadow(0 0 20px rgba(79, 195, 247, 0.8));
|
||||
transform: scale(1.05);
|
||||
}
|
||||
|
||||
.wow-server-name {
|
||||
color: var(--wotlk-ice-light);
|
||||
font-size: 0.9rem;
|
||||
font-weight: 600;
|
||||
text-transform: uppercase;
|
||||
letter-spacing: 1px;
|
||||
margin-top: 0.25rem;
|
||||
text-shadow: 0 0 10px rgba(129, 212, 250, 0.6);
|
||||
}
|
||||
|
||||
.wow-title {
|
||||
font-family: 'Uncial Antiqua', serif;
|
||||
color: var(--wotlk-ice-blue);
|
||||
text-shadow:
|
||||
2px 2px 4px rgba(0, 0, 0, 0.9),
|
||||
0 0 20px rgba(79, 195, 247, 0.8),
|
||||
0 0 40px rgba(129, 212, 250, 0.4);
|
||||
letter-spacing: 2px;
|
||||
position: relative;
|
||||
display: inline-block;
|
||||
}
|
||||
|
||||
.wow-title::before {
|
||||
content: '❄';
|
||||
position: absolute;
|
||||
left: -2rem;
|
||||
top: 50%;
|
||||
transform: translateY(-50%);
|
||||
color: var(--wotlk-ice-light);
|
||||
font-size: 0.8em;
|
||||
text-shadow: 0 0 15px rgba(129, 212, 250, 0.9);
|
||||
animation: wow-ice-pulse 4s ease-in-out infinite;
|
||||
}
|
||||
|
||||
.wow-title::after {
|
||||
content: '❄';
|
||||
position: absolute;
|
||||
right: -2rem;
|
||||
top: 50%;
|
||||
transform: translateY(-50%) rotate(45deg);
|
||||
color: var(--wotlk-ice-light);
|
||||
font-size: 0.8em;
|
||||
text-shadow: 0 0 15px rgba(129, 212, 250, 0.9);
|
||||
animation: wow-ice-pulse 4s ease-in-out infinite reverse;
|
||||
}
|
||||
|
||||
@keyframes wow-ice-pulse {
|
||||
0%, 100% { opacity: 0.7; transform: translateY(-50%) scale(1) rotate(0deg); }
|
||||
50% { opacity: 1; transform: translateY(-50%) scale(1.2) rotate(15deg); }
|
||||
}
|
||||
|
||||
.wow-subtitle {
|
||||
color: var(--wow-text-secondary);
|
||||
font-style: italic;
|
||||
margin-top: -5px;
|
||||
}
|
||||
|
||||
/* Panels */
|
||||
.wow-panel {
|
||||
background:
|
||||
/* Ornate corner decorations */
|
||||
radial-gradient(circle at 0% 0%, rgba(255, 209, 0, 0.1) 0%, transparent 15%),
|
||||
radial-gradient(circle at 100% 0%, rgba(255, 209, 0, 0.1) 0%, transparent 15%),
|
||||
radial-gradient(circle at 0% 100%, rgba(255, 209, 0, 0.1) 0%, transparent 15%),
|
||||
radial-gradient(circle at 100% 100%, rgba(255, 209, 0, 0.1) 0%, transparent 15%),
|
||||
/* Stone-like texture */
|
||||
linear-gradient(135deg, rgba(26, 26, 26, 0.95) 0%, rgba(30, 30, 30, 0.98) 50%, rgba(22, 22, 22, 0.95) 100%),
|
||||
/* Subtle pattern */
|
||||
repeating-linear-gradient(0deg, transparent, transparent 1px, rgba(255, 255, 255, 0.01) 1px, rgba(255, 255, 255, 0.01) 2px);
|
||||
border: 2px solid var(--wow-border);
|
||||
border-radius: 8px;
|
||||
box-shadow:
|
||||
0 8px 32px rgba(0, 0, 0, 0.6),
|
||||
inset 0 1px 0 rgba(255, 209, 0, 0.1),
|
||||
inset 0 -1px 0 rgba(0, 0, 0, 0.5);
|
||||
overflow: hidden;
|
||||
position: relative;
|
||||
}
|
||||
|
||||
.wow-panel::before {
|
||||
content: '';
|
||||
position: absolute;
|
||||
top: 0;
|
||||
left: 0;
|
||||
right: 0;
|
||||
bottom: 0;
|
||||
background:
|
||||
linear-gradient(45deg, transparent 48%, rgba(255, 209, 0, 0.05) 49%, rgba(255, 209, 0, 0.05) 51%, transparent 52%),
|
||||
linear-gradient(-45deg, transparent 48%, rgba(255, 209, 0, 0.03) 49%, rgba(255, 209, 0, 0.03) 51%, transparent 52%);
|
||||
pointer-events: none;
|
||||
}
|
||||
|
||||
.wow-panel-header {
|
||||
background:
|
||||
/* Ornate header pattern */
|
||||
linear-gradient(90deg,
|
||||
rgba(255, 209, 0, 0.05) 0%,
|
||||
rgba(255, 209, 0, 0.1) 10%,
|
||||
rgba(255, 209, 0, 0.08) 50%,
|
||||
rgba(255, 209, 0, 0.1) 90%,
|
||||
rgba(255, 209, 0, 0.05) 100%
|
||||
),
|
||||
linear-gradient(90deg, var(--wow-bg-card), var(--wow-bg-panel));
|
||||
border-bottom: 2px solid var(--wow-border-gold);
|
||||
padding: 1rem 1.5rem;
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
position: relative;
|
||||
}
|
||||
|
||||
.wow-panel-header::before {
|
||||
content: '';
|
||||
position: absolute;
|
||||
top: 50%;
|
||||
left: 1rem;
|
||||
transform: translateY(-50%);
|
||||
width: 8px;
|
||||
height: 8px;
|
||||
background: radial-gradient(circle, var(--wow-gold), var(--wow-gold-dark));
|
||||
border-radius: 50%;
|
||||
box-shadow: 0 0 8px rgba(255, 209, 0, 0.6);
|
||||
}
|
||||
|
||||
.wow-panel-header::after {
|
||||
content: '';
|
||||
position: absolute;
|
||||
top: 50%;
|
||||
right: 1rem;
|
||||
transform: translateY(-50%);
|
||||
width: 8px;
|
||||
height: 8px;
|
||||
background: radial-gradient(circle, var(--wow-gold), var(--wow-gold-dark));
|
||||
border-radius: 50%;
|
||||
box-shadow: 0 0 8px rgba(255, 209, 0, 0.6);
|
||||
}
|
||||
|
||||
.wow-panel-content {
|
||||
padding: 1.5rem;
|
||||
}
|
||||
|
||||
.wow-section-title {
|
||||
color: var(--wow-gold);
|
||||
font-family: 'Uncial Antiqua', serif;
|
||||
text-shadow: 1px 1px 2px rgba(0, 0, 0, 0.8);
|
||||
}
|
||||
|
||||
/* Form Elements */
|
||||
.wow-input-group {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
}
|
||||
|
||||
.wow-label {
|
||||
color: var(--wow-gold);
|
||||
font-weight: 600;
|
||||
margin-bottom: 0.5rem;
|
||||
font-size: 0.9rem;
|
||||
text-transform: uppercase;
|
||||
letter-spacing: 1px;
|
||||
}
|
||||
|
||||
.wow-input,
|
||||
.wow-select {
|
||||
background: var(--wow-bg-card);
|
||||
border: 2px solid var(--wow-border);
|
||||
border-radius: 4px;
|
||||
padding: 0.75rem;
|
||||
color: var(--wow-text-primary);
|
||||
font-family: 'Cinzel', serif;
|
||||
transition: all 0.3s ease;
|
||||
}
|
||||
|
||||
.wow-input:focus,
|
||||
.wow-select:focus {
|
||||
outline: none;
|
||||
border-color: var(--wow-gold);
|
||||
box-shadow: 0 0 10px rgba(255, 209, 0, 0.3);
|
||||
}
|
||||
|
||||
.wow-help-text {
|
||||
color: var(--wow-text-muted);
|
||||
font-size: 0.8rem;
|
||||
margin-top: 0.25rem;
|
||||
font-style: italic;
|
||||
}
|
||||
|
||||
/* Tabs */
|
||||
.wow-tab-container {
|
||||
display: flex;
|
||||
border-bottom: 2px solid var(--wow-border);
|
||||
margin-bottom: 1rem;
|
||||
}
|
||||
|
||||
.wow-tab {
|
||||
background: var(--wow-bg-card);
|
||||
border: 2px solid var(--wow-border);
|
||||
border-bottom: none;
|
||||
padding: 0.75rem 1.5rem;
|
||||
color: var(--wow-text-secondary);
|
||||
font-family: 'Cinzel', serif;
|
||||
font-weight: 600;
|
||||
cursor: pointer;
|
||||
transition: all 0.3s ease;
|
||||
margin-right: 2px;
|
||||
}
|
||||
|
||||
.wow-tab:hover {
|
||||
background: var(--wow-bg-panel);
|
||||
color: var(--wow-gold);
|
||||
}
|
||||
|
||||
.wow-tab-active {
|
||||
background: var(--wow-bg-panel);
|
||||
color: var(--wow-gold);
|
||||
border-color: var(--wow-border-gold);
|
||||
position: relative;
|
||||
}
|
||||
|
||||
.wow-tab-active::after {
|
||||
content: '';
|
||||
position: absolute;
|
||||
bottom: -2px;
|
||||
left: 0;
|
||||
right: 0;
|
||||
height: 2px;
|
||||
background: var(--wow-gold);
|
||||
}
|
||||
|
||||
/* Buttons */
|
||||
.wow-button {
|
||||
background: linear-gradient(135deg, var(--wow-bg-card), var(--wow-bg-panel));
|
||||
border: 2px solid var(--wow-border);
|
||||
color: var(--wow-text-primary);
|
||||
padding: 0.75rem 2rem;
|
||||
border-radius: 4px;
|
||||
font-family: 'Cinzel', serif;
|
||||
font-weight: 600;
|
||||
cursor: pointer;
|
||||
transition: all 0.3s ease;
|
||||
position: relative;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.wow-button::before {
|
||||
content: '';
|
||||
position: absolute;
|
||||
top: 0;
|
||||
left: -100%;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
background: linear-gradient(90deg, transparent, rgba(255, 209, 0, 0.2), transparent);
|
||||
transition: left 0.5s ease;
|
||||
}
|
||||
|
||||
.wow-button:hover::before {
|
||||
left: 100%;
|
||||
}
|
||||
|
||||
.wow-button:hover {
|
||||
border-color: var(--wow-gold);
|
||||
box-shadow: 0 0 20px rgba(255, 209, 0, 0.3);
|
||||
transform: translateY(-2px);
|
||||
}
|
||||
|
||||
.wow-button-primary {
|
||||
background: linear-gradient(135deg, #2a4d6e, #1e3a52);
|
||||
border-color: var(--wow-blue);
|
||||
color: var(--wow-text-primary);
|
||||
}
|
||||
|
||||
.wow-button-primary:hover {
|
||||
border-color: var(--wow-gold);
|
||||
background: linear-gradient(135deg, #3a5d7e, #2e4a62);
|
||||
}
|
||||
|
||||
.wow-button-secondary {
|
||||
background: linear-gradient(135deg, #4a2a6e, #3a1e52);
|
||||
border-color: var(--wow-purple);
|
||||
}
|
||||
|
||||
.wow-button-secondary:hover {
|
||||
border-color: var(--wow-gold);
|
||||
background: linear-gradient(135deg, #5a3a7e, #4a2e62);
|
||||
}
|
||||
|
||||
.wow-button-small {
|
||||
padding: 0.5rem 1rem;
|
||||
font-size: 0.85rem;
|
||||
}
|
||||
|
||||
.wow-button-text {
|
||||
position: relative;
|
||||
z-index: 1;
|
||||
}
|
||||
|
||||
/* Search Results */
|
||||
.wow-search-results {
|
||||
background: var(--wow-bg-card);
|
||||
border: 2px solid var(--wow-border);
|
||||
border-top: none;
|
||||
max-height: 200px;
|
||||
overflow-y: auto;
|
||||
position: absolute;
|
||||
width: 100%;
|
||||
z-index: 10;
|
||||
border-radius: 0 0 4px 4px;
|
||||
}
|
||||
|
||||
.wow-search-item {
|
||||
padding: 0.75rem;
|
||||
cursor: pointer;
|
||||
border-bottom: 1px solid var(--wow-border);
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 0.75rem;
|
||||
transition: background 0.2s ease;
|
||||
}
|
||||
|
||||
.wow-search-item:hover {
|
||||
background: var(--wow-bg-panel);
|
||||
}
|
||||
|
||||
.wow-search-item:last-child {
|
||||
border-bottom: none;
|
||||
}
|
||||
|
||||
/* Item Cards */
|
||||
.wow-item-card {
|
||||
background: var(--wow-bg-card);
|
||||
border: 2px solid var(--wow-border);
|
||||
border-radius: 8px;
|
||||
padding: 1.5rem;
|
||||
margin-bottom: 1rem;
|
||||
position: relative;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.wow-item-card::before {
|
||||
content: '';
|
||||
position: absolute;
|
||||
top: 0;
|
||||
left: 0;
|
||||
right: 0;
|
||||
height: 4px;
|
||||
background: linear-gradient(90deg, transparent, var(--wow-gold), transparent);
|
||||
}
|
||||
|
||||
.wow-item-epic {
|
||||
border-color: var(--wow-purple);
|
||||
}
|
||||
|
||||
.wow-item-legendary {
|
||||
border-color: var(--wow-orange);
|
||||
}
|
||||
|
||||
.wow-item-comparison {
|
||||
display: grid;
|
||||
grid-template-columns: 1fr auto 1fr;
|
||||
gap: 2rem;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.wow-item-before,
|
||||
.wow-item-after {
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.wow-item-arrow {
|
||||
font-size: 2rem;
|
||||
color: var(--wow-gold);
|
||||
text-shadow: 1px 1px 2px rgba(0, 0, 0, 0.8);
|
||||
}
|
||||
|
||||
.wow-item-image {
|
||||
width: 64px;
|
||||
height: 64px;
|
||||
border: 2px solid var(--wow-border);
|
||||
border-radius: 4px;
|
||||
margin: 0 auto 1rem;
|
||||
background: var(--wow-bg-panel);
|
||||
}
|
||||
|
||||
.wow-item-name {
|
||||
font-weight: 700;
|
||||
font-size: 1.1rem;
|
||||
margin-bottom: 0.5rem;
|
||||
}
|
||||
|
||||
.wow-item-stats {
|
||||
font-size: 0.9rem;
|
||||
line-height: 1.5;
|
||||
}
|
||||
|
||||
.wow-stat-line {
|
||||
margin-bottom: 0.25rem;
|
||||
}
|
||||
|
||||
.wow-stat-improved {
|
||||
color: var(--wow-green);
|
||||
}
|
||||
|
||||
.wow-stat-decreased {
|
||||
color: var(--wow-red);
|
||||
}
|
||||
|
||||
/* Quality Colors */
|
||||
.quality-poor { color: #9d9d9d; }
|
||||
.quality-common { color: #ffffff; }
|
||||
.quality-uncommon { color: #1eff00; }
|
||||
.quality-rare { color: #0070dd; }
|
||||
.quality-epic { color: var(--wow-purple); }
|
||||
.quality-legendary { color: var(--wow-orange); }
|
||||
|
||||
/* Loading Animation */
|
||||
.wow-loading {
|
||||
text-align: center;
|
||||
padding: 3rem;
|
||||
}
|
||||
|
||||
.wow-spinner {
|
||||
width: 60px;
|
||||
height: 60px;
|
||||
border: 4px solid var(--wow-border);
|
||||
border-top: 4px solid var(--wow-gold);
|
||||
border-radius: 50%;
|
||||
animation: wow-spin 1s linear infinite;
|
||||
margin: 0 auto 1rem;
|
||||
}
|
||||
|
||||
.wow-loading-text {
|
||||
color: var(--wow-gold);
|
||||
font-size: 1.1rem;
|
||||
font-weight: 600;
|
||||
animation: wow-pulse 1.5s ease-in-out infinite;
|
||||
}
|
||||
|
||||
@keyframes wow-spin {
|
||||
0% { transform: rotate(0deg); }
|
||||
100% { transform: rotate(360deg); }
|
||||
}
|
||||
|
||||
@keyframes wow-pulse {
|
||||
0%, 100% { opacity: 0.7; }
|
||||
50% { opacity: 1; }
|
||||
}
|
||||
|
||||
/* Footer - always at bottom */
|
||||
.wow-footer {
|
||||
background: var(--wow-bg-panel);
|
||||
border-top: 2px solid var(--wow-border);
|
||||
margin-top: auto; /* This pushes footer to bottom */
|
||||
flex-shrink: 0; /* Prevent footer from shrinking */
|
||||
position: relative;
|
||||
z-index: 10;
|
||||
}
|
||||
|
||||
.wow-footer::before {
|
||||
content: '';
|
||||
position: absolute;
|
||||
top: 0;
|
||||
left: 0;
|
||||
right: 0;
|
||||
height: 2px;
|
||||
background: linear-gradient(90deg, transparent, var(--wotlk-ice-blue), transparent);
|
||||
box-shadow: 0 0 10px rgba(79, 195, 247, 0.4);
|
||||
}
|
||||
|
||||
.wow-footer-text {
|
||||
color: var(--wow-text-muted);
|
||||
font-size: 0.9rem;
|
||||
}
|
||||
|
||||
/* Frost/ice particle effects */
|
||||
.wow-bg::after {
|
||||
content: '';
|
||||
position: fixed;
|
||||
top: 0;
|
||||
left: 0;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
background-image:
|
||||
radial-gradient(2px 2px at 20px 30px, rgba(79, 195, 247, 0.4), transparent),
|
||||
radial-gradient(1px 1px at 40px 70px, rgba(129, 212, 250, 0.3), transparent),
|
||||
radial-gradient(3px 3px at 90px 40px, rgba(179, 229, 252, 0.3), transparent),
|
||||
radial-gradient(1px 1px at 130px 80px, rgba(79, 195, 247, 0.4), transparent),
|
||||
radial-gradient(2px 2px at 160px 30px, rgba(129, 212, 250, 0.25), transparent),
|
||||
radial-gradient(1px 1px at 180px 60px, rgba(26, 35, 126, 0.3), transparent);
|
||||
background-repeat: repeat;
|
||||
background-size: 250px 120px;
|
||||
animation: wow-frost-particles 25s linear infinite;
|
||||
pointer-events: none;
|
||||
z-index: -1;
|
||||
opacity: 0.7;
|
||||
}
|
||||
|
||||
@keyframes wow-frost-particles {
|
||||
0% { transform: translateY(0) translateX(0) rotate(0deg); }
|
||||
100% { transform: translateY(-120px) translateX(30px) rotate(180deg); }
|
||||
}
|
||||
|
||||
/* Enhanced section titles with ice decorative elements */
|
||||
.wow-section-title::before {
|
||||
content: '❖';
|
||||
margin-right: 0.5rem;
|
||||
color: var(--wotlk-ice-light);
|
||||
text-shadow: 0 0 15px rgba(129, 212, 250, 0.9);
|
||||
animation: wow-ice-gem-glow 3s ease-in-out infinite alternate;
|
||||
}
|
||||
|
||||
.wow-section-title::after {
|
||||
content: '❖';
|
||||
margin-left: 0.5rem;
|
||||
color: var(--wotlk-ice-light);
|
||||
text-shadow: 0 0 15px rgba(129, 212, 250, 0.9);
|
||||
animation: wow-ice-gem-glow 3s ease-in-out infinite alternate-reverse;
|
||||
}
|
||||
|
||||
@keyframes wow-ice-gem-glow {
|
||||
0% { opacity: 0.6; transform: scale(1) rotate(0deg); }
|
||||
100% { opacity: 1; transform: scale(1.3) rotate(45deg); }
|
||||
}
|
||||
|
||||
/* Responsive Design */
|
||||
@media (max-width: 768px) {
|
||||
.wow-item-comparison {
|
||||
grid-template-columns: 1fr;
|
||||
gap: 1rem;
|
||||
}
|
||||
|
||||
.wow-item-arrow {
|
||||
transform: rotate(90deg);
|
||||
font-size: 1.5rem;
|
||||
}
|
||||
|
||||
.wow-tab-container {
|
||||
flex-direction: column;
|
||||
}
|
||||
|
||||
.wow-tab {
|
||||
margin-right: 0;
|
||||
margin-bottom: 2px;
|
||||
}
|
||||
|
||||
.wow-title::before,
|
||||
.wow-title::after {
|
||||
display: none; /* Hide sword decorations on mobile */
|
||||
}
|
||||
}
|
||||
34
wow-item-scaler-web/images/README.md
Normal file
34
wow-item-scaler-web/images/README.md
Normal file
@@ -0,0 +1,34 @@
|
||||
# Background Images for WoW Item Scaler
|
||||
|
||||
This directory should contain WoW frost/ice themed background images to enhance the visual appearance of the application.
|
||||
|
||||
## Required Images:
|
||||
|
||||
1. **wotlk-bg1.jpg** - Wrath of the Lich King landscape (recommended: 1920x1080)
|
||||
2. **wotlk-bg2.jpg** - Northrend/frost themed scenery (recommended: 1920x1080)
|
||||
3. **icecrown-bg.jpg** - Icecrown Citadel or similar WotLK location (recommended: 1920x1080)
|
||||
|
||||
## Recommended Sources:
|
||||
|
||||
- Official Blizzard press kit images
|
||||
- WoW community screenshots (with proper licensing)
|
||||
- Fan art (with permission)
|
||||
- Generated AI art in WoW style
|
||||
|
||||
## Image Specifications:
|
||||
|
||||
- **Format**: JPG or PNG
|
||||
- **Size**: 1920x1080 recommended for best quality
|
||||
- **Theme**: Frost, ice, snow, Wrath of the Lich King landscapes
|
||||
- **Colors**: Cool blues, whites, grays to match Araxia theme
|
||||
|
||||
## CSS Integration:
|
||||
|
||||
The images are automatically integrated via `css/wow-theme.css` with:
|
||||
- Araxia color overlay blending
|
||||
- Ice particle effects on top
|
||||
- Multiple layer composition for depth
|
||||
|
||||
## Fallback:
|
||||
|
||||
If images are not present, the CSS will fall back to pure CSS-generated frost patterns and gradients that simulate the WoW aesthetic.
|
||||
143
wow-item-scaler-web/index.html
Normal file
143
wow-item-scaler-web/index.html
Normal file
@@ -0,0 +1,143 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<title>WoW Item Scaler</title>
|
||||
<script src="https://cdn.tailwindcss.com"></script>
|
||||
<script src="https://wow.zamimg.com/widgets/power.js"></script>
|
||||
<link href="https://fonts.googleapis.com/css2?family=Cinzel:wght@400;600;700&family=Uncial+Antiqua&display=swap" rel="stylesheet">
|
||||
<link rel="stylesheet" href="css/wow-theme.css">
|
||||
</head>
|
||||
<body class="min-h-screen wow-bg">
|
||||
<!-- Header -->
|
||||
<header class="wow-header border-b-4 shadow-2xl" style="border-color: #4fc3f7;">
|
||||
<div class="container mx-auto px-6 py-4">
|
||||
<div class="flex items-center justify-center">
|
||||
<div class="wow-logo-container">
|
||||
<div class="flex items-center justify-center mb-2">
|
||||
<img src="https://araxiaonline.github.io/docs/_media/logo.png" alt="Araxia Online" class="araxia-logo" onerror="this.style.display='none'">
|
||||
</div>
|
||||
<h1 class="wow-title text-4xl font-bold">Item Scaler</h1>
|
||||
<p class="wow-subtitle text-lg">Wrath of the Lich King</p>
|
||||
<p class="wow-server-name">Araxia Online</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</header>
|
||||
|
||||
<main class="container mx-auto px-6 py-8">
|
||||
<!-- Scaling Parameters Panel -->
|
||||
<div class="wow-panel mb-8">
|
||||
<div class="wow-panel-header">
|
||||
<h2 class="wow-section-title text-2xl font-semibold">Scaling Parameters</h2>
|
||||
</div>
|
||||
<div class="wow-panel-content">
|
||||
<div class="grid grid-cols-1 md:grid-cols-4 gap-6">
|
||||
<div class="wow-input-group">
|
||||
<label for="itemLevel" class="wow-label">Item Level</label>
|
||||
<input type="number" id="itemLevel" class="wow-input" value="325" min="1" max="500">
|
||||
</div>
|
||||
<div class="wow-input-group">
|
||||
<label for="phase" class="wow-label">Phase</label>
|
||||
<select id="phase" class="wow-select">
|
||||
<option value="0">No Tier Bonus</option>
|
||||
<option value="1">Phase 1</option>
|
||||
<option value="2">Phase 2</option>
|
||||
<option value="3">Phase 3</option>
|
||||
<option value="4">Phase 4</option>
|
||||
<option value="5">Phase 5</option>
|
||||
</select>
|
||||
</div>
|
||||
<div class="wow-input-group">
|
||||
<label for="quality" class="wow-label">Quality</label>
|
||||
<select id="quality" class="wow-select">
|
||||
<option value="4" class="text-purple-400">Epic</option>
|
||||
<option value="5" class="text-orange-400">Legendary</option>
|
||||
</select>
|
||||
</div>
|
||||
<div class="wow-input-group">
|
||||
<label for="catchup" class="wow-label">Catchup Bonus</label>
|
||||
<input type="number" id="catchup" class="wow-input" value="1.0" min="0.1" max="3.0" step="0.1">
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Item Input Panel -->
|
||||
<div class="wow-panel mb-8">
|
||||
<div class="wow-panel-header">
|
||||
<h2 class="wow-section-title text-2xl font-semibold">Item Selection</h2>
|
||||
</div>
|
||||
<div class="wow-panel-content">
|
||||
<div class="space-y-6">
|
||||
<!-- Tab Navigation -->
|
||||
<div class="wow-tab-container">
|
||||
<button id="tabEntries" class="wow-tab wow-tab-active">Entry IDs</button>
|
||||
<button id="tabSearch" class="wow-tab">Search by Name</button>
|
||||
</div>
|
||||
|
||||
<!-- Entry IDs Input -->
|
||||
<div id="entriesPanel" class="wow-tab-panel">
|
||||
<div class="wow-input-group">
|
||||
<label for="entryIds" class="wow-label">Entry IDs (comma-separated)</label>
|
||||
<input type="text" id="entryIds" class="wow-input" placeholder="19019, 19103, 17076">
|
||||
<p class="wow-help-text">Enter item entry IDs separated by commas</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Search Input -->
|
||||
<div id="searchPanel" class="wow-tab-panel hidden">
|
||||
<div class="wow-input-group">
|
||||
<label for="itemSearch" class="wow-label">Item Name</label>
|
||||
<input type="text" id="itemSearch" class="wow-input" placeholder="Thunderfury">
|
||||
<div id="searchResults" class="wow-search-results hidden"></div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Action Buttons -->
|
||||
<div class="flex gap-4">
|
||||
<button id="scaleButton" class="wow-button wow-button-primary">
|
||||
<span class="wow-button-text">Scale Items</span>
|
||||
</button>
|
||||
<button id="clearButton" class="wow-button wow-button-secondary">
|
||||
<span class="wow-button-text">Clear Results</span>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Loading Spinner -->
|
||||
<div id="loadingSpinner" class="wow-loading hidden">
|
||||
<div class="wow-spinner"></div>
|
||||
<p class="wow-loading-text">Forging your items...</p>
|
||||
</div>
|
||||
|
||||
<!-- Results Panel -->
|
||||
<div id="resultsPanel" class="wow-panel hidden">
|
||||
<div class="wow-panel-header">
|
||||
<h2 class="wow-section-title text-2xl font-semibold">Scaled Items</h2>
|
||||
<div class="flex gap-2">
|
||||
<button id="exportSqlButton" class="wow-button-small wow-button-secondary">Export SQL</button>
|
||||
<button id="copyResultsButton" class="wow-button-small wow-button-secondary">Copy Results</button>
|
||||
</div>
|
||||
</div>
|
||||
<div id="resultsContainer" class="wow-panel-content">
|
||||
<!-- Results will be populated here -->
|
||||
</div>
|
||||
</div>
|
||||
</main>
|
||||
|
||||
<!-- Footer -->
|
||||
<footer class="wow-footer mt-12">
|
||||
<div class="container mx-auto px-6 py-4 text-center">
|
||||
<p class="wow-footer-text">Araxia Online - Wrath of the Lich King Item Scaler</p>
|
||||
<p class="text-xs mt-2" style="color: #7986cb;">Forge your destiny in the frozen wastes of Northrend</p>
|
||||
</div>
|
||||
</footer>
|
||||
|
||||
<script src="js/wow-theme.js"></script>
|
||||
<script src="js/item-scaler.js"></script>
|
||||
</body>
|
||||
</html>
|
||||
342
wow-item-scaler-web/js/item-scaler.js
Normal file
342
wow-item-scaler-web/js/item-scaler.js
Normal file
@@ -0,0 +1,342 @@
|
||||
// Main Item Scaler Application Logic
|
||||
class ItemScaler {
|
||||
constructor() {
|
||||
this.backendUrl = 'http://localhost:8080'; // Update this to match your backend
|
||||
this.searchTimeout = null;
|
||||
this.init();
|
||||
}
|
||||
|
||||
init() {
|
||||
this.setupEventListeners();
|
||||
this.loadDefaultValues();
|
||||
}
|
||||
|
||||
setupEventListeners() {
|
||||
// Scale button
|
||||
document.getElementById('scaleButton').addEventListener('click', () => {
|
||||
this.scaleItems();
|
||||
});
|
||||
|
||||
// Clear button
|
||||
document.getElementById('clearButton').addEventListener('click', () => {
|
||||
WowTheme.clearResults();
|
||||
});
|
||||
|
||||
// Export SQL button
|
||||
document.getElementById('exportSqlButton').addEventListener('click', () => {
|
||||
this.exportSQL();
|
||||
});
|
||||
|
||||
// Copy results button
|
||||
document.getElementById('copyResultsButton').addEventListener('click', () => {
|
||||
this.copyResults();
|
||||
});
|
||||
|
||||
// Search input
|
||||
document.getElementById('itemSearch').addEventListener('input', (e) => {
|
||||
this.handleSearchInput(e.target.value);
|
||||
});
|
||||
|
||||
// Hide search results when clicking outside
|
||||
document.addEventListener('click', (e) => {
|
||||
const searchContainer = document.getElementById('searchPanel');
|
||||
if (!searchContainer.contains(e.target)) {
|
||||
document.getElementById('searchResults').classList.add('hidden');
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
loadDefaultValues() {
|
||||
// Load any saved preferences from localStorage
|
||||
const savedValues = this.getSavedValues();
|
||||
if (savedValues) {
|
||||
document.getElementById('itemLevel').value = savedValues.itemLevel || 325;
|
||||
document.getElementById('phase').value = savedValues.phase || 0;
|
||||
document.getElementById('quality').value = savedValues.quality || 4;
|
||||
document.getElementById('catchup').value = savedValues.catchup || 1.0;
|
||||
}
|
||||
}
|
||||
|
||||
getSavedValues() {
|
||||
try {
|
||||
return JSON.parse(localStorage.getItem('wowItemScalerSettings'));
|
||||
} catch {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
saveValues() {
|
||||
const values = {
|
||||
itemLevel: parseInt(document.getElementById('itemLevel').value),
|
||||
phase: parseInt(document.getElementById('phase').value),
|
||||
quality: parseInt(document.getElementById('quality').value),
|
||||
catchup: parseFloat(document.getElementById('catchup').value)
|
||||
};
|
||||
localStorage.setItem('wowItemScalerSettings', JSON.stringify(values));
|
||||
}
|
||||
|
||||
async scaleItems() {
|
||||
try {
|
||||
WowTheme.showLoading();
|
||||
this.saveValues();
|
||||
|
||||
const scalingParams = this.getScalingParameters();
|
||||
const itemEntries = this.getItemEntries();
|
||||
|
||||
if (itemEntries.length === 0) {
|
||||
WowTheme.hideLoading();
|
||||
WowTheme.showNotification('Please provide item entries or search for items', 'error');
|
||||
return;
|
||||
}
|
||||
|
||||
const results = await this.callBackendAPI(scalingParams, itemEntries);
|
||||
this.displayResults(results);
|
||||
|
||||
} catch (error) {
|
||||
console.error('Error scaling items:', error);
|
||||
WowTheme.hideLoading();
|
||||
WowTheme.showNotification(`Error: ${error.message}`, 'error');
|
||||
}
|
||||
}
|
||||
|
||||
getScalingParameters() {
|
||||
return {
|
||||
itemLevel: parseInt(document.getElementById('itemLevel').value),
|
||||
phase: parseInt(document.getElementById('phase').value),
|
||||
quality: parseInt(document.getElementById('quality').value),
|
||||
catchup: parseFloat(document.getElementById('catchup').value)
|
||||
};
|
||||
}
|
||||
|
||||
getItemEntries() {
|
||||
const entriesText = document.getElementById('entryIds').value.trim();
|
||||
if (!entriesText) {
|
||||
return [];
|
||||
}
|
||||
|
||||
return entriesText
|
||||
.split(',')
|
||||
.map(entry => entry.trim())
|
||||
.filter(entry => entry && !isNaN(entry))
|
||||
.map(entry => parseInt(entry));
|
||||
}
|
||||
|
||||
async callBackendAPI(scalingParams, itemEntries) {
|
||||
const requestData = {
|
||||
...scalingParams,
|
||||
entries: itemEntries
|
||||
};
|
||||
|
||||
console.log('Sending request:', requestData);
|
||||
|
||||
const response = await fetch(`${this.backendUrl}/api/scale-items`, {
|
||||
method: 'POST',
|
||||
headers: {
|
||||
'Content-Type': 'application/json',
|
||||
},
|
||||
body: JSON.stringify(requestData)
|
||||
});
|
||||
|
||||
if (!response.ok) {
|
||||
const errorData = await response.json().catch(() => ({}));
|
||||
throw new Error(errorData.message || `HTTP ${response.status}: ${response.statusText}`);
|
||||
}
|
||||
|
||||
return await response.json();
|
||||
}
|
||||
|
||||
displayResults(results) {
|
||||
const container = document.getElementById('resultsContainer');
|
||||
container.innerHTML = '';
|
||||
|
||||
if (!results || !results.items || results.items.length === 0) {
|
||||
container.innerHTML = `
|
||||
<div class="text-center text-gray-400 py-8">
|
||||
<p>No items were successfully scaled.</p>
|
||||
<p class="text-sm mt-2">Check the console for detailed error information.</p>
|
||||
</div>
|
||||
`;
|
||||
WowTheme.showResults();
|
||||
return;
|
||||
}
|
||||
|
||||
// Display summary
|
||||
const summary = `
|
||||
<div class="wow-panel mb-6">
|
||||
<div class="wow-panel-content">
|
||||
<div class="text-center">
|
||||
<h3 class="text-xl font-semibold text-yellow-400 mb-4">Scaling Summary</h3>
|
||||
<div class="grid grid-cols-2 md:grid-cols-4 gap-4 text-sm">
|
||||
<div>
|
||||
<div class="text-gray-400">Total Items</div>
|
||||
<div class="text-white font-semibold">${results.summary?.total || results.items.length}</div>
|
||||
</div>
|
||||
<div>
|
||||
<div class="text-gray-400">Successful</div>
|
||||
<div class="text-green-400 font-semibold">${results.summary?.successful || results.items.length}</div>
|
||||
</div>
|
||||
<div>
|
||||
<div class="text-gray-400">Failed</div>
|
||||
<div class="text-red-400 font-semibold">${results.summary?.failed || 0}</div>
|
||||
</div>
|
||||
<div>
|
||||
<div class="text-gray-400">Success Rate</div>
|
||||
<div class="text-yellow-400 font-semibold">${results.summary?.successRate || '100.0'}%</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
`;
|
||||
|
||||
container.innerHTML = summary;
|
||||
|
||||
// Display individual item results
|
||||
results.items.forEach(result => {
|
||||
if (result.success) {
|
||||
const itemCard = WowTheme.createItemCard(
|
||||
result.original,
|
||||
result.scaled,
|
||||
result.referenceItem
|
||||
);
|
||||
container.innerHTML += itemCard;
|
||||
} else {
|
||||
// Display error for failed item
|
||||
container.innerHTML += `
|
||||
<div class="wow-item-card border-red-600">
|
||||
<div class="text-center">
|
||||
<h3 class="text-red-400 font-semibold mb-2">Failed to scale item</h3>
|
||||
<p class="text-gray-300 mb-2">Entry ID: ${result.entryId}</p>
|
||||
<div class="text-sm text-gray-400">
|
||||
${result.errors ? result.errors.map(error => `<p>${error}</p>`).join('') : 'Unknown error occurred'}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
`;
|
||||
}
|
||||
});
|
||||
|
||||
WowTheme.showResults();
|
||||
this.reinitializeTooltips();
|
||||
}
|
||||
|
||||
reinitializeTooltips() {
|
||||
// Reinitialize Wowhead tooltips for newly added content
|
||||
if (window.$WowheadPower) {
|
||||
window.$WowheadPower.refreshLinks();
|
||||
}
|
||||
}
|
||||
|
||||
async handleSearchInput(query) {
|
||||
clearTimeout(this.searchTimeout);
|
||||
|
||||
if (!query || query.length < 2) {
|
||||
document.getElementById('searchResults').classList.add('hidden');
|
||||
return;
|
||||
}
|
||||
|
||||
this.searchTimeout = setTimeout(async () => {
|
||||
try {
|
||||
const results = await this.searchItems(query);
|
||||
this.displaySearchResults(results);
|
||||
} catch (error) {
|
||||
console.error('Search error:', error);
|
||||
WowTheme.showNotification('Search failed', 'error');
|
||||
}
|
||||
}, 300);
|
||||
}
|
||||
|
||||
async searchItems(query) {
|
||||
const response = await fetch(`${this.backendUrl}/api/search-items?q=${encodeURIComponent(query)}`, {
|
||||
method: 'GET',
|
||||
headers: {
|
||||
'Content-Type': 'application/json',
|
||||
}
|
||||
});
|
||||
|
||||
if (!response.ok) {
|
||||
throw new Error(`Search failed: ${response.status}`);
|
||||
}
|
||||
|
||||
return await response.json();
|
||||
}
|
||||
|
||||
displaySearchResults(results) {
|
||||
const container = document.getElementById('searchResults');
|
||||
|
||||
if (!results || results.length === 0) {
|
||||
container.innerHTML = `
|
||||
<div class="wow-search-item">
|
||||
<div class="text-gray-400">No items found</div>
|
||||
</div>
|
||||
`;
|
||||
} else {
|
||||
container.innerHTML = results
|
||||
.slice(0, 10) // Limit to 10 results
|
||||
.map(item => WowTheme.createSearchResultItem(item))
|
||||
.join('');
|
||||
}
|
||||
|
||||
container.classList.remove('hidden');
|
||||
}
|
||||
|
||||
async exportSQL() {
|
||||
try {
|
||||
const scalingParams = this.getScalingParameters();
|
||||
const itemEntries = this.getItemEntries();
|
||||
|
||||
if (itemEntries.length === 0) {
|
||||
WowTheme.showNotification('No items to export', 'error');
|
||||
return;
|
||||
}
|
||||
|
||||
const response = await fetch(`${this.backendUrl}/api/export-sql`, {
|
||||
method: 'POST',
|
||||
headers: {
|
||||
'Content-Type': 'application/json',
|
||||
},
|
||||
body: JSON.stringify({
|
||||
...scalingParams,
|
||||
entries: itemEntries
|
||||
})
|
||||
});
|
||||
|
||||
if (!response.ok) {
|
||||
throw new Error(`Export failed: ${response.status}`);
|
||||
}
|
||||
|
||||
const blob = await response.blob();
|
||||
const url = window.URL.createObjectURL(blob);
|
||||
const a = document.createElement('a');
|
||||
a.href = url;
|
||||
a.download = `scaled_items_${Date.now()}.sql`;
|
||||
document.body.appendChild(a);
|
||||
a.click();
|
||||
document.body.removeChild(a);
|
||||
window.URL.revokeObjectURL(url);
|
||||
|
||||
WowTheme.showNotification('SQL exported successfully!', 'success');
|
||||
|
||||
} catch (error) {
|
||||
console.error('Export error:', error);
|
||||
WowTheme.showNotification('Export failed', 'error');
|
||||
}
|
||||
}
|
||||
|
||||
async copyResults() {
|
||||
try {
|
||||
const container = document.getElementById('resultsContainer');
|
||||
const textContent = container.innerText;
|
||||
await navigator.clipboard.writeText(textContent);
|
||||
WowTheme.showNotification('Results copied to clipboard!', 'success');
|
||||
} catch (error) {
|
||||
console.error('Copy error:', error);
|
||||
WowTheme.showNotification('Failed to copy results', 'error');
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Initialize the application
|
||||
document.addEventListener('DOMContentLoaded', () => {
|
||||
new ItemScaler();
|
||||
});
|
||||
250
wow-item-scaler-web/js/wow-theme.js
Normal file
250
wow-item-scaler-web/js/wow-theme.js
Normal file
@@ -0,0 +1,250 @@
|
||||
// WoW Theme JavaScript utilities
|
||||
class WowTheme {
|
||||
static init() {
|
||||
this.setupTabNavigation();
|
||||
this.setupTooltips();
|
||||
this.initializeWowheadPower();
|
||||
}
|
||||
|
||||
static setupTabNavigation() {
|
||||
const tabButtons = document.querySelectorAll('.wow-tab');
|
||||
const tabPanels = document.querySelectorAll('.wow-tab-panel');
|
||||
|
||||
tabButtons.forEach(button => {
|
||||
button.addEventListener('click', () => {
|
||||
const isEntries = button.id === 'tabEntries';
|
||||
|
||||
// Update tab states
|
||||
tabButtons.forEach(btn => btn.classList.remove('wow-tab-active'));
|
||||
button.classList.add('wow-tab-active');
|
||||
|
||||
// Show/hide panels
|
||||
document.getElementById('entriesPanel').classList.toggle('hidden', !isEntries);
|
||||
document.getElementById('searchPanel').classList.toggle('hidden', isEntries);
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
static setupTooltips() {
|
||||
// Initialize Wowhead tooltips when they become available
|
||||
if (window.$WowheadPower) {
|
||||
window.$WowheadPower.init();
|
||||
}
|
||||
}
|
||||
|
||||
static initializeWowheadPower() {
|
||||
// Configure Wowhead Power settings
|
||||
if (window.$WH) {
|
||||
window.$WH.Tooltip.config = {
|
||||
colorLinks: true,
|
||||
iconizeLinks: true,
|
||||
renameLinks: true
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
static showLoading() {
|
||||
document.getElementById('loadingSpinner').classList.remove('hidden');
|
||||
document.getElementById('resultsPanel').classList.add('hidden');
|
||||
}
|
||||
|
||||
static hideLoading() {
|
||||
document.getElementById('loadingSpinner').classList.add('hidden');
|
||||
}
|
||||
|
||||
static showResults() {
|
||||
document.getElementById('resultsPanel').classList.remove('hidden');
|
||||
this.hideLoading();
|
||||
}
|
||||
|
||||
static clearResults() {
|
||||
const container = document.getElementById('resultsContainer');
|
||||
container.innerHTML = '';
|
||||
document.getElementById('resultsPanel').classList.add('hidden');
|
||||
}
|
||||
|
||||
static getQualityClass(quality) {
|
||||
const qualityMap = {
|
||||
0: 'quality-poor',
|
||||
1: 'quality-common',
|
||||
2: 'quality-uncommon',
|
||||
3: 'quality-rare',
|
||||
4: 'quality-epic',
|
||||
5: 'quality-legendary'
|
||||
};
|
||||
return qualityMap[quality] || 'quality-common';
|
||||
}
|
||||
|
||||
static getQualityName(quality) {
|
||||
const qualityNames = {
|
||||
0: 'Poor',
|
||||
1: 'Common',
|
||||
2: 'Uncommon',
|
||||
3: 'Rare',
|
||||
4: 'Epic',
|
||||
5: 'Legendary'
|
||||
};
|
||||
return qualityNames[quality] || 'Common';
|
||||
}
|
||||
|
||||
static createItemCard(original, scaled, referenceItem = null) {
|
||||
const qualityClass = this.getQualityClass(scaled.quality);
|
||||
const cardClass = scaled.quality === 4 ? 'wow-item-epic' : 'wow-item-legendary';
|
||||
|
||||
return `
|
||||
<div class="wow-item-card ${cardClass}">
|
||||
<div class="wow-item-comparison">
|
||||
<div class="wow-item-before">
|
||||
<h3 class="wow-item-name ${this.getQualityClass(original.quality)}">
|
||||
${original.name}
|
||||
</h3>
|
||||
<div class="wow-item-image">
|
||||
<img src="https://wow.zamimg.com/images/wow/icons/medium/${this.getItemIcon(original.entry)}.jpg"
|
||||
alt="${original.name}"
|
||||
onerror="this.src='https://wow.zamimg.com/images/wow/icons/medium/inv_misc_questionmark.jpg'">
|
||||
</div>
|
||||
<div class="wow-item-stats">
|
||||
<div class="wow-stat-line">Item Level: ${original.itemLevel || 'Unknown'}</div>
|
||||
<div class="wow-stat-line">Quality: ${this.getQualityName(original.quality)}</div>
|
||||
${this.formatStats(original.stats)}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="wow-item-arrow">➤</div>
|
||||
|
||||
<div class="wow-item-after">
|
||||
<h3 class="wow-item-name ${qualityClass}">
|
||||
${scaled.name}
|
||||
</h3>
|
||||
<div class="wow-item-image">
|
||||
<img src="https://wow.zamimg.com/images/wow/icons/medium/${this.getItemIcon(scaled.entry)}.jpg"
|
||||
alt="${scaled.name}"
|
||||
onerror="this.src='https://wow.zamimg.com/images/wow/icons/medium/inv_misc_questionmark.jpg'">
|
||||
</div>
|
||||
<div class="wow-item-stats">
|
||||
<div class="wow-stat-line">Item Level: ${scaled.itemLevel}</div>
|
||||
<div class="wow-stat-line">Quality: ${this.getQualityName(scaled.quality)}</div>
|
||||
${this.formatStats(scaled.stats, original.stats)}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
${referenceItem ? `
|
||||
<div class="mt-4 pt-4 border-t border-gray-600">
|
||||
<p class="text-sm text-gray-400 mb-2">Reference Item Used:</p>
|
||||
<p class="text-yellow-400">${referenceItem.name}</p>
|
||||
</div>
|
||||
` : ''}
|
||||
|
||||
<div class="mt-4 pt-4 border-t border-gray-600 flex justify-between">
|
||||
<span class="text-sm text-gray-400">Entry ID: ${scaled.entry}</span>
|
||||
<button class="wow-button-small wow-button-secondary" onclick="WowTheme.copyToClipboard('${scaled.entry}')">
|
||||
Copy Entry ID
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
`;
|
||||
}
|
||||
|
||||
static formatStats(stats, originalStats = null) {
|
||||
if (!stats || Object.keys(stats).length === 0) {
|
||||
return '<div class="wow-stat-line text-gray-500">No stats available</div>';
|
||||
}
|
||||
|
||||
return Object.entries(stats).map(([statName, value]) => {
|
||||
let className = 'wow-stat-line';
|
||||
let prefix = '';
|
||||
|
||||
if (originalStats && originalStats[statName] !== undefined) {
|
||||
const originalValue = originalStats[statName];
|
||||
if (value > originalValue) {
|
||||
className += ' wow-stat-improved';
|
||||
prefix = '+';
|
||||
} else if (value < originalValue) {
|
||||
className += ' wow-stat-decreased';
|
||||
}
|
||||
}
|
||||
|
||||
return `<div class="${className}">${prefix}${value} ${statName}</div>`;
|
||||
}).join('');
|
||||
}
|
||||
|
||||
static getItemIcon(entryId) {
|
||||
// This would ideally come from your backend or a lookup table
|
||||
// For now, return a default or use the entry ID as a fallback
|
||||
return `inv_misc_questionmark`;
|
||||
}
|
||||
|
||||
static async copyToClipboard(text) {
|
||||
try {
|
||||
await navigator.clipboard.writeText(text);
|
||||
this.showNotification('Copied to clipboard!', 'success');
|
||||
} catch (err) {
|
||||
console.error('Failed to copy: ', err);
|
||||
this.showNotification('Failed to copy', 'error');
|
||||
}
|
||||
}
|
||||
|
||||
static showNotification(message, type = 'info') {
|
||||
const notification = document.createElement('div');
|
||||
notification.className = `fixed top-4 right-4 p-4 rounded-lg shadow-lg z-50 transition-all duration-300 ${
|
||||
type === 'success' ? 'bg-green-600' :
|
||||
type === 'error' ? 'bg-red-600' :
|
||||
'bg-blue-600'
|
||||
} text-white`;
|
||||
notification.textContent = message;
|
||||
|
||||
document.body.appendChild(notification);
|
||||
|
||||
// Animate in
|
||||
setTimeout(() => notification.classList.add('opacity-100'), 10);
|
||||
|
||||
// Remove after 3 seconds
|
||||
setTimeout(() => {
|
||||
notification.classList.add('opacity-0');
|
||||
setTimeout(() => notification.remove(), 300);
|
||||
}, 3000);
|
||||
}
|
||||
|
||||
static createSearchResultItem(item) {
|
||||
return `
|
||||
<div class="wow-search-item" data-entry="${item.entry}" onclick="WowTheme.selectSearchItem(${item.entry}, '${item.name.replace(/'/g, "\\'")}')">
|
||||
<div class="wow-item-image" style="width: 32px; height: 32px;">
|
||||
<img src="https://wow.zamimg.com/images/wow/icons/small/${this.getItemIcon(item.entry)}.jpg"
|
||||
alt="${item.name}"
|
||||
style="width: 100%; height: 100%;"
|
||||
onerror="this.src='https://wow.zamimg.com/images/wow/icons/small/inv_misc_questionmark.jpg'">
|
||||
</div>
|
||||
<div>
|
||||
<div class="font-medium ${this.getQualityClass(item.quality)}">${item.name}</div>
|
||||
<div class="text-xs text-gray-400">Entry ID: ${item.entry}</div>
|
||||
</div>
|
||||
</div>
|
||||
`;
|
||||
}
|
||||
|
||||
static selectSearchItem(entryId, itemName) {
|
||||
const entriesInput = document.getElementById('entryIds');
|
||||
const currentEntries = entriesInput.value.trim();
|
||||
|
||||
if (currentEntries) {
|
||||
entriesInput.value = `${currentEntries}, ${entryId}`;
|
||||
} else {
|
||||
entriesInput.value = entryId.toString();
|
||||
}
|
||||
|
||||
// Clear search
|
||||
document.getElementById('itemSearch').value = '';
|
||||
document.getElementById('searchResults').classList.add('hidden');
|
||||
|
||||
// Switch to entries tab
|
||||
document.getElementById('tabEntries').click();
|
||||
|
||||
this.showNotification(`Added ${itemName} to selection`, 'success');
|
||||
}
|
||||
}
|
||||
|
||||
// Initialize theme when DOM is loaded
|
||||
document.addEventListener('DOMContentLoaded', () => {
|
||||
WowTheme.init();
|
||||
});
|
||||
Reference in New Issue
Block a user