Wynn versioning method (#238)
* Update tomes.json with 2.0 tomes Added the 18 new weapon tomes coming in update 2.0. Also fixed fabled t1 weapon tomes having level 80 instead of 60. * Update tome_map.json with 2.0 tomes Added the 18 new weapon tomes coming in update 2.0. * Add missing regression tests * Encode and decode V8, initial files * Adding shortcut load use json directly meme * Dummy data for 2.0.1.2 (same as 2.0.1.1) update documentation slightly * Tier 3 tomes, and update files from api .... tech debt... when binary encode * Change versioning system to use query instead of hash hopefully less breaking change; also just prettier * More misc bugfix Fix race condition in builder graph load Fix loading empty hash Add boundless set tag and set bonus Update mage atree * Data files for wynn version 2.0.1.2, and updated atree const json * Add ability for nodes to have (single) archetype req but no archetype Possibly we want to make a more general req system * Finish inputting rest of the atree changes hopefully * Minify index.html * Add tree decoding pseudocode to dev/index.html * Update V8 docs * Style fixes, bump db versions * missing... semicolons... Co-authored-by: FrozenEarth <39888817+FrozenEarth-git@users.noreply.github.com> Co-authored-by: hppeng <hppeng>
This commit is contained in:
parent
ba1f23e7ab
commit
2561feb621
30 changed files with 35583 additions and 32047 deletions
File diff suppressed because one or more lines are too long
|
@ -1313,13 +1313,12 @@
|
|||
<script type="text/javascript" src="../js/load_tome.js"></script>
|
||||
<script type="text/javascript" src="../js/custom.js"></script>
|
||||
<script type="text/javascript" src="../js/craft.js"></script>
|
||||
<script type="text/javascript" src="../js/builder/atree_constants_min.js"></script>
|
||||
<script type="text/javascript" src="../js/builder/build.js"></script>
|
||||
<script type="text/javascript" src="../js/builder/builder_constants.js"></script>
|
||||
<script type="text/javascript" src="../js/builder/build_encode_decode.js"></script>
|
||||
<script type="text/javascript" src="../js/builder/atree.js"></script>
|
||||
<script type="text/javascript" src="../js/builder/builder.js"></script>
|
||||
<script type="text/javascript" src="../js/builder/builder_graph.js"></script>
|
||||
<script type="text/javascript" src="../js/builder/builder.js"></script>
|
||||
<!--script type="text/javascript" src="../js/builder/optimize.js"></script-->
|
||||
</body>
|
||||
</html>
|
||||
|
|
62740
clean.json
62740
clean.json
File diff suppressed because it is too large
Load diff
File diff suppressed because one or more lines are too long
1
data/2.0.1.1/atree.json
Normal file
1
data/2.0.1.1/atree.json
Normal file
File diff suppressed because one or more lines are too long
1
data/2.0.1.1/ingreds.json
Normal file
1
data/2.0.1.1/ingreds.json
Normal file
File diff suppressed because one or more lines are too long
1
data/2.0.1.1/items.json
Normal file
1
data/2.0.1.1/items.json
Normal file
File diff suppressed because one or more lines are too long
809
data/2.0.1.1/tomes.json
Normal file
809
data/2.0.1.1/tomes.json
Normal file
|
@ -0,0 +1,809 @@
|
|||
{
|
||||
"tomes": [
|
||||
{
|
||||
"name": "Retaliating Tome of Armour Mastery I",
|
||||
"tier": "Fabled",
|
||||
"type": "armorTome",
|
||||
"category": "tome",
|
||||
"drop": "never",
|
||||
"restrict": "Soulbound Item",
|
||||
"lvl": 60,
|
||||
"defmobs": 3,
|
||||
"thorns": 6,
|
||||
"ref": 6,
|
||||
"hpBonus": 120,
|
||||
"fixID": false,
|
||||
"id": 0,
|
||||
"alias": "Thorns I"
|
||||
},
|
||||
{
|
||||
"name": "Retaliating Tome of Armour Mastery II",
|
||||
"tier": "Fabled",
|
||||
"type": "armorTome",
|
||||
"category": "tome",
|
||||
"drop": "never",
|
||||
"restrict": "Soulbound Item",
|
||||
"lvl": 100,
|
||||
"defMobs": 5,
|
||||
"thorns": 8,
|
||||
"ref": 8,
|
||||
"fixID": false,
|
||||
"id": 1,
|
||||
"alias": "Thorns II"
|
||||
},
|
||||
{
|
||||
"name": "Destructive Tome of Armour Mastery I",
|
||||
"tier": "Fabled",
|
||||
"type": "armorTome",
|
||||
"category": "tome",
|
||||
"drop": "never",
|
||||
"restrict": "Soulbound Item",
|
||||
"lvl": 60,
|
||||
"defMobs": 3,
|
||||
"exploding": 5,
|
||||
"mdPct": 5,
|
||||
"hpBonus": 120,
|
||||
"fixID": false,
|
||||
"id": 2,
|
||||
"alias": "Melee I"
|
||||
},
|
||||
{
|
||||
"name": "Destructive Tome of Armour Mastery II",
|
||||
"tier": "Fabled",
|
||||
"type": "armorTome",
|
||||
"category": "tome",
|
||||
"drop": "never",
|
||||
"restrict": "Soulbound Item",
|
||||
"lvl": 100,
|
||||
"defMobs": 5,
|
||||
"exploding": 6,
|
||||
"mdPct": 6,
|
||||
"fixID": false,
|
||||
"id": 3,
|
||||
"alias": "Melee II"
|
||||
},
|
||||
{
|
||||
"name": "Sorcerer's Tome of Armour Mastery I",
|
||||
"tier": "Fabled",
|
||||
"type": "armorTome",
|
||||
"category": "tome",
|
||||
"drop": "never",
|
||||
"restrict": "Soulbound Item",
|
||||
"lvl": 60,
|
||||
"defMobs": 3,
|
||||
"sdPct": 5,
|
||||
"hpBonus": 120,
|
||||
"fixID": false,
|
||||
"id": 4,
|
||||
"alias": "Spell Damage I"
|
||||
},
|
||||
{
|
||||
"name": "Sorcerer's Tome of Armour Mastery II",
|
||||
"tier": "Fabled",
|
||||
"type": "armorTome",
|
||||
"category": "tome",
|
||||
"drop": "never",
|
||||
"restrict": "Soulbound Item",
|
||||
"lvl": 100,
|
||||
"defMobs": 5,
|
||||
"sdPct": 6,
|
||||
"fixID": false,
|
||||
"id": 5,
|
||||
"alias": "Spell Damage II"
|
||||
},
|
||||
{
|
||||
"name": "Everlasting Tome of Armour Mastery I",
|
||||
"tier": "Fabled",
|
||||
"type": "armorTome",
|
||||
"category": "tome",
|
||||
"drop": "never",
|
||||
"restrict": "Soulbound Item",
|
||||
"lvl": 60,
|
||||
"defMobs": 3,
|
||||
"hprRaw": 15,
|
||||
"hpBonus": 120,
|
||||
"fixID": false,
|
||||
"id": 6,
|
||||
"alias": "Health Regen I"
|
||||
},
|
||||
{
|
||||
"name": "Everlasting Tome of Armour Mastery II",
|
||||
"tier": "Fabled",
|
||||
"type": "armorTome",
|
||||
"category": "tome",
|
||||
"drop": "never",
|
||||
"restrict": "Soulbound Item",
|
||||
"lvl": 100,
|
||||
"defMobs": 5,
|
||||
"hprRaw": 60,
|
||||
"fixID": false,
|
||||
"id": 7,
|
||||
"alias": "Health Regen II"
|
||||
},
|
||||
{
|
||||
"name": "Vampiric Tome of Armour Mastery I",
|
||||
"tier": "Fabled",
|
||||
"type": "armorTome",
|
||||
"category": "tome",
|
||||
"drop": "never",
|
||||
"restrict": "Soulbound Item",
|
||||
"lvl": 60,
|
||||
"defMobs": 3,
|
||||
"ls": 25,
|
||||
"hpBonus": 120,
|
||||
"fixID": false,
|
||||
"id": 8,
|
||||
"alias": "Life Steal I"
|
||||
},
|
||||
{
|
||||
"name": "Vampiric Tome of Armour Mastery II",
|
||||
"tier": "Fabled",
|
||||
"type": "armorTome",
|
||||
"category": "tome",
|
||||
"drop": "never",
|
||||
"restrict": "Soulbound Item",
|
||||
"lvl": 100,
|
||||
"defMobs": 5,
|
||||
"ls": 85,
|
||||
"fixID": false,
|
||||
"id": 9,
|
||||
"alias": "Life Steal II"
|
||||
},
|
||||
{
|
||||
"name": "Greedy Tome of Armour Mastery I",
|
||||
"tier": "Fabled",
|
||||
"type": "armorTome",
|
||||
"category": "tome",
|
||||
"drop": "never",
|
||||
"restrict": "Soulbound Item",
|
||||
"lvl": 60,
|
||||
"defMobs": 3,
|
||||
"lb": 5,
|
||||
"hpBonus": 120,
|
||||
"fixID": false,
|
||||
"id": 10,
|
||||
"alias": "Loot Bonus I"
|
||||
},
|
||||
{
|
||||
"name": "Greedy Tome of Armour Mastery II",
|
||||
"tier": "Fabled",
|
||||
"type": "armorTome",
|
||||
"category": "tome",
|
||||
"drop": "never",
|
||||
"restrict": "Soulbound Item",
|
||||
"lvl": 100,
|
||||
"defMobs": 5,
|
||||
"lb": 6,
|
||||
"fixID": false,
|
||||
"id": 11,
|
||||
"alias": "Loot Bonus II"
|
||||
},
|
||||
{
|
||||
"name": "Weightless Tome of Armour Mastery I",
|
||||
"tier": "Fabled",
|
||||
"type": "armorTome",
|
||||
"category": "tome",
|
||||
"drop": "never",
|
||||
"restrict": "Soulbound Item",
|
||||
"lvl": 60,
|
||||
"defMobs": 3,
|
||||
"spd": 5,
|
||||
"hpBonus": 120,
|
||||
"fixID": false,
|
||||
"id": 12,
|
||||
"alias": "Walk Speed I"
|
||||
},
|
||||
{
|
||||
"name": "Weightless Tome of Armour Mastery II",
|
||||
"tier": "Fabled",
|
||||
"type": "armorTome",
|
||||
"category": "tome",
|
||||
"drop": "never",
|
||||
"restrict": "Soulbound Item",
|
||||
"lvl": 100,
|
||||
"defMobs": 5,
|
||||
"spd": 6,
|
||||
"fixID": false,
|
||||
"id": 13,
|
||||
"alias": "Walk Speed II"
|
||||
},
|
||||
{
|
||||
"name": "Blooming Tome of Armour Mastery II",
|
||||
"tier": "Mythic",
|
||||
"type": "armorTome",
|
||||
"category": "tome",
|
||||
"drop": "never",
|
||||
"restrict": "Soulbound Item",
|
||||
"lvl": 100,
|
||||
"defMobs": 8,
|
||||
"eDefPct": 10,
|
||||
"hpBonus": 150,
|
||||
"fixID": false,
|
||||
"id": 14,
|
||||
"alias": "Earth Defense II"
|
||||
},
|
||||
{
|
||||
"name": "Pulsing Tome of Armour Mastery II",
|
||||
"tier": "Mythic",
|
||||
"type": "armorTome",
|
||||
"category": "tome",
|
||||
"drop": "never",
|
||||
"restrict": "Soulbound Item",
|
||||
"lvl": 100,
|
||||
"defMobs": 8,
|
||||
"tDefPct": 10,
|
||||
"hpBonus": 150,
|
||||
"fixID": false,
|
||||
"id": 15,
|
||||
"alias": "Thunder Defense II"
|
||||
},
|
||||
{
|
||||
"name": "Oceanic Tome of Armour Mastery II",
|
||||
"tier": "Mythic",
|
||||
"type": "armorTome",
|
||||
"category": "tome",
|
||||
"drop": "never",
|
||||
"restrict": "Soulbound Item",
|
||||
"lvl": 100,
|
||||
"defMobs": 8,
|
||||
"wDefPct": 10,
|
||||
"hpBonus": 150,
|
||||
"fixID": false,
|
||||
"id": 16,
|
||||
"alias": "Water Defense II"
|
||||
},
|
||||
{
|
||||
"name": "Courageous Tome of Armour Mastery II",
|
||||
"tier": "Mythic",
|
||||
"type": "armorTome",
|
||||
"category": "tome",
|
||||
"drop": "never",
|
||||
"restrict": "Soulbound Item",
|
||||
"lvl": 100,
|
||||
"defMobs": 8,
|
||||
"fDefPct": 10,
|
||||
"hpBonus": 150,
|
||||
"fixID": false,
|
||||
"id": 17,
|
||||
"alias": "Fire Defense II"
|
||||
},
|
||||
{
|
||||
"name": "Clouded Tome of Armour Mastery II",
|
||||
"tier": "Mythic",
|
||||
"type": "armorTome",
|
||||
"category": "tome",
|
||||
"drop": "never",
|
||||
"restrict": "Soulbound Item",
|
||||
"lvl": 100,
|
||||
"defMobs": 8,
|
||||
"aDefPct": 10,
|
||||
"hpBonus": 150,
|
||||
"fixID": false,
|
||||
"id": 18,
|
||||
"alias": "Air Defense II"
|
||||
},
|
||||
{
|
||||
"name": "Radiant Tome of Armour Mastery II",
|
||||
"tier": "Mythic",
|
||||
"type": "armorTome",
|
||||
"category": "tome",
|
||||
"drop": "never",
|
||||
"restrict": "Soulbound Item",
|
||||
"lvl": 100,
|
||||
"defMobs": 8,
|
||||
"eDefPct": 6,
|
||||
"tDefPct": 6,
|
||||
"wDefPct": 6,
|
||||
"fDefPct": 6,
|
||||
"aDefPct": 6,
|
||||
"hpBonus": 150,
|
||||
"fixID": false,
|
||||
"id": 19,
|
||||
"alias": "Rainbow Defense II"
|
||||
},
|
||||
{
|
||||
"name": "Tome of Weapon Mastery I",
|
||||
"tier": "Legendary",
|
||||
"type": "weaponTome",
|
||||
"category": "tome",
|
||||
"drop": "never",
|
||||
"restrict": "Soulbound Item",
|
||||
"lvl": 60,
|
||||
"damMobs": 6,
|
||||
"fixID": false,
|
||||
"id": 20,
|
||||
"alias": "Weapon Mastery I"
|
||||
},
|
||||
{
|
||||
"name": "Earthbound Tome of Weapon Mastery I",
|
||||
"tier": "Fabled",
|
||||
"type": "weaponTome",
|
||||
"category": "tome",
|
||||
"drop": "never",
|
||||
"restrict": "Soulbound Item",
|
||||
"lvl": 80,
|
||||
"damMobs": 7,
|
||||
"str": 3,
|
||||
"fixID": false,
|
||||
"id": 21,
|
||||
"alias": "Strength I"
|
||||
},
|
||||
{
|
||||
"name": "Earthbound Tome of Weapon Mastery II",
|
||||
"tier": "Fabled",
|
||||
"type": "weaponTome",
|
||||
"category": "tome",
|
||||
"drop": "never",
|
||||
"restrict": "Soulbound Item",
|
||||
"lvl": 80,
|
||||
"damMobs": 8,
|
||||
"str": 3,
|
||||
"fixID": false,
|
||||
"id": 22,
|
||||
"alias": "Strength II"
|
||||
},
|
||||
{
|
||||
"name": "Nimble Tome of Weapon Mastery I",
|
||||
"tier": "Fabled",
|
||||
"type": "weaponTome",
|
||||
"category": "tome",
|
||||
"drop": "never",
|
||||
"restrict": "Soulbound Item",
|
||||
"lvl": 80,
|
||||
"damMobs": 7,
|
||||
"dex": 3,
|
||||
"fixID": false,
|
||||
"id": 23,
|
||||
"alias": "Dexterity I"
|
||||
},
|
||||
{
|
||||
"name": "Nimble Tome of Weapon Mastery II",
|
||||
"tier": "Fabled",
|
||||
"type": "weaponTome",
|
||||
"category": "tome",
|
||||
"drop": "never",
|
||||
"restrict": "Soulbound Item",
|
||||
"lvl": 80,
|
||||
"damMobs": 8,
|
||||
"dex": 3,
|
||||
"fixID": false,
|
||||
"id": 24,
|
||||
"alias": "Dexterity II"
|
||||
},
|
||||
{
|
||||
"name": "Mystical Tome of Weapon Mastery I",
|
||||
"tier": "Fabled",
|
||||
"type": "weaponTome",
|
||||
"category": "tome",
|
||||
"drop": "never",
|
||||
"restrict": "Soulbound Item",
|
||||
"lvl": 80,
|
||||
"damMobs": 7,
|
||||
"int": 3,
|
||||
"fixID": false,
|
||||
"id": 25,
|
||||
"alias": "Intelligence I"
|
||||
},
|
||||
{
|
||||
"name": "Mystical Tome of Weapon Mastery II",
|
||||
"tier": "Fabled",
|
||||
"type": "weaponTome",
|
||||
"category": "tome",
|
||||
"drop": "never",
|
||||
"restrict": "Soulbound Item",
|
||||
"lvl": 80,
|
||||
"damMobs": 8,
|
||||
"int": 3,
|
||||
"fixID": false,
|
||||
"id": 26,
|
||||
"alias": "Intelligence II"
|
||||
},
|
||||
{
|
||||
"name": "Warding Tome of Weapon Mastery I",
|
||||
"tier": "Fabled",
|
||||
"type": "weaponTome",
|
||||
"category": "tome",
|
||||
"drop": "never",
|
||||
"restrict": "Soulbound Item",
|
||||
"lvl": 80,
|
||||
"damMobs": 7,
|
||||
"def": 3,
|
||||
"fixID": false,
|
||||
"id": 27,
|
||||
"alias": "Defense I"
|
||||
},
|
||||
{
|
||||
"name": "Warding Tome of Weapon Mastery II",
|
||||
"tier": "Fabled",
|
||||
"type": "weaponTome",
|
||||
"category": "tome",
|
||||
"drop": "never",
|
||||
"restrict": "Soulbound Item",
|
||||
"lvl": 80,
|
||||
"damMobs": 8,
|
||||
"def": 3,
|
||||
"fixID": false,
|
||||
"id": 28,
|
||||
"alias": "Defense II"
|
||||
},
|
||||
{
|
||||
"name": "Athletic Tome of Weapon Mastery I",
|
||||
"tier": "Fabled",
|
||||
"type": "weaponTome",
|
||||
"category": "tome",
|
||||
"drop": "never",
|
||||
"restrict": "Soulbound Item",
|
||||
"lvl": 80,
|
||||
"damMobs": 7,
|
||||
"agi": 3,
|
||||
"fixID": false,
|
||||
"id": 29,
|
||||
"alias": "Agility I"
|
||||
},
|
||||
{
|
||||
"name": "Athletic Tome of Weapon Mastery II",
|
||||
"tier": "Fabled",
|
||||
"type": "weaponTome",
|
||||
"category": "tome",
|
||||
"drop": "never",
|
||||
"restrict": "Soulbound Item",
|
||||
"lvl": 80,
|
||||
"damMobs": 8,
|
||||
"agi": 3,
|
||||
"fixID": false,
|
||||
"id": 30,
|
||||
"alias": "Agility II"
|
||||
},
|
||||
{
|
||||
"name": "Cosmic Tome of Weapon Mastery I",
|
||||
"tier": "Fabled",
|
||||
"type": "weaponTome",
|
||||
"category": "tome",
|
||||
"drop": "never",
|
||||
"restrict": "Soulbound Item",
|
||||
"lvl": 80,
|
||||
"damMobs": 7,
|
||||
"str": 1,
|
||||
"dex": 1,
|
||||
"int": 1,
|
||||
"def": 1,
|
||||
"agi": 1,
|
||||
"fixID": false,
|
||||
"id": 31,
|
||||
"alias": "Rainbow Skillpoint I"
|
||||
},
|
||||
{
|
||||
"name": "Cosmic Tome of Weapon Mastery II",
|
||||
"tier": "Fabled",
|
||||
"type": "weaponTome",
|
||||
"category": "tome",
|
||||
"drop": "never",
|
||||
"restrict": "Soulbound Item",
|
||||
"lvl": 80,
|
||||
"damMobs": 8,
|
||||
"str": 1,
|
||||
"dex": 1,
|
||||
"int": 1,
|
||||
"def": 1,
|
||||
"agi": 1,
|
||||
"fixID": false,
|
||||
"id": 32,
|
||||
"alias": "Rainbow Skillpoint II"
|
||||
},
|
||||
{
|
||||
"name": "Seismic Tome of Weapon Mastery II",
|
||||
"tier": "Mythic",
|
||||
"type": "weaponTome",
|
||||
"category": "tome",
|
||||
"drop": "never",
|
||||
"restrict": "Soulbound Item",
|
||||
"lvl": 80,
|
||||
"damMobs": 12,
|
||||
"eDamPct": 7,
|
||||
"fixID": false,
|
||||
"id": 33,
|
||||
"alias": "Earth Damage II"
|
||||
},
|
||||
{
|
||||
"name": "Voltaic Tome of Weapon Mastery II",
|
||||
"tier": "Mythic",
|
||||
"type": "weaponTome",
|
||||
"category": "tome",
|
||||
"drop": "never",
|
||||
"restrict": "Soulbound Item",
|
||||
"lvl": 80,
|
||||
"damMobs": 12,
|
||||
"tDamPct": 7,
|
||||
"fixID": false,
|
||||
"id": 34,
|
||||
"alias": "Thunder Damage II"
|
||||
},
|
||||
{
|
||||
"name": "Abyssal Tome of Weapon Mastery II",
|
||||
"tier": "Mythic",
|
||||
"type": "weaponTome",
|
||||
"category": "tome",
|
||||
"drop": "never",
|
||||
"restrict": "Soulbound Item",
|
||||
"lvl": 80,
|
||||
"damMobs": 12,
|
||||
"wDamPct": 7,
|
||||
"fixID": false,
|
||||
"id": 35,
|
||||
"alias": "Water Damage II"
|
||||
},
|
||||
{
|
||||
"name": "Infernal Tome of Weapon Mastery II",
|
||||
"tier": "Mythic",
|
||||
"type": "weaponTome",
|
||||
"category": "tome",
|
||||
"drop": "never",
|
||||
"restrict": "Soulbound Item",
|
||||
"lvl": 80,
|
||||
"damMobs": 12,
|
||||
"fDamPct": 7,
|
||||
"fixID": false,
|
||||
"id": 36,
|
||||
"alias": "Fire Damage II"
|
||||
},
|
||||
{
|
||||
"name": "Cyclonic Tome of Weapon Mastery II",
|
||||
"tier": "Mythic",
|
||||
"type": "weaponTome",
|
||||
"category": "tome",
|
||||
"drop": "never",
|
||||
"restrict": "Soulbound Item",
|
||||
"lvl": 80,
|
||||
"damMobs": 12,
|
||||
"aDamPct": 7,
|
||||
"fixID": false,
|
||||
"id": 37,
|
||||
"alias": "Air Damage II"
|
||||
},
|
||||
{
|
||||
"name": "Astral Tome of Weapon Mastery II",
|
||||
"tier": "Mythic",
|
||||
"type": "weaponTome",
|
||||
"category": "tome",
|
||||
"drop": "never",
|
||||
"restrict": "Soulbound Item",
|
||||
"lvl": 80,
|
||||
"damMobs": 12,
|
||||
"eDamPct": 6,
|
||||
"tDamPct": 6,
|
||||
"wDamPct": 6,
|
||||
"fDamPct": 6,
|
||||
"aDamPct": 6,
|
||||
"fixID": false,
|
||||
"id": 38,
|
||||
"alias": "Rainbow Damage II"
|
||||
},
|
||||
{
|
||||
"name": "Brute's Tome of Allegiance",
|
||||
"tier": "Legendary",
|
||||
"type": "guildTome",
|
||||
"category": "tome",
|
||||
"drop": "never",
|
||||
"restrict": "Untradable",
|
||||
"lvl": 100,
|
||||
"str": 3,
|
||||
"eDamPct": 2,
|
||||
"fixID": false,
|
||||
"id": 39,
|
||||
"alias": "Strength"
|
||||
},
|
||||
{
|
||||
"name": "Sadist's Tome of Allegiance",
|
||||
"tier": "Legendary",
|
||||
"type": "guildTome",
|
||||
"category": "tome",
|
||||
"drop": "never",
|
||||
"restrict": "Untradable",
|
||||
"lvl": 100,
|
||||
"dex": 3,
|
||||
"tDamPct": 2,
|
||||
"fixID": false,
|
||||
"id": 40,
|
||||
"alias": "Dexterity"
|
||||
},
|
||||
{
|
||||
"name": "Mastermind's Tome of Allegiance",
|
||||
"tier": "Legendary",
|
||||
"type": "guildTome",
|
||||
"category": "tome",
|
||||
"drop": "never",
|
||||
"restrict": "Untradable",
|
||||
"lvl": 100,
|
||||
"int": 3,
|
||||
"wDamPct": 2,
|
||||
"fixID": false,
|
||||
"id": 41,
|
||||
"alias": "Intelligence"
|
||||
},
|
||||
{
|
||||
"name": "Arsonist's Tome of Allegiance",
|
||||
"tier": "Legendary",
|
||||
"type": "guildTome",
|
||||
"category": "tome",
|
||||
"drop": "never",
|
||||
"restrict": "Untradable",
|
||||
"lvl": 100,
|
||||
"def": 3,
|
||||
"fDamPct": 2,
|
||||
"fixID": false,
|
||||
"id": 42,
|
||||
"alias": "Defense"
|
||||
},
|
||||
{
|
||||
"name": "Ghost's Tome of Allegiance",
|
||||
"tier": "Legendary",
|
||||
"type": "guildTome",
|
||||
"category": "tome",
|
||||
"drop": "never",
|
||||
"restrict": "Untradable",
|
||||
"lvl": 100,
|
||||
"agi": 3,
|
||||
"aDamPct": 2,
|
||||
"fixID": false,
|
||||
"id": 43,
|
||||
"alias": "Agility"
|
||||
},
|
||||
{
|
||||
"name": "Psychopath's Tome of Allegiance",
|
||||
"tier": "Legendary",
|
||||
"type": "guildTome",
|
||||
"category": "tome",
|
||||
"drop": "never",
|
||||
"restrict": "Untradable",
|
||||
"lvl": 100,
|
||||
"str": 2,
|
||||
"dex": 2,
|
||||
"fixID": false,
|
||||
"id": 44,
|
||||
"alias": "ET"
|
||||
},
|
||||
{
|
||||
"name": "Loner's Tome of Allegiance",
|
||||
"tier": "Legendary",
|
||||
"type": "guildTome",
|
||||
"category": "tome",
|
||||
"drop": "never",
|
||||
"restrict": "Untradable",
|
||||
"lvl": 100,
|
||||
"str": 2,
|
||||
"int": 2,
|
||||
"fixID": false,
|
||||
"id": 45,
|
||||
"alias": "EW"
|
||||
},
|
||||
{
|
||||
"name": "Warlock's Tome of Allegiance",
|
||||
"tier": "Legendary",
|
||||
"type": "guildTome",
|
||||
"category": "tome",
|
||||
"drop": "never",
|
||||
"restrict": "Untradable",
|
||||
"lvl": 100,
|
||||
"dex": 2,
|
||||
"int": 2,
|
||||
"fixID": false,
|
||||
"id": 46,
|
||||
"alias": "TW"
|
||||
},
|
||||
{
|
||||
"name": "Destroyer's Tome of Allegiance",
|
||||
"tier": "Legendary",
|
||||
"type": "guildTome",
|
||||
"category": "tome",
|
||||
"drop": "never",
|
||||
"restrict": "Untradable",
|
||||
"lvl": 100,
|
||||
"str": 2,
|
||||
"def": 2,
|
||||
"fixID": false,
|
||||
"id": 47,
|
||||
"alias": "EF"
|
||||
},
|
||||
{
|
||||
"name": "Devil's Tome of Allegiance",
|
||||
"tier": "Legendary",
|
||||
"type": "guildTome",
|
||||
"category": "tome",
|
||||
"drop": "never",
|
||||
"restrict": "Untradable",
|
||||
"lvl": 100,
|
||||
"dex": 2,
|
||||
"def": 2,
|
||||
"fixID": false,
|
||||
"id": 48,
|
||||
"alias": "TF"
|
||||
},
|
||||
{
|
||||
"name": "Alchemist's Tome of Allegiance",
|
||||
"tier": "Legendary",
|
||||
"type": "guildTome",
|
||||
"category": "tome",
|
||||
"drop": "never",
|
||||
"restrict": "Untradable",
|
||||
"lvl": 100,
|
||||
"int": 2,
|
||||
"def": 2,
|
||||
"fixID": false,
|
||||
"id": 49,
|
||||
"alias": "WF"
|
||||
},
|
||||
{
|
||||
"name": "Barbarian's Tome of Allegiance",
|
||||
"tier": "Legendary",
|
||||
"type": "guildTome",
|
||||
"category": "tome",
|
||||
"drop": "never",
|
||||
"restrict": "Untradable",
|
||||
"lvl": 100,
|
||||
"str": 2,
|
||||
"agi": 2,
|
||||
"fixID": false,
|
||||
"id": 50,
|
||||
"alias": "EA"
|
||||
},
|
||||
{
|
||||
"name": "Freelancer's Tome of Allegiance",
|
||||
"tier": "Legendary",
|
||||
"type": "guildTome",
|
||||
"category": "tome",
|
||||
"drop": "never",
|
||||
"restrict": "Untradable",
|
||||
"lvl": 100,
|
||||
"dex": 2,
|
||||
"agi": 2,
|
||||
"fixID": false,
|
||||
"id": 51,
|
||||
"alias": "TA"
|
||||
},
|
||||
{
|
||||
"name": "Sycophant's Tome of Allegiance",
|
||||
"tier": "Legendary",
|
||||
"type": "guildTome",
|
||||
"category": "tome",
|
||||
"drop": "never",
|
||||
"restrict": "Untradable",
|
||||
"lvl": 100,
|
||||
"int": 2,
|
||||
"agi": 2,
|
||||
"fixID": false,
|
||||
"id": 52,
|
||||
"alias": "WA"
|
||||
},
|
||||
{
|
||||
"name": "Fanatic's Tome of Allegiance",
|
||||
"tier": "Legendary",
|
||||
"type": "guildTome",
|
||||
"category": "tome",
|
||||
"drop": "never",
|
||||
"restrict": "Untradable",
|
||||
"lvl": 100,
|
||||
"def": 2,
|
||||
"agi": 2,
|
||||
"fixID": false,
|
||||
"id": 53,
|
||||
"alias": "FA"
|
||||
},
|
||||
{
|
||||
"name": "Assimilator's Tome of Allegiance",
|
||||
"tier": "Legendary",
|
||||
"type": "guildTome",
|
||||
"category": "tome",
|
||||
"drop": "never",
|
||||
"restrict": "Untradable",
|
||||
"lvl": 100,
|
||||
"str": 1,
|
||||
"dex": 1,
|
||||
"int": 1,
|
||||
"def": 1,
|
||||
"agi": 1,
|
||||
"fixID": false,
|
||||
"id": 54,
|
||||
"alias": "Rainbow"
|
||||
}
|
||||
]
|
||||
}
|
1
data/2.0.1.2/atree.json
Normal file
1
data/2.0.1.2/atree.json
Normal file
File diff suppressed because one or more lines are too long
1
data/2.0.1.2/ingreds.json
Normal file
1
data/2.0.1.2/ingreds.json
Normal file
File diff suppressed because one or more lines are too long
1
data/2.0.1.2/items.json
Normal file
1
data/2.0.1.2/items.json
Normal file
File diff suppressed because one or more lines are too long
1069
data/2.0.1.2/tomes.json
Normal file
1069
data/2.0.1.2/tomes.json
Normal file
File diff suppressed because it is too large
Load diff
|
@ -143,11 +143,82 @@
|
|||
|
||||
</div>
|
||||
<p>
|
||||
All build links will end in "#[version number]_[build hash]".
|
||||
All build links starting from Version 8 may look like "?v=[wynn version number]#[version number]_[build hash]".
|
||||
The query section is optional.
|
||||
</p>
|
||||
<p>
|
||||
All build links older than Version 8 look like "#[version number]_[build hash]".
|
||||
</p>
|
||||
<div class="row section" title="Version 8">
|
||||
<p>
|
||||
Version 8 was made to account for an oversight made when designing the tome encoding, and to signal the beginning of versions that support wynn version history. Version 8 and higher links may start with a query indicating the wynn version to use.
|
||||
</p>
|
||||
<p>
|
||||
Additionally, Version 8 uses 2 characters instead of 1 character to encode the ID of each tome. (The IDs representing NONE tomes does not change.)
|
||||
</p>
|
||||
</div>
|
||||
<div class="row section" title="Version 7">
|
||||
<p>
|
||||
Version 7 was made to account for ability trees in wynncraft 2.0. Version 7 introduces a new field at the end of the build hash, for ability tree data. Atree data is compressed using a depth first search algorithm into a binary blob, which is then base-64 encoded and appended to the V6 hash. The binry blob is decompressed by using the corresponding traversal.
|
||||
</p>
|
||||
<p>
|
||||
The tree structure defining the ability tree can be found in a json file (by default, <code>js/builder/atree_constants_min.json</code>). The file defines connections between the ability tree nodes: Each node has an unordered list of parent nodes, and an ordered list of child nodes.
|
||||
</p>
|
||||
<p>
|
||||
A reference implementation of the encoding/decoding algorithms can be found in <code>js/builder/build_encode_decode.js</code>. A pseudocode description of the algorithms is given here:
|
||||
</p>
|
||||
<code style="white-space: pre">
|
||||
// Encode an ability tree configuration into a binary blob.
|
||||
// NOTE: this algorithm only works for "connected" (valid) ability trees.
|
||||
// Its behavior is not well defined otherwise.
|
||||
//
|
||||
// Parameters:
|
||||
// tree_data: Object containing ability tree structure.
|
||||
// tree_state: Object containing info about which abilities are selected.
|
||||
function encode(tree_data, tree_state):
|
||||
|
||||
return_vector = BitVector()
|
||||
visited = Set()
|
||||
|
||||
function recursive_traverse(head_node):
|
||||
for each child of head_node, in order:
|
||||
if child is not in visited:
|
||||
add child to visited set
|
||||
if tree_state.is_active(child):
|
||||
append bit 1 to return_vector
|
||||
recursive_traverse(child)
|
||||
else:
|
||||
append bit 0 to return_vector
|
||||
|
||||
recursive_traverse(tree_data.root)
|
||||
return return_vector
|
||||
|
||||
// Decode a binary blob into an ability tree configuration
|
||||
//
|
||||
// Parameters:
|
||||
// tree_data: Object containing ability tree structure.
|
||||
// tree_state: Object containing info about which abilities are selected.
|
||||
// tree_bitvector: raw binary data, accessed one bit at a time
|
||||
function decode(tree_data, tree_state, tree_bitvector):
|
||||
|
||||
i = 0
|
||||
visited = Set()
|
||||
|
||||
function recursive_traverse(head_node):
|
||||
for each child of head_node, in order:
|
||||
if child is not in visited:
|
||||
add child to visited set
|
||||
if tree_bitvector[i]:
|
||||
child.active = True
|
||||
recursive_traverse(child)
|
||||
else:
|
||||
child.active = False
|
||||
i = i + 1
|
||||
</code>
|
||||
</div>
|
||||
<div class="row section" title="Version 6">
|
||||
<p>
|
||||
Version 6 was made to account for the desire to save tomes in a build. As of the last version of this documentation, version 6 is used for encoding whenever there are tomes in the build.
|
||||
Version 6 was made to account for the desire to save tomes in a build.
|
||||
</p>
|
||||
<div class = "row section" title = "Example 1: With Tomes">
|
||||
<code class="full-width">
|
||||
|
|
1545
ingreds_clean.json
1545
ingreds_clean.json
File diff suppressed because it is too large
Load diff
File diff suppressed because one or more lines are too long
|
@ -18,6 +18,7 @@ atree_node: {
|
|||
desc: str
|
||||
archetype: Optional[str] // not present or empty string = no arch
|
||||
archetype_req: Optional[int] // default: 0
|
||||
req_archetype: Optional[str] // what the req is for if no archetype defined... maybe clean up this data format later...?
|
||||
base_abil: Optional[int] // Modify another abil? poorly defined...
|
||||
parents: List[int]
|
||||
dependencies: List[int] // Hard reqs
|
||||
|
@ -107,6 +108,21 @@ scaling_target: {
|
|||
*/
|
||||
|
||||
|
||||
// Space for big json data
|
||||
let atrees;
|
||||
let atree_load_complete = false;
|
||||
/*
|
||||
* Load atree info remote DB (aka a big json file).
|
||||
*/
|
||||
async function load_atree_data(version_str) {
|
||||
let getUrl = window.location;
|
||||
let baseUrl = `${getUrl.protocol}//${getUrl.host}/`;
|
||||
// No random string -- we want to use caching
|
||||
let url = `${baseUrl}/data/${version_str}/atree.json`;
|
||||
atrees = await (await fetch(url)).json();
|
||||
atree_load_complete = true;
|
||||
}
|
||||
|
||||
const elem_mastery_abil = { display_name: "Elemental Mastery", id: 998, properties: {}, effects: [] };
|
||||
|
||||
// TODO: Range numbers
|
||||
|
@ -276,12 +292,17 @@ function abil_can_activate(atree_node, atree_state, reachable, archetype_count,
|
|||
if (!node_reachable) {
|
||||
return [false, false, 'not reachable'];
|
||||
}
|
||||
if ('archetype' in ability && ability.archetype !== "") {
|
||||
if ('archetype_req' in ability && ability.archetype_req !== 0) {
|
||||
const others = (archetype_count.get(ability.archetype) || 0);
|
||||
if (others < ability.archetype_req) {
|
||||
return [false, false, ability.archetype+': '+others+' < '+ability.archetype_req];
|
||||
}
|
||||
if ('archetype_req' in ability && ability.archetype_req !== 0) {
|
||||
let req_archetype;
|
||||
if ('req_archetype' in ability && ability.req_archetype !== "") {
|
||||
req_archetype = ability.req_archetype;
|
||||
}
|
||||
else {
|
||||
req_archetype = ability.archetype;
|
||||
}
|
||||
const others = (archetype_count.get(req_archetype) || 0);
|
||||
if (others < ability.archetype_req) {
|
||||
return [false, false, req_archetype+': '+others+' < '+ability.archetype_req];
|
||||
}
|
||||
}
|
||||
if (ability.cost > points_remain) {
|
||||
|
@ -1259,7 +1280,8 @@ function generateTooltip(container, node_elem, ability, atree_map) {
|
|||
// calculate if requirements are satisfied
|
||||
let apUsed = 0;
|
||||
let maxAP = parseInt(document.getElementById("active_AP_cap").innerHTML);
|
||||
let archChosen = 0;
|
||||
let arch_chosen = 0;
|
||||
const node_arch = ability.req_archetype || ability.archetype;
|
||||
let satisfiedDependencies = [];
|
||||
let blockedBy = [];
|
||||
for (let [id, node_wrap] of atree_map.entries()) {
|
||||
|
@ -1267,8 +1289,8 @@ function generateTooltip(container, node_elem, ability, atree_map) {
|
|||
continue; // we don't want to count abilities that are not selected, and an ability should not count towards itself
|
||||
}
|
||||
apUsed += node_wrap.ability.cost;
|
||||
if (node_wrap.ability.archetype == ability.archetype) {
|
||||
archChosen++;
|
||||
if (node_wrap.ability.archetype == node_arch) {
|
||||
arch_chosen++;
|
||||
}
|
||||
if (ability.dependencies.includes(id)) {
|
||||
satisfiedDependencies.push(id);
|
||||
|
@ -1292,15 +1314,21 @@ function generateTooltip(container, node_elem, ability, atree_map) {
|
|||
container.appendChild(cost);
|
||||
|
||||
// archetype req
|
||||
if (ability.archetype_req > 0 && ability.archetype != null) {
|
||||
let archReq = make_elem("p", ["scaled-font", "my-0", "mx-1"], {});
|
||||
if (archChosen >= ability.archetype_req) {
|
||||
archReq.innerHTML = reqYes;
|
||||
} else {
|
||||
archReq.innerHTML = reqNo;
|
||||
if (ability.archetype_req > 0) {
|
||||
let arch_req = make_elem("p", ["scaled-font", "my-0", "mx-1"], {});
|
||||
if ('req_archetype' in ability && ability.req_archetype !== "") {
|
||||
req_archetype = ability.req_archetype;
|
||||
}
|
||||
archReq.innerHTML += "<span class = 'mc-gray'>Min " + ability.archetype + " Archetype:</span> " + archChosen + "<span class = 'mc-gray'>/" + ability.archetype_req;
|
||||
container.appendChild(archReq);
|
||||
else {
|
||||
req_archetype = ability.archetype;
|
||||
}
|
||||
if (arch_chosen >= ability.archetype_req) {
|
||||
arch_req.innerHTML = reqYes;
|
||||
} else {
|
||||
arch_req.innerHTML = reqNo;
|
||||
}
|
||||
arch_req.innerHTML += "<span class = 'mc-gray'>Min " + req_archetype+ " Archetype:</span> " + arch_chosen + "<span class = 'mc-gray'>/" + ability.archetype_req;
|
||||
container.appendChild(arch_req);
|
||||
}
|
||||
|
||||
// dependencies
|
||||
|
|
File diff suppressed because it is too large
Load diff
File diff suppressed because one or more lines are too long
|
@ -27,128 +27,200 @@ function parsePowdering(powder_info) {
|
|||
}
|
||||
|
||||
let atree_data = null;
|
||||
const wynn_version_names = [
|
||||
'2.0.1.1',
|
||||
'2.0.1.2'
|
||||
];
|
||||
const WYNN_VERSION_LATEST = wynn_version_names.length - 1;
|
||||
// Default to the newest version.
|
||||
let wynn_version_id = WYNN_VERSION_LATEST;
|
||||
|
||||
/*
|
||||
* Populate fields based on url, and calculate build.
|
||||
* TODO: THIS CODE IS GOD AWFUL result of being lazy
|
||||
* fix all the slice() and break into functions or do something about it... its inefficient, ugly and error prone
|
||||
*/
|
||||
function decodeBuild(url_tag) {
|
||||
if (url_tag) {
|
||||
//default values
|
||||
let equipment = [null, null, null, null, null, null, null, null, null];
|
||||
let tomes = [null, null, null, null, null, null, null];
|
||||
let powdering = ["", "", "", "", ""];
|
||||
let info = url_tag.split("_");
|
||||
let version = info[0];
|
||||
let save_skp = false;
|
||||
let skillpoints = [0, 0, 0, 0, 0];
|
||||
let level = 106;
|
||||
async function parse_hash(url_tag) {
|
||||
const default_load_promises = [ load_atree_data(wynn_version_names[WYNN_VERSION_LATEST]),
|
||||
load_init(), load_ing_init(), load_tome_init() ];
|
||||
if (!url_tag) {
|
||||
await Promise.all(default_load_promises);
|
||||
return;
|
||||
}
|
||||
//default values
|
||||
let equipment = [null, null, null, null, null, null, null, null, null];
|
||||
let tomes = [null, null, null, null, null, null, null];
|
||||
let powdering = ["", "", "", "", ""];
|
||||
let info = url_tag.split("_");
|
||||
let version = info[0];
|
||||
let save_skp = false;
|
||||
let skillpoints = [0, 0, 0, 0, 0];
|
||||
let level = 106;
|
||||
|
||||
let version_number = parseInt(version)
|
||||
//equipment (items)
|
||||
// TODO: use filters
|
||||
if (version_number < 4) {
|
||||
let equipments = info[1];
|
||||
for (let i = 0; i < 9; ++i ) {
|
||||
let equipment_str = equipments.slice(i*3,i*3+3);
|
||||
let version_number = parseInt(version);
|
||||
let data_str = info[1];
|
||||
if (version_number >= 8) {
|
||||
// parse query parameters
|
||||
// https://stackoverflow.com/questions/901115/how-can-i-get-query-string-values-in-javascript
|
||||
const url_params = new URLSearchParams(window.location.search);
|
||||
const version_id = url_params.get('v');
|
||||
wynn_version_id = parseInt(version_id);
|
||||
if (isNaN(wynn_version_id) || wynn_version_id > WYNN_VERSION_LATEST || wynn_version_id < 0) {
|
||||
// TODO: maybe make the NAN try to use the human readable version?
|
||||
// NOTE: Failing silently... do we want to raise a loud error?
|
||||
console.log("Explicit version not found or invalid, using latest version");
|
||||
wynn_version_id = WYNN_VERSION_LATEST;
|
||||
}
|
||||
else {
|
||||
console.log(`Build link for wynn version ${wynn_version_id} (${wynn_version_names[wynn_version_id]})`);
|
||||
}
|
||||
}
|
||||
else {
|
||||
// Change the default to oldest. (A time before v8)
|
||||
wynn_version_id = 0;
|
||||
}
|
||||
|
||||
// the deal with this is because old versions should default to 0 (oldest wynn item version), and v8+ defaults to latest.
|
||||
// its ugly... but i think this is the behavior we want...
|
||||
if (wynn_version_id != WYNN_VERSION_LATEST) {
|
||||
// force reload item database and such.
|
||||
// TODO MUST: display a warning showing older version!
|
||||
const msg = 'This build was created in an older version of wynncraft '
|
||||
+ `(${wynn_version_names[wynn_version_id]} < ${wynn_version_names[WYNN_VERSION_LATEST]}). `
|
||||
+ 'Would you like to update to the latest version? Updating may break the build and ability tree.';
|
||||
|
||||
if (confirm(msg)) {
|
||||
wynn_version_id = WYNN_VERSION_LATEST;
|
||||
}
|
||||
else {
|
||||
version_name = wynn_version_names[wynn_version_id];
|
||||
const load_promises = [ load_atree_data(version_name),
|
||||
load_old_version(version_name),
|
||||
load_ings_old_version(version_name),
|
||||
load_tome_old_version(version_name) ];
|
||||
console.log("Loading old version data...", version_name)
|
||||
await Promise.all(load_promises);
|
||||
}
|
||||
}
|
||||
if (wynn_version_id == WYNN_VERSION_LATEST) {
|
||||
await Promise.all(default_load_promises);
|
||||
}
|
||||
|
||||
//equipment (items)
|
||||
// TODO: use filters
|
||||
if (version_number < 4) {
|
||||
let equipments = info[1];
|
||||
for (let i = 0; i < 9; ++i ) {
|
||||
let equipment_str = equipments.slice(i*3,i*3+3);
|
||||
equipment[i] = getItemNameFromID(Base64.toInt(equipment_str));
|
||||
}
|
||||
data_str = equipments.slice(27);
|
||||
}
|
||||
else if (version_number == 4) {
|
||||
let info_str = data_str;
|
||||
let start_idx = 0;
|
||||
for (let i = 0; i < 9; ++i ) {
|
||||
if (info_str.charAt(start_idx) === "-") {
|
||||
equipment[i] = "CR-"+info_str.slice(start_idx+1, start_idx+18);
|
||||
start_idx += 18;
|
||||
}
|
||||
else {
|
||||
let equipment_str = info_str.slice(start_idx, start_idx+3);
|
||||
equipment[i] = getItemNameFromID(Base64.toInt(equipment_str));
|
||||
start_idx += 3;
|
||||
}
|
||||
info[1] = equipments.slice(27);
|
||||
}
|
||||
else if (version_number == 4) {
|
||||
let info_str = info[1];
|
||||
let start_idx = 0;
|
||||
for (let i = 0; i < 9; ++i ) {
|
||||
if (info_str.charAt(start_idx) === "-") {
|
||||
equipment[i] = "CR-"+info_str.slice(start_idx+1, start_idx+18);
|
||||
start_idx += 18;
|
||||
}
|
||||
else {
|
||||
let equipment_str = info_str.slice(start_idx, start_idx+3);
|
||||
equipment[i] = getItemNameFromID(Base64.toInt(equipment_str));
|
||||
start_idx += 3;
|
||||
}
|
||||
data_str = info_str.slice(start_idx);
|
||||
}
|
||||
else if (version_number <= 8) {
|
||||
let info_str = data_str;
|
||||
let start_idx = 0;
|
||||
for (let i = 0; i < 9; ++i ) {
|
||||
if (info_str.slice(start_idx,start_idx+3) === "CR-") {
|
||||
equipment[i] = info_str.slice(start_idx, start_idx+20);
|
||||
start_idx += 20;
|
||||
} else if (info_str.slice(start_idx+3,start_idx+6) === "CI-") {
|
||||
let len = Base64.toInt(info_str.slice(start_idx,start_idx+3));
|
||||
equipment[i] = info_str.slice(start_idx+3,start_idx+3+len);
|
||||
start_idx += (3+len);
|
||||
} else {
|
||||
let equipment_str = info_str.slice(start_idx, start_idx+3);
|
||||
equipment[i] = getItemNameFromID(Base64.toInt(equipment_str));
|
||||
start_idx += 3;
|
||||
}
|
||||
info[1] = info_str.slice(start_idx);
|
||||
}
|
||||
else if (version_number <= 7) {
|
||||
let info_str = info[1];
|
||||
let start_idx = 0;
|
||||
for (let i = 0; i < 9; ++i ) {
|
||||
if (info_str.slice(start_idx,start_idx+3) === "CR-") {
|
||||
equipment[i] = info_str.slice(start_idx, start_idx+20);
|
||||
start_idx += 20;
|
||||
} else if (info_str.slice(start_idx+3,start_idx+6) === "CI-") {
|
||||
let len = Base64.toInt(info_str.slice(start_idx,start_idx+3));
|
||||
equipment[i] = info_str.slice(start_idx+3,start_idx+3+len);
|
||||
start_idx += (3+len);
|
||||
} else {
|
||||
let equipment_str = info_str.slice(start_idx, start_idx+3);
|
||||
equipment[i] = getItemNameFromID(Base64.toInt(equipment_str));
|
||||
start_idx += 3;
|
||||
}
|
||||
}
|
||||
info[1] = info_str.slice(start_idx);
|
||||
}
|
||||
//constant in all versions
|
||||
for (let i in equipment) {
|
||||
setValue(equipment_inputs[i], equipment[i]);
|
||||
data_str = info_str.slice(start_idx);
|
||||
}
|
||||
//constant in all versions
|
||||
for (let i in equipment) {
|
||||
setValue(equipment_inputs[i], equipment[i]);
|
||||
}
|
||||
|
||||
//level, skill point assignments, and powdering
|
||||
if (version_number == 1) {
|
||||
let powder_info = data_str;
|
||||
let res = parsePowdering(powder_info);
|
||||
powdering = res[0];
|
||||
} else if (version_number == 2) {
|
||||
save_skp = true;
|
||||
let skillpoint_info = data_str.slice(0, 10);
|
||||
for (let i = 0; i < 5; ++i ) {
|
||||
skillpoints[i] = Base64.toIntSigned(skillpoint_info.slice(i*2,i*2+2));
|
||||
}
|
||||
|
||||
//level, skill point assignments, and powdering
|
||||
if (version_number == 1) {
|
||||
let powder_info = info[1];
|
||||
let res = parsePowdering(powder_info);
|
||||
powdering = res[0];
|
||||
} else if (version_number == 2) {
|
||||
save_skp = true;
|
||||
let skillpoint_info = info[1].slice(0, 10);
|
||||
for (let i = 0; i < 5; ++i ) {
|
||||
skillpoints[i] = Base64.toIntSigned(skillpoint_info.slice(i*2,i*2+2));
|
||||
}
|
||||
|
||||
let powder_info = info[1].slice(10);
|
||||
let res = parsePowdering(powder_info);
|
||||
powdering = res[0];
|
||||
} else if (version_number <= 7){
|
||||
level = Base64.toInt(info[1].slice(10,12));
|
||||
setValue("level-choice",level);
|
||||
save_skp = true;
|
||||
let skillpoint_info = info[1].slice(0, 10);
|
||||
for (let i = 0; i < 5; ++i ) {
|
||||
skillpoints[i] = Base64.toIntSigned(skillpoint_info.slice(i*2,i*2+2));
|
||||
}
|
||||
|
||||
let powder_info = info[1].slice(12);
|
||||
|
||||
let res = parsePowdering(powder_info);
|
||||
powdering = res[0];
|
||||
info[1] = res[1];
|
||||
let powder_info = data_str.slice(10);
|
||||
let res = parsePowdering(powder_info);
|
||||
powdering = res[0];
|
||||
} else if (version_number <= 8){
|
||||
level = Base64.toInt(data_str.slice(10,12));
|
||||
setValue("level-choice",level);
|
||||
save_skp = true;
|
||||
let skillpoint_info = data_str.slice(0, 10);
|
||||
for (let i = 0; i < 5; ++i ) {
|
||||
skillpoints[i] = Base64.toIntSigned(skillpoint_info.slice(i*2,i*2+2));
|
||||
}
|
||||
// Tomes.
|
||||
if (version >= 6) {
|
||||
//tome values do not appear in anything before v6.
|
||||
|
||||
let powder_info = data_str.slice(12);
|
||||
|
||||
let res = parsePowdering(powder_info);
|
||||
powdering = res[0];
|
||||
data_str = res[1];
|
||||
}
|
||||
// Tomes.
|
||||
if (version_number >= 6) {
|
||||
//tome values do not appear in anything before v6.
|
||||
if (version_number < 8) {
|
||||
for (let i in tomes) {
|
||||
let tome_str = info[1].charAt(i);
|
||||
let tome_str = data_str.charAt(i);
|
||||
let tome_name = getTomeNameFromID(Base64.toInt(tome_str));
|
||||
setValue(tomeInputs[i], tome_name);
|
||||
}
|
||||
info[1] = info[1].slice(7);
|
||||
}
|
||||
|
||||
if (version >= 7) {
|
||||
// ugly af. only works since its the last thing. will be fixed with binary decode
|
||||
atree_data = new BitVector(info[1]);
|
||||
data_str = data_str.slice(7);
|
||||
}
|
||||
else {
|
||||
atree_data = null;
|
||||
// 2chr tome encoding to allow for more tomes.
|
||||
for (let i in tomes) {
|
||||
let tome_str = data_str.slice(2*i, 2*i+2);
|
||||
let tome_name = getTomeNameFromID(Base64.toInt(tome_str));
|
||||
setValue(tomeInputs[i], tome_name);
|
||||
}
|
||||
data_str = data_str.slice(14);
|
||||
}
|
||||
}
|
||||
|
||||
for (let i in powder_inputs) {
|
||||
setValue(powder_inputs[i], powdering[i]);
|
||||
}
|
||||
for (let i in skillpoints) {
|
||||
setValue(skp_order[i] + "-skp", skillpoints[i]);
|
||||
}
|
||||
if (version_number >= 7) {
|
||||
// ugly af. only works since its the last thing. will be fixed with binary decode
|
||||
atree_data = new BitVector(data_str);
|
||||
}
|
||||
else {
|
||||
atree_data = null;
|
||||
}
|
||||
|
||||
for (let i in powder_inputs) {
|
||||
setValue(powder_inputs[i], powdering[i]);
|
||||
}
|
||||
for (let i in skillpoints) {
|
||||
setValue(skp_order[i] + "-skp", skillpoints[i]);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -161,7 +233,8 @@ function encodeBuild(build, powders, skillpoints, atree, atree_state) {
|
|||
|
||||
//V6 encoding - Tomes
|
||||
//V7 encoding - ATree
|
||||
build_version = 5;
|
||||
//V8 encoding - wynn version
|
||||
build_version = 8;
|
||||
build_string = "";
|
||||
tome_string = "";
|
||||
|
||||
|
@ -169,16 +242,16 @@ function encodeBuild(build, powders, skillpoints, atree, atree_state) {
|
|||
if (item.statMap.get("custom")) {
|
||||
let custom = "CI-"+encodeCustom(item, true);
|
||||
build_string += Base64.fromIntN(custom.length, 3) + custom;
|
||||
build_version = Math.max(build_version, 5);
|
||||
//build_version = Math.max(build_version, 5);
|
||||
} else if (item.statMap.get("crafted")) {
|
||||
build_string += "CR-"+encodeCraft(item);
|
||||
} else if (item.statMap.get("category") === "tome") {
|
||||
let tome_id = item.statMap.get("id");
|
||||
if (tome_id <= 60) {
|
||||
// valid normal tome. ID 61-63 is for NONE tomes.
|
||||
build_version = Math.max(build_version, 6);
|
||||
//build_version = Math.max(build_version, 6);
|
||||
}
|
||||
tome_string += Base64.fromIntN(tome_id, 1);
|
||||
tome_string += Base64.fromIntN(tome_id, 2);
|
||||
} else {
|
||||
build_string += Base64.fromIntN(item.statMap.get("id"), 3);
|
||||
}
|
||||
|
@ -206,7 +279,7 @@ function encodeBuild(build, powders, skillpoints, atree, atree_state) {
|
|||
build_string += tome_string;
|
||||
|
||||
if (atree.length > 0 && atree_state.get(atree[0].ability.id).active) {
|
||||
build_version = Math.max(build_version, 7);
|
||||
//build_version = Math.max(build_version, 7);
|
||||
const bitvec = encode_atree(atree, atree_state);
|
||||
build_string += bitvec.toB64();
|
||||
}
|
||||
|
@ -215,14 +288,18 @@ function encodeBuild(build, powders, skillpoints, atree, atree_state) {
|
|||
}
|
||||
}
|
||||
|
||||
function get_full_url() {
|
||||
return `${url_base}?v=${wynn_version_id.toString()}${location.hash}`
|
||||
}
|
||||
|
||||
function copyBuild() {
|
||||
copyTextToClipboard(url_base+location.hash);
|
||||
copyTextToClipboard();
|
||||
document.getElementById("copy-button").textContent = "Copied!";
|
||||
}
|
||||
|
||||
function shareBuild(build) {
|
||||
if (build) {
|
||||
let text = url_base+location.hash+"\n"+
|
||||
let text = url_base+'?v='+wynn_version_id.toString()+location.hash+"\n"+
|
||||
"WynnBuilder build:\n"+
|
||||
"> "+build.items[0].statMap.get("displayName")+"\n"+
|
||||
"> "+build.items[1].statMap.get("displayName")+"\n"+
|
||||
|
|
|
@ -47,6 +47,8 @@ function loadBuild() {
|
|||
let saveName = document.getElementById("build-name").value;
|
||||
|
||||
if (Object.keys(savedBuilds).includes(saveName)) {
|
||||
// NOTE: this is broken since decodeBuild is async func.
|
||||
// Doubly broken because of versioning... lets just kill this for now
|
||||
decodeBuild(savedBuilds[saveName])
|
||||
document.getElementById("loaded-error").textContent = "";
|
||||
document.getElementById("loaded-build").textContent = "Build loaded";
|
||||
|
@ -305,9 +307,8 @@ function collapse_element(elmnt) {
|
|||
document.querySelector(elmnt).style.removeProperty('display');
|
||||
}
|
||||
|
||||
function init() {
|
||||
async function init() {
|
||||
console.log("builder.js init");
|
||||
init_autocomplete();
|
||||
|
||||
// Other "main" stuff
|
||||
// Spell dropdowns
|
||||
|
@ -329,34 +330,41 @@ function init() {
|
|||
}
|
||||
|
||||
// Masonry setup
|
||||
let masonry = Macy({
|
||||
container: "#masonry-container",
|
||||
columns: 1,
|
||||
mobileFirst: true,
|
||||
breakAt: {
|
||||
1200: 4,
|
||||
},
|
||||
margin: {
|
||||
x: 20,
|
||||
y: 20,
|
||||
}
|
||||
|
||||
});
|
||||
try {
|
||||
let masonry = Macy({
|
||||
container: "#masonry-container",
|
||||
columns: 1,
|
||||
mobileFirst: true,
|
||||
breakAt: {
|
||||
1200: 4,
|
||||
},
|
||||
margin: {
|
||||
x: 20,
|
||||
y: 20,
|
||||
}
|
||||
});
|
||||
|
||||
let search_masonry = Macy({
|
||||
container: "#search-results",
|
||||
columns: 1,
|
||||
mobileFirst: true,
|
||||
breakAt: {
|
||||
1200: 4,
|
||||
},
|
||||
margin: {
|
||||
x: 20,
|
||||
y: 20,
|
||||
}
|
||||
|
||||
});
|
||||
decodeBuild(url_tag);
|
||||
let search_masonry = Macy({
|
||||
container: "#search-results",
|
||||
columns: 1,
|
||||
mobileFirst: true,
|
||||
breakAt: {
|
||||
1200: 4,
|
||||
},
|
||||
margin: {
|
||||
x: 20,
|
||||
y: 20,
|
||||
}
|
||||
});
|
||||
} catch (e) {
|
||||
console.log("Could not initialize macy components. Maybe you're offline?");
|
||||
}
|
||||
await parse_hash(url_tag);
|
||||
try {
|
||||
init_autocomplete();
|
||||
} catch (e) {
|
||||
console.log("Could not initialize autocomplete. Maybe you're offline?");
|
||||
}
|
||||
builder_graph_init();
|
||||
for (const item_node of item_nodes) {
|
||||
if (item_node.get_value() === null) {
|
||||
|
@ -364,6 +372,7 @@ function init() {
|
|||
if (confirm('One or more items failed to load correctly. This could be due to a corrupted build link, or (more likely) a database load failure. Would you like to reload?')) {
|
||||
hardReload();
|
||||
}
|
||||
console.log(item_node);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
@ -375,7 +384,5 @@ window.onerror = function(message, source, lineno, colno, error) {
|
|||
};
|
||||
|
||||
(async function() {
|
||||
let load_promises = [ load_init(), load_ing_init(), load_tome_init() ];
|
||||
await Promise.all(load_promises);
|
||||
init();
|
||||
await init();
|
||||
})();
|
||||
|
|
26
js/load.js
26
js/load.js
|
@ -1,4 +1,4 @@
|
|||
const DB_VERSION = 117;
|
||||
const DB_VERSION = 118;
|
||||
// @See https://github.com/mdn/learning-area/blob/master/javascript/apis/client-side-storage/indexeddb/video-store/index.jsA
|
||||
|
||||
let db;
|
||||
|
@ -92,13 +92,31 @@ function clean_item(item) {
|
|||
}
|
||||
}
|
||||
|
||||
async function load_old_version(version_str) {
|
||||
load_in_progress = true;
|
||||
let getUrl = window.location;
|
||||
let baseUrl = `${getUrl.protocol}//${getUrl.host}/`;
|
||||
// No random string -- we want to use caching
|
||||
let url = `${baseUrl}/data/${version_str}/items.json`;
|
||||
let result = await (await fetch(url)).json();
|
||||
items = result.items;
|
||||
for (const item of items) {
|
||||
clean_item(item);
|
||||
}
|
||||
let sets_ = result.sets;
|
||||
for (const set in sets_) {
|
||||
sets.set(set, sets_[set]);
|
||||
}
|
||||
init_maps();
|
||||
load_complete = true;
|
||||
}
|
||||
|
||||
/*
|
||||
* Load item set from remote DB (aka a big json file). Calls init() on success.
|
||||
*/
|
||||
async function load() {
|
||||
|
||||
let getUrl = window.location;
|
||||
let baseUrl = getUrl.protocol + "//" + getUrl.host + "/";// + getUrl.pathname.split('/')[1];
|
||||
let baseUrl = `${getUrl.protocol}//${getUrl.host}/`;
|
||||
// "Random" string to prevent caching!
|
||||
let url = baseUrl + "/compress.json?"+new Date();
|
||||
let result = await (await fetch(url)).json();
|
||||
|
@ -150,7 +168,7 @@ async function load_init() {
|
|||
console.log("Skipping load...")
|
||||
}
|
||||
else {
|
||||
load_in_progress = true
|
||||
load_in_progress = true;
|
||||
if (reload) {
|
||||
console.log("Using new data...")
|
||||
await load();
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
const ING_DB_VERSION = 18;
|
||||
const ING_DB_VERSION = 19;
|
||||
|
||||
// @See https://github.com/mdn/learning-area/blob/master/javascript/apis/client-side-storage/indexeddb/video-store/index.js
|
||||
|
||||
|
@ -59,22 +59,41 @@ function clean_ing(ing) {
|
|||
}
|
||||
}
|
||||
|
||||
async function load_ings_old_version(version_str) {
|
||||
iload_in_progress = true;
|
||||
let getUrl = window.location;
|
||||
let baseUrl = `${getUrl.protocol}//${getUrl.host}/`;
|
||||
// No random string -- we want to use caching
|
||||
let url = `${baseUrl}/data/${version_str}/ingreds.json`;
|
||||
let result = await (await fetch(url)).json();
|
||||
ings = result;
|
||||
for (const id in ings) {
|
||||
clean_ing(ings[id]);
|
||||
}
|
||||
|
||||
url = baseUrl + "/recipes_compress.json";
|
||||
result = await (await fetch(url)).json();
|
||||
recipes = result.recipes;
|
||||
|
||||
init_maps();
|
||||
iload_complete = true;
|
||||
}
|
||||
|
||||
/*
|
||||
* Load item set from remote DB (aka a big json file). Calls init() on success.
|
||||
*/
|
||||
async function load_ings() {
|
||||
|
||||
let getUrl = window.location;
|
||||
let baseUrl = getUrl.protocol + "//" + getUrl.host + "/";// + getUrl.pathname.split('/')[1];
|
||||
let baseUrl = `${getUrl.protocol}//${getUrl.host}/`;
|
||||
// "Random" string to prevent caching!
|
||||
let url = baseUrl + "/ingreds_compress.json?"+new Date();
|
||||
url = url.replace(/\w+.html/, "") ;
|
||||
let result = await (await fetch(url)).json();
|
||||
|
||||
result = await (await fetch(url)).json();
|
||||
ings = result;
|
||||
|
||||
url = url.replace("/ingreds_compress.json", "/recipes_compress.json");
|
||||
url = baseUrl + "/recipes_compress.json?"+new Date();
|
||||
result = await (await fetch(url)).json();
|
||||
recipes = result.recipes;
|
||||
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
const TOME_DB_VERSION = 5;
|
||||
const TOME_DB_VERSION = 6;
|
||||
// @See https://github.com/mdn/learning-area/blob/master/javascript/apis/client-side-storage/indexeddb/video-store/index.jsA
|
||||
|
||||
let tdb;
|
||||
|
@ -34,13 +34,27 @@ async function load_tome_local() {
|
|||
});
|
||||
}
|
||||
|
||||
async function load_tome_old_version(version_str) {
|
||||
tload_in_progress = true;
|
||||
let getUrl = window.location;
|
||||
let baseUrl = `${getUrl.protocol}//${getUrl.host}/`;
|
||||
// No random string -- we want to use caching
|
||||
let url = `${baseUrl}/data/${version_str}/tomes.json`;
|
||||
let result = await (await fetch(url)).json();
|
||||
tomes = result.tomes;
|
||||
for (const tome of tomes) {
|
||||
//dependency on clean_item in load.js
|
||||
clean_item(tome);
|
||||
}
|
||||
init_tome_maps();
|
||||
tload_complete = true;
|
||||
}
|
||||
/*
|
||||
* Load tome set from remote DB (json). Calls init() on success.
|
||||
*/
|
||||
async function load_tome() {
|
||||
|
||||
let getUrl = window.location;
|
||||
let baseUrl = getUrl.protocol + "//" + getUrl.host + "/";// + getUrl.pathname.split('/')[1];
|
||||
let baseUrl = `${getUrl.protocol}//${getUrl.host}/`;
|
||||
// "Random" string to prevent caching!
|
||||
let url = baseUrl + "/tomes.json?"+new Date();
|
||||
let result = await (await fetch(url)).json();
|
||||
|
|
|
@ -3647,10 +3647,6 @@
|
|||
"Mask of the Spirits": 3649,
|
||||
"Inhibitor": 3650,
|
||||
"Spear of Testiness": 3651,
|
||||
"Blue Wynnter Sweater": 3648,
|
||||
"Green Wynnter Sweater": 3649,
|
||||
"Purple Wynnter Sweater": 3650,
|
||||
"Red Wynnter Sweater": 3651,
|
||||
"Snowtread Boots": 3652,
|
||||
"White Wynnter Sweater": 3653,
|
||||
"Keratoconus": 3579,
|
||||
|
@ -3768,5 +3764,35 @@
|
|||
"Sharpened Seaglass": 3762,
|
||||
"Storyteller": 3763,
|
||||
"Midnight Sun": 3764,
|
||||
"Lachesism": 3765
|
||||
"Lachesism": 3765,
|
||||
"Bison Tipper": 3766,
|
||||
"Decaying Headdress": 3767,
|
||||
"Despondence": 3768,
|
||||
"Expedition's End": 3769,
|
||||
"Fire Sword Style-2": 3770,
|
||||
"Black Wynnter Sweater": 3771,
|
||||
"Brown Wynnter Sweater": 3772,
|
||||
"Cerulean Wynnter Sweater": 3773,
|
||||
"Pink Wynnter Sweater": 3774,
|
||||
"Yellow Wynnter Sweater": 3775,
|
||||
"Poison-Tipped Poleaxe": 3776,
|
||||
"Compliance": 3777,
|
||||
"Dispersion": 3778,
|
||||
"Obstinance": 3779,
|
||||
"Succession": 3780,
|
||||
"Continuum": 3781,
|
||||
"Divergence": 3782,
|
||||
"Aleph Null": 3783,
|
||||
"Fractal": 3784,
|
||||
"Nonexistence": 3785,
|
||||
"Infinitesimal": 3786,
|
||||
"Recursion": 3787,
|
||||
"Soul Ink": 3788,
|
||||
"Swimmer Net": 3789,
|
||||
"Unusual": 3790,
|
||||
"Santa Earmuffs": 3791,
|
||||
"Blue Wynnter Sweater": 3792,
|
||||
"Green Wynnter Sweater": 3793,
|
||||
"Purple Wynnter Sweater": 3794,
|
||||
"Red Wynnter Sweater": 3795
|
||||
}
|
|
@ -717,5 +717,18 @@
|
|||
"Windswept Roots": 705,
|
||||
"Yale Leather": 706,
|
||||
"Contraband Hibiscus": 717,
|
||||
"Myocardial Leg": 718
|
||||
"Myocardial Leg": 718,
|
||||
"Broken Ram Horn": 719,
|
||||
"Climber's Padding": 720,
|
||||
"Rusty Spurs": 721,
|
||||
"Sheep Hoof": 722,
|
||||
"Consecrated Ivory": 723,
|
||||
"Intermittenstirrups": 724,
|
||||
"Natural Nitrates": 725,
|
||||
"Pigman Ivory": 726,
|
||||
"Runner's Bandages": 727,
|
||||
"Blazing Stimulants": 728,
|
||||
"Icy Crampons": 729,
|
||||
"Sanctified Sheep Soul": 730,
|
||||
"Solcrystal Horn": 731
|
||||
}
|
|
@ -5,3 +5,5 @@ Version 3: http://localhost:8000/#3_0250px0uX0K50K20OK0OJ00A0Qe1z+m21001M1g00001
|
|||
Version 3: http://localhost:8000/#3_0K60iv0CE0Qt0BK0BK0K40Jc0uG160V050o1L1g00001003C6
|
||||
Version 4: http://localhost:8000/#4_-1+W+W+W+W+W+W9g91-1+W+W+W+W+W+W9d91-1+W+W+W+W+W+W9i9--1+W+W+W+W+W+W9a91-1+W+W+W+W+W+W9m91-1+W+W+W+W+W+W9m91-1+W+W+W+W+W+W9c91-1+W+W+W+W+W+W9n91-1+W+W+W+W+W+W9q9100000000001g000010036C
|
||||
Version 5 (CI): http://localhost:8000/index.html#5_0lS0JX0u50tv00nCI-10000MFlipped%20Lapis%20Ring0200540M01010V010m0K20OL0og00-CI-110230401030570A07287-3530F40M0201d0c07287-3530w023zu100202e-Y0i211q-Y1g00000
|
||||
Version 6: (tomes): https://localhost:8000/builder/#6_02509-0p00Qj0K2CR-19i7n9i7n9C7J9m910T40Ji0R1-t+f1k-P2W1g00001007lUbW51I6p
|
||||
Version 7 (atree): http://localhost:8000/builder/#7_0ZP0iv0uR0Lg00502C0K40uY0BE161a+W0o161g00001001Z6zz++++--6l-VU6
|
BIN
regression_tests/v6.png
Executable file
BIN
regression_tests/v6.png
Executable file
Binary file not shown.
After Width: | Height: | Size: 128 KiB |
BIN
regression_tests/v7.png
Executable file
BIN
regression_tests/v7.png
Executable file
Binary file not shown.
After Width: | Height: | Size: 304 KiB |
|
@ -53,5 +53,23 @@
|
|||
"Freelancer's Tome of Allegiance": 51,
|
||||
"Sycophant's Tome of Allegiance": 52,
|
||||
"Fanatic's Tome of Allegiance": 53,
|
||||
"Assimilator's Tome of Allegiance": 54
|
||||
}
|
||||
"Assimilator's Tome of Allegiance": 54,
|
||||
"Ephemeral Tome of Weapon Mastery I": 55,
|
||||
"Ephemeral Tome of Weapon Mastery II": 56,
|
||||
"Ephemeral Tome of Weapon Mastery III": 57,
|
||||
"Harvester's Tome of Weapon Mastery I": 58,
|
||||
"Harvester's Tome of Weapon Mastery II": 59,
|
||||
"Harvester's Tome of Weapon Mastery III": 60,
|
||||
"Earthbound Tome of Weapon Mastery III": 64,
|
||||
"Nimble Tome of Weapon Mastery III": 65,
|
||||
"Mystical Tome of Weapon Mastery III": 66,
|
||||
"Warding Tome of Weapon Mastery III": 67,
|
||||
"Athletic Tome of Weapon Mastery III": 68,
|
||||
"Cosmic Tome of Weapon Mastery III": 69,
|
||||
"Seismic Tome of Weapon Mastery III": 70,
|
||||
"Voltaic Tome of Weapon Mastery III": 71,
|
||||
"Abyssal Tome of Weapon Mastery III": 72,
|
||||
"Infernal Tome of Weapon Mastery III": 73,
|
||||
"Cyclonic Tome of Weapon Mastery III": 74,
|
||||
"Astral Tome of Weapon Mastery III": 75
|
||||
}
|
||||
|
|
272
tomes.json
272
tomes.json
|
@ -321,7 +321,7 @@
|
|||
"category": "tome",
|
||||
"drop": "never",
|
||||
"restrict": "Soulbound Item",
|
||||
"lvl": 80,
|
||||
"lvl": 60,
|
||||
"damMobs": 7,
|
||||
"str": 3,
|
||||
"fixID": false,
|
||||
|
@ -349,7 +349,7 @@
|
|||
"category": "tome",
|
||||
"drop": "never",
|
||||
"restrict": "Soulbound Item",
|
||||
"lvl": 80,
|
||||
"lvl": 60,
|
||||
"damMobs": 7,
|
||||
"dex": 3,
|
||||
"fixID": false,
|
||||
|
@ -377,7 +377,7 @@
|
|||
"category": "tome",
|
||||
"drop": "never",
|
||||
"restrict": "Soulbound Item",
|
||||
"lvl": 80,
|
||||
"lvl": 60,
|
||||
"damMobs": 7,
|
||||
"int": 3,
|
||||
"fixID": false,
|
||||
|
@ -405,7 +405,7 @@
|
|||
"category": "tome",
|
||||
"drop": "never",
|
||||
"restrict": "Soulbound Item",
|
||||
"lvl": 80,
|
||||
"lvl": 60,
|
||||
"damMobs": 7,
|
||||
"def": 3,
|
||||
"fixID": false,
|
||||
|
@ -433,7 +433,7 @@
|
|||
"category": "tome",
|
||||
"drop": "never",
|
||||
"restrict": "Soulbound Item",
|
||||
"lvl": 80,
|
||||
"lvl": 60,
|
||||
"damMobs": 7,
|
||||
"agi": 3,
|
||||
"fixID": false,
|
||||
|
@ -461,7 +461,7 @@
|
|||
"category": "tome",
|
||||
"drop": "never",
|
||||
"restrict": "Soulbound Item",
|
||||
"lvl": 80,
|
||||
"lvl": 60,
|
||||
"damMobs": 7,
|
||||
"str": 1,
|
||||
"dex": 1,
|
||||
|
@ -804,6 +804,266 @@
|
|||
"fixID": false,
|
||||
"id": 54,
|
||||
"alias": "Rainbow"
|
||||
},
|
||||
{
|
||||
"name": "Ephemeral Tome of Weapon Mastery I",
|
||||
"tier": "Fabled",
|
||||
"type": "weaponTome",
|
||||
"category": "tome",
|
||||
"drop": "never",
|
||||
"restrict": "Soulbound Item",
|
||||
"lvl": 60,
|
||||
"damMobs": 7,
|
||||
"mr": 1,
|
||||
"fixID": false,
|
||||
"id": 55,
|
||||
"alias": "Mana Regen I"
|
||||
},
|
||||
{
|
||||
"name": "Ephemeral Tome of Weapon Mastery II",
|
||||
"tier": "Fabled",
|
||||
"type": "weaponTome",
|
||||
"category": "tome",
|
||||
"drop": "never",
|
||||
"restrict": "Soulbound Item",
|
||||
"lvl": 80,
|
||||
"damMobs": 8,
|
||||
"mr": 1,
|
||||
"fixID": false,
|
||||
"id": 56,
|
||||
"alias": "Mana Regen II"
|
||||
},
|
||||
{
|
||||
"name": "Ephemeral Tome of Weapon Mastery III",
|
||||
"tier": "Fabled",
|
||||
"type": "weaponTome",
|
||||
"category": "tome",
|
||||
"drop": "never",
|
||||
"restrict": "Soulbound Item",
|
||||
"lvl": 105,
|
||||
"damMobs": 13,
|
||||
"mr": 1,
|
||||
"fixID": false,
|
||||
"id": 57,
|
||||
"alias": "Mana Regen III"
|
||||
},
|
||||
{
|
||||
"name": "Harvester's Tome of Weapon Mastery I",
|
||||
"tier": "Fabled",
|
||||
"type": "weaponTome",
|
||||
"category": "tome",
|
||||
"drop": "never",
|
||||
"restrict": "Soulbound Item",
|
||||
"lvl": 60,
|
||||
"damMobs": 7,
|
||||
"ms": 1,
|
||||
"fixID": false,
|
||||
"id": 58,
|
||||
"alias": "Mana Steal I"
|
||||
},
|
||||
{
|
||||
"name": "Harvester's Tome of Weapon Mastery II",
|
||||
"tier": "Fabled",
|
||||
"type": "weaponTome",
|
||||
"category": "tome",
|
||||
"drop": "never",
|
||||
"restrict": "Soulbound Item",
|
||||
"lvl": 80,
|
||||
"damMobs": 8,
|
||||
"ms": 1,
|
||||
"fixID": false,
|
||||
"id": 59,
|
||||
"alias": "Mana Steal II"
|
||||
},
|
||||
{
|
||||
"name": "Harvester's Tome of Weapon Mastery III",
|
||||
"tier": "Fabled",
|
||||
"type": "weaponTome",
|
||||
"category": "tome",
|
||||
"drop": "never",
|
||||
"restrict": "Soulbound Item",
|
||||
"lvl": 105,
|
||||
"damMobs": 13,
|
||||
"ms": 1,
|
||||
"fixID": false,
|
||||
"id": 60,
|
||||
"alias": "Mana Steal III"
|
||||
},
|
||||
{
|
||||
"name": "Earthbound Tome of Weapon Mastery III",
|
||||
"tier": "Fabled",
|
||||
"type": "weaponTome",
|
||||
"category": "tome",
|
||||
"drop": "never",
|
||||
"restrict": "Soulbound Item",
|
||||
"lvl": 105,
|
||||
"damMobs": 13,
|
||||
"str": 3,
|
||||
"fixID": false,
|
||||
"id": 64,
|
||||
"alias": "Strength III"
|
||||
},
|
||||
{
|
||||
"name": "Nimble Tome of Weapon Mastery III",
|
||||
"tier": "Fabled",
|
||||
"type": "weaponTome",
|
||||
"category": "tome",
|
||||
"drop": "never",
|
||||
"restrict": "Soulbound Item",
|
||||
"lvl": 105,
|
||||
"damMobs": 13,
|
||||
"dex": 3,
|
||||
"fixID": false,
|
||||
"id": 65,
|
||||
"alias": "Dexterity III"
|
||||
},
|
||||
{
|
||||
"name": "Mystical Tome of Weapon Mastery III",
|
||||
"tier": "Fabled",
|
||||
"type": "weaponTome",
|
||||
"category": "tome",
|
||||
"drop": "never",
|
||||
"restrict": "Soulbound Item",
|
||||
"lvl": 105,
|
||||
"damMobs": 13,
|
||||
"int": 3,
|
||||
"fixID": false,
|
||||
"id": 66,
|
||||
"alias": "Intelligence III"
|
||||
},
|
||||
{
|
||||
"name": "Warding Tome of Weapon Mastery III",
|
||||
"tier": "Fabled",
|
||||
"type": "weaponTome",
|
||||
"category": "tome",
|
||||
"drop": "never",
|
||||
"restrict": "Soulbound Item",
|
||||
"lvl": 105,
|
||||
"damMobs": 13,
|
||||
"def": 3,
|
||||
"fixID": false,
|
||||
"id": 67,
|
||||
"alias": "Defense III"
|
||||
},
|
||||
{
|
||||
"name": "Athletic Tome of Weapon Mastery III",
|
||||
"tier": "Fabled",
|
||||
"type": "weaponTome",
|
||||
"category": "tome",
|
||||
"drop": "never",
|
||||
"restrict": "Soulbound Item",
|
||||
"lvl": 105,
|
||||
"damMobs": 13,
|
||||
"agi": 3,
|
||||
"fixID": false,
|
||||
"id": 68,
|
||||
"alias": "Agility III"
|
||||
},
|
||||
{
|
||||
"name": "Cosmic Tome of Weapon Mastery III",
|
||||
"tier": "Fabled",
|
||||
"type": "weaponTome",
|
||||
"category": "tome",
|
||||
"drop": "never",
|
||||
"restrict": "Soulbound Item",
|
||||
"lvl": 105,
|
||||
"damMobs": 13,
|
||||
"str": 1,
|
||||
"dex": 1,
|
||||
"int": 1,
|
||||
"def": 1,
|
||||
"agi": 1,
|
||||
"fixID": false,
|
||||
"id": 69,
|
||||
"alias": "Rainbow Skillpoint III"
|
||||
},
|
||||
{
|
||||
"name": "Seismic Tome of Weapon Mastery III",
|
||||
"tier": "Mythic",
|
||||
"type": "weaponTome",
|
||||
"category": "tome",
|
||||
"drop": "never",
|
||||
"restrict": "Soulbound Item",
|
||||
"lvl": 105,
|
||||
"damMobs": 16,
|
||||
"eDamPct": 8,
|
||||
"fixID": false,
|
||||
"id": 70,
|
||||
"alias": "Earth Damage III"
|
||||
},
|
||||
{
|
||||
"name": "Voltaic Tome of Weapon Mastery III",
|
||||
"tier": "Mythic",
|
||||
"type": "weaponTome",
|
||||
"category": "tome",
|
||||
"drop": "never",
|
||||
"restrict": "Soulbound Item",
|
||||
"lvl": 105,
|
||||
"damMobs": 16,
|
||||
"tDamPct": 8,
|
||||
"fixID": false,
|
||||
"id": 71,
|
||||
"alias": "Thunder Damage III"
|
||||
},
|
||||
{
|
||||
"name": "Abyssal Tome of Weapon Mastery III",
|
||||
"tier": "Mythic",
|
||||
"type": "weaponTome",
|
||||
"category": "tome",
|
||||
"drop": "never",
|
||||
"restrict": "Soulbound Item",
|
||||
"lvl": 105,
|
||||
"damMobs": 16,
|
||||
"wDamPct": 8,
|
||||
"fixID": false,
|
||||
"id": 72,
|
||||
"alias": "Water Damage III"
|
||||
},
|
||||
{
|
||||
"name": "Infernal Tome of Weapon Mastery III",
|
||||
"tier": "Mythic",
|
||||
"type": "weaponTome",
|
||||
"category": "tome",
|
||||
"drop": "never",
|
||||
"restrict": "Soulbound Item",
|
||||
"lvl": 105,
|
||||
"damMobs": 16,
|
||||
"fDamPct": 8,
|
||||
"fixID": false,
|
||||
"id": 73,
|
||||
"alias": "Fire Damage III"
|
||||
},
|
||||
{
|
||||
"name": "Cyclonic Tome of Weapon Mastery III",
|
||||
"tier": "Mythic",
|
||||
"type": "weaponTome",
|
||||
"category": "tome",
|
||||
"drop": "never",
|
||||
"restrict": "Soulbound Item",
|
||||
"lvl": 105,
|
||||
"damMobs": 16,
|
||||
"aDamPct": 8,
|
||||
"fixID": false,
|
||||
"id": 74,
|
||||
"alias": "Air Damage III"
|
||||
},
|
||||
{
|
||||
"name": "Astral Tome of Weapon Mastery III",
|
||||
"tier": "Mythic",
|
||||
"type": "weaponTome",
|
||||
"category": "tome",
|
||||
"drop": "never",
|
||||
"restrict": "Soulbound Item",
|
||||
"lvl": 105,
|
||||
"damMobs": 16,
|
||||
"eDamPct": 7,
|
||||
"tDamPct": 7,
|
||||
"wDamPct": 7,
|
||||
"fDamPct": 7,
|
||||
"aDamPct": 7,
|
||||
"fixID": false,
|
||||
"id": 75,
|
||||
"alias": "Rainbow Damage III"
|
||||
}
|
||||
]
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue