Updating to wynn 2.0.2.3 (except item database...)
* Fix enraged blow typo; allow "or" and "and" in adv search
...forgot to update json
* Lacerate is blocked by Echo, not Mirror Image
* Misc bugfix
Fix bug with skillpoints and negative set bonus
Add final multiplier for echo
* Clean up testing folder
and add script for quick plotting pairs of ids/item values
* Fix typo in better lightweaver
add to the correct dps
* Partial update to 2.0.2.3 (festival of heroes)
patch:
- ing changes (manual)
- two endgame items (the ones that I got customs for)
bugfix:
- Fix bug in reverse mapping that mapped item "type" to "accessoryType"
* Forgot to commit all the 2.0.2.3 data files...
* Fix epilogue displayName
* Fix minor incorrectness with fromIntV invocation
don't think this was a bug? but its not the correct number of arguments lol
* Move powder ingreds to ing load sequence
not used anywhere else
also, remove extra prints in crafter
* Refactor powder special display
fix quake/chain/courage not displaying some powder special information 💀
* Finally fix satsujin to work with powder specials
thanks to powder special display refactor
* Fix mask of the awakened giving outdated stats
e
* Add prologue and gleeman's tale
wynn api when
...fix epilgoue
---------
Co-authored-by: hppeng <hppeng>
This commit is contained in:
parent
4b9460ebc2
commit
d9e5d6da95
29 changed files with 27503 additions and 26243 deletions
52138
clean.json
52138
clean.json
File diff suppressed because it is too large
Load diff
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
1
data/2.0.2.3/atree.json
Normal file
1
data/2.0.2.3/atree.json
Normal file
File diff suppressed because one or more lines are too long
1
data/2.0.2.3/ingreds.json
Normal file
1
data/2.0.2.3/ingreds.json
Normal file
File diff suppressed because one or more lines are too long
1
data/2.0.2.3/items.json
Normal file
1
data/2.0.2.3/items.json
Normal file
File diff suppressed because one or more lines are too long
1069
data/2.0.2.3/tomes.json
Normal file
1069
data/2.0.2.3/tomes.json
Normal file
File diff suppressed because it is too large
Load diff
|
@ -15710,8 +15710,8 @@
|
|||
"maximum": 7
|
||||
},
|
||||
"lq": {
|
||||
"minimum": 3,
|
||||
"maximum": 4
|
||||
"minimum": 4,
|
||||
"maximum": 5
|
||||
}
|
||||
},
|
||||
"itemIDs": {
|
||||
|
@ -16169,7 +16169,7 @@
|
|||
"lvl": 4,
|
||||
"ids": {},
|
||||
"itemIDs": {
|
||||
"dura": -70,
|
||||
"dura": -30,
|
||||
"strReq": 0,
|
||||
"dexReq": 0,
|
||||
"intReq": 0,
|
||||
|
@ -18451,7 +18451,7 @@
|
|||
"posMods": {
|
||||
"left": 0,
|
||||
"right": 0,
|
||||
"above": 30,
|
||||
"above": 25,
|
||||
"under": 0,
|
||||
"touching": 0,
|
||||
"notTouching": 0
|
||||
|
@ -23923,7 +23923,7 @@
|
|||
"lvl": 100,
|
||||
"ids": {},
|
||||
"itemIDs": {
|
||||
"dura": -175,
|
||||
"dura": -160,
|
||||
"strReq": 0,
|
||||
"dexReq": 0,
|
||||
"intReq": 0,
|
||||
|
@ -23934,7 +23934,7 @@
|
|||
},
|
||||
"consumableIDs": {
|
||||
"charges": 0,
|
||||
"dura": -300
|
||||
"dura": -275
|
||||
},
|
||||
"posMods": {
|
||||
"left": 110,
|
||||
|
@ -24214,8 +24214,8 @@
|
|||
"right": 0,
|
||||
"above": 0,
|
||||
"under": 0,
|
||||
"touching": 12,
|
||||
"notTouching": 12
|
||||
"touching": 15,
|
||||
"notTouching": 15
|
||||
},
|
||||
"id": 569
|
||||
},
|
||||
|
@ -24722,7 +24722,7 @@
|
|||
"above": 0,
|
||||
"under": 0,
|
||||
"touching": -100,
|
||||
"notTouching": 75
|
||||
"notTouching": 55
|
||||
},
|
||||
"id": 582
|
||||
},
|
||||
|
@ -24913,8 +24913,8 @@
|
|||
"posMods": {
|
||||
"left": -100,
|
||||
"right": -100,
|
||||
"above": 75,
|
||||
"under": 75,
|
||||
"above": 60,
|
||||
"under": 60,
|
||||
"touching": 0,
|
||||
"notTouching": 0
|
||||
},
|
||||
|
@ -24942,10 +24942,10 @@
|
|||
"dura": -300
|
||||
},
|
||||
"posMods": {
|
||||
"left": -75,
|
||||
"right": -75,
|
||||
"above": -50,
|
||||
"under": -50,
|
||||
"left": -50,
|
||||
"right": -50,
|
||||
"above": -75,
|
||||
"under": -75,
|
||||
"touching": 120,
|
||||
"notTouching": 0
|
||||
},
|
||||
|
@ -25983,7 +25983,7 @@
|
|||
"above": 0,
|
||||
"under": 0,
|
||||
"touching": 0,
|
||||
"notTouching": 65
|
||||
"notTouching": 55
|
||||
},
|
||||
"id": 610
|
||||
},
|
||||
|
@ -26140,8 +26140,8 @@
|
|||
"right": 0,
|
||||
"above": 0,
|
||||
"under": 0,
|
||||
"touching": 33,
|
||||
"notTouching": 33
|
||||
"touching": 25,
|
||||
"notTouching": 25
|
||||
},
|
||||
"id": 614
|
||||
},
|
||||
|
@ -26688,8 +26688,8 @@
|
|||
"right": -122,
|
||||
"above": 0,
|
||||
"under": 0,
|
||||
"touching": -29,
|
||||
"notTouching": -29
|
||||
"touching": -15,
|
||||
"notTouching": -15
|
||||
},
|
||||
"id": 627
|
||||
},
|
||||
|
@ -26846,7 +26846,7 @@
|
|||
"posMods": {
|
||||
"left": 0,
|
||||
"right": 0,
|
||||
"above": -180,
|
||||
"above": -140,
|
||||
"under": 0,
|
||||
"touching": 0,
|
||||
"notTouching": 0
|
||||
|
@ -27433,12 +27433,12 @@
|
|||
"dura": 0
|
||||
},
|
||||
"posMods": {
|
||||
"left": -45,
|
||||
"right": -45,
|
||||
"left": -30,
|
||||
"right": -30,
|
||||
"above": 0,
|
||||
"under": 0,
|
||||
"touching": 45,
|
||||
"notTouching": 45
|
||||
"touching": 30,
|
||||
"notTouching": 30
|
||||
},
|
||||
"id": 645
|
||||
},
|
||||
|
@ -28657,8 +28657,8 @@
|
|||
"right": 0,
|
||||
"above": 0,
|
||||
"under": 0,
|
||||
"touching": 20,
|
||||
"notTouching": 20
|
||||
"touching": 15,
|
||||
"notTouching": 15
|
||||
},
|
||||
"id": 691
|
||||
},
|
||||
|
@ -28715,7 +28715,7 @@
|
|||
"lvl": 80,
|
||||
"ids": {},
|
||||
"itemIDs": {
|
||||
"dura": -150,
|
||||
"dura": -140,
|
||||
"strReq": -25,
|
||||
"dexReq": -25,
|
||||
"intReq": -25,
|
||||
|
@ -28802,8 +28802,8 @@
|
|||
"right": 0,
|
||||
"above": 0,
|
||||
"under": 0,
|
||||
"touching": 40,
|
||||
"notTouching": 80
|
||||
"touching": 25,
|
||||
"notTouching": 45
|
||||
},
|
||||
"id": 674
|
||||
},
|
||||
|
|
File diff suppressed because one or more lines are too long
|
@ -94,10 +94,12 @@ let str_item_fields = [ "name", "displayName", "lore", "color", "tier", "set", "
|
|||
|
||||
//File reading for ID translations for JSON purposes
|
||||
let reversetranslations = new Map();
|
||||
let translations = new Map([["name", "name"],["displayName", "displayName"],["tier", "tier"],["set", "set"],["sockets", "slots"],["type", "type"],["armorColor", "color"],["addedLore", "lore"],["dropType", "drop"],["quest", "quest"],["restrictions", "restrict"],["damage", "nDam"],["fireDamage", "fDam"],["waterDamage", "wDam"],["airDamage", "aDam"],["thunderDamage", "tDam"],["earthDamage", "eDam"],["attackSpeed", "atkSpd"],["health", "hp"],["fireDefense", "fDef"],["waterDefense", "wDef"],["airDefense", "aDef"],["thunderDefense", "tDef"],["earthDefense", "eDef"],["level", "lvl"],["classRequirement", "classReq"],["strength", "strReq"],["dexterity", "dexReq"],["intelligence", "intReq"],["agility", "agiReq"],["defense", "defReq"],["healthRegen", "hprPct"],["manaRegen", "mr"],["spellDamageBonus", "sdPct"],["spellElementalDamageBonus", "rSdPct"],["spellNeutralDamageBonus", "nSdPct"],["spellFireDamageBonus", "fSdPct"],["spellWaterDamageBonus", "wSdPct"],["spellAirDamageBonus", "aSdPct"],["spellThunderDamageBonus", "tSdPct"],["spellEarthDamageBonus", "eSdPct"],["mainAttackDamageBonus", "mdPct"],["mainAttackElementalDamageBonus", "rMdPct"],["mainAttackNeutralDamageBonus", "nMdPct"],["mainAttackFireDamageBonus", "fMdPct"],["mainAttackWaterDamageBonus", "wMdPct"],["mainAttackAirDamageBonus", "aMdPct"],["mainAttackThunderDamageBonus", "tMdPct"],["mainAttackEarthDamageBonus", "eMdPct"],["lifeSteal", "ls"],["manaSteal", "ms"],["xpBonus", "xpb"],["lootBonus", "lb"],["reflection", "ref"],["strengthPoints", "str"],["dexterityPoints", "dex"],["intelligencePoints", "int"],["agilityPoints", "agi"],["defensePoints", "def"],["thorns", "thorns"],["exploding", "expd"],["speed", "spd"],["attackSpeedBonus", "atkTier"],["poison", "poison"],["healthBonus", "hpBonus"],["soulPoints", "spRegen"],["emeraldStealing", "eSteal"],["healthRegenRaw", "hprRaw"],["spellDamageBonusRaw", "sdRaw"],["spellElementalDamageBonusRaw", "rSdRaw"],["spellNeutralDamageBonusRaw", "nSdRaw"],["spellFireDamageBonusRaw", "fSdRaw"],["spellWaterDamageBonusRaw", "wSdRaw"],["spellAirDamageBonusRaw", "aSdRaw"],["spellThunderDamageBonusRaw", "tSdRaw"],["spellEarthDamageBonusRaw", "eSdRaw"],["mainAttackDamageBonusRaw", "mdRaw"],["mainAttackElementalDamageBonusRaw", "rMdRaw"],["mainAttackNeutralDamageBonusRaw", "nMdRaw"],["mainAttackFireDamageBonusRaw", "fMdRaw"],["mainAttackWaterDamageBonusRaw", "wMdRaw"],["mainAttackAirDamageBonusRaw", "aMdRaw"],["mainAttackThunderDamageBonusRaw", "tMdRaw"],["mainAttackEarthDamageBonusRaw", "eMdRaw"],["fireDamageBonus", "fDamPct"],["waterDamageBonus", "wDamPct"],["airDamageBonus", "aDamPct"],["thunderDamageBonus", "tDamPct"],["earthDamageBonus", "eDamPct"],["bonusFireDefense", "fDefPct"],["bonusWaterDefense", "wDefPct"],["bonusAirDefense", "aDefPct"],["bonusThunderDefense", "tDefPct"],["bonusEarthDefense", "eDefPct"],["accessoryType", "type"],["identified", "fixID"],["skin", "skin"],["category", "category"],["spellCostPct1", "spPct1"],["spellCostRaw1", "spRaw1"],["spellCostPct2", "spPct2"],["spellCostRaw2", "spRaw2"],["spellCostPct3", "spPct3"],["spellCostRaw3", "spRaw3"],["spellCostPct4", "spPct4"],["spellCostRaw4", "spRaw4"],["sprint", "sprint"],["sprintRegen", "sprintReg"],["jumpHeight", "jh"],["lootQuality", "lq"],["gatherXpBonus", "gXp"],["gatherSpeed", "gSpd"]]);
|
||||
let _translations_list = [["name", "name"],["displayName", "displayName"],["tier", "tier"],["set", "set"],["sockets", "slots"],["type", "type"],["armorColor", "color"],["addedLore", "lore"],["dropType", "drop"],["quest", "quest"],["restrictions", "restrict"],["damage", "nDam"],["fireDamage", "fDam"],["waterDamage", "wDam"],["airDamage", "aDam"],["thunderDamage", "tDam"],["earthDamage", "eDam"],["attackSpeed", "atkSpd"],["health", "hp"],["fireDefense", "fDef"],["waterDefense", "wDef"],["airDefense", "aDef"],["thunderDefense", "tDef"],["earthDefense", "eDef"],["level", "lvl"],["classRequirement", "classReq"],["strength", "strReq"],["dexterity", "dexReq"],["intelligence", "intReq"],["agility", "agiReq"],["defense", "defReq"],["healthRegen", "hprPct"],["manaRegen", "mr"],["spellDamageBonus", "sdPct"],["spellElementalDamageBonus", "rSdPct"],["spellNeutralDamageBonus", "nSdPct"],["spellFireDamageBonus", "fSdPct"],["spellWaterDamageBonus", "wSdPct"],["spellAirDamageBonus", "aSdPct"],["spellThunderDamageBonus", "tSdPct"],["spellEarthDamageBonus", "eSdPct"],["mainAttackDamageBonus", "mdPct"],["mainAttackElementalDamageBonus", "rMdPct"],["mainAttackNeutralDamageBonus", "nMdPct"],["mainAttackFireDamageBonus", "fMdPct"],["mainAttackWaterDamageBonus", "wMdPct"],["mainAttackAirDamageBonus", "aMdPct"],["mainAttackThunderDamageBonus", "tMdPct"],["mainAttackEarthDamageBonus", "eMdPct"],["lifeSteal", "ls"],["manaSteal", "ms"],["xpBonus", "xpb"],["lootBonus", "lb"],["reflection", "ref"],["strengthPoints", "str"],["dexterityPoints", "dex"],["intelligencePoints", "int"],["agilityPoints", "agi"],["defensePoints", "def"],["thorns", "thorns"],["exploding", "expd"],["speed", "spd"],["attackSpeedBonus", "atkTier"],["poison", "poison"],["healthBonus", "hpBonus"],["soulPoints", "spRegen"],["emeraldStealing", "eSteal"],["healthRegenRaw", "hprRaw"],["spellDamageBonusRaw", "sdRaw"],["spellElementalDamageBonusRaw", "rSdRaw"],["spellNeutralDamageBonusRaw", "nSdRaw"],["spellFireDamageBonusRaw", "fSdRaw"],["spellWaterDamageBonusRaw", "wSdRaw"],["spellAirDamageBonusRaw", "aSdRaw"],["spellThunderDamageBonusRaw", "tSdRaw"],["spellEarthDamageBonusRaw", "eSdRaw"],["mainAttackDamageBonusRaw", "mdRaw"],["mainAttackElementalDamageBonusRaw", "rMdRaw"],["mainAttackNeutralDamageBonusRaw", "nMdRaw"],["mainAttackFireDamageBonusRaw", "fMdRaw"],["mainAttackWaterDamageBonusRaw", "wMdRaw"],["mainAttackAirDamageBonusRaw", "aMdRaw"],["mainAttackThunderDamageBonusRaw", "tMdRaw"],["mainAttackEarthDamageBonusRaw", "eMdRaw"],["fireDamageBonus", "fDamPct"],["waterDamageBonus", "wDamPct"],["airDamageBonus", "aDamPct"],["thunderDamageBonus", "tDamPct"],["earthDamageBonus", "eDamPct"],["bonusFireDefense", "fDefPct"],["bonusWaterDefense", "wDefPct"],["bonusAirDefense", "aDefPct"],["bonusThunderDefense", "tDefPct"],["bonusEarthDefense", "eDefPct"],["accessoryType", "type"],["identified", "fixID"],["skin", "skin"],["category", "category"],["spellCostPct1", "spPct1"],["spellCostRaw1", "spRaw1"],["spellCostPct2", "spPct2"],["spellCostRaw2", "spRaw2"],["spellCostPct3", "spPct3"],["spellCostRaw3", "spRaw3"],["spellCostPct4", "spPct4"],["spellCostRaw4", "spRaw4"],["sprint", "sprint"],["sprintRegen", "sprintReg"],["jumpHeight", "jh"],["lootQuality", "lq"],["gatherXpBonus", "gXp"],["gatherSpeed", "gSpd"]];
|
||||
let translations = new Map(_translations_list);
|
||||
|
||||
//does not include damMobs (wep tomes) and defMobs (armor tomes)
|
||||
for (const [k, v] of translations) {
|
||||
for (const [k, v] of _translations_list) {
|
||||
if (reversetranslations.has(v)) { continue; }
|
||||
reversetranslations.set(v, k);
|
||||
}
|
||||
|
||||
|
|
|
@ -3665,7 +3665,7 @@ const atrees = {
|
|||
},
|
||||
{
|
||||
"display_name": "Enraged Blow",
|
||||
"desc": "While Corrupted, every 1% of Health you lose will increase your damage by +2% (Max 80%)",
|
||||
"desc": "While Corrupted, every 1% of Health you lose will increase your damage by +1.5% (Max 80%)",
|
||||
"archetype": "Fallen",
|
||||
"archetype_req": 0,
|
||||
"base_abil": "Bak'al's Grasp",
|
||||
|
@ -6964,7 +6964,7 @@ const atrees = {
|
|||
"effects": [
|
||||
{
|
||||
"type": "add_spell_prop",
|
||||
"target_part": "Orb Damage",
|
||||
"target_part": "Orb DPS",
|
||||
"base_spell": 5,
|
||||
"hits": {
|
||||
"Single Orb": 1
|
||||
|
@ -7906,7 +7906,6 @@ const atrees = {
|
|||
"desc": "After leaving Vanish, summon 3 Clones that will follow you and protect you (15s Cooldown). When hit, gain a chance to take 80% less damage and lose 1 Clone.",
|
||||
"archetype": "Trickster",
|
||||
"archetype_req": 2,
|
||||
"base_abil": "Dash",
|
||||
"parents": [
|
||||
"Sticky Bomb"
|
||||
],
|
||||
|
@ -7943,7 +7942,7 @@ const atrees = {
|
|||
],
|
||||
"dependencies": [],
|
||||
"blockers": [
|
||||
"Mirror Image"
|
||||
"Echo"
|
||||
],
|
||||
"cost": 2,
|
||||
"display": {
|
||||
|
@ -8545,7 +8544,7 @@ const atrees = {
|
|||
"desc": "Your Clones will mimic your spells and abilities. While they are active, deal -60% damage.",
|
||||
"archetype": "Trickster",
|
||||
"archetype_req": 6,
|
||||
"base_abil": "Dash",
|
||||
"base_abil": "Mirror Image",
|
||||
"parents": [
|
||||
"Sandbagging",
|
||||
"Shurikens"
|
||||
|
@ -8581,6 +8580,22 @@ const atrees = {
|
|||
"behavior": "modify",
|
||||
"target_part": "Slash Damage",
|
||||
"multipliers": [ 690, 0, 0, 110, 0, 0 ]
|
||||
},
|
||||
{
|
||||
"type": "stat_scaling",
|
||||
"slider": true,
|
||||
"slider_name": "Spell Copies",
|
||||
"slider_step": 1,
|
||||
"slider_max": 3,
|
||||
"output": [
|
||||
{
|
||||
"type": "stat",
|
||||
"name": "damMult.EchoCast"
|
||||
}
|
||||
],
|
||||
"scaling": [
|
||||
100
|
||||
]
|
||||
}
|
||||
]
|
||||
},
|
||||
|
@ -9123,7 +9138,7 @@ const atrees = {
|
|||
"desc": "Improve your damage while your Clones are active by +15%",
|
||||
"archetype": "Trickster",
|
||||
"archetype_req": 7,
|
||||
"base_abil": "Dash",
|
||||
"base_abil": "Mirror Image",
|
||||
"parents": [
|
||||
"Cheaper Smoke Bomb 2",
|
||||
"Blade Fury"
|
||||
|
@ -9173,7 +9188,7 @@ const atrees = {
|
|||
},
|
||||
{
|
||||
"display_name": "Satsujin",
|
||||
"desc": "If an enemy has 3 Marks and 70% of their health or more, your next Multihit or Main Attack will deal triple damage. (20s Cooldown, per enemy)",
|
||||
"desc": "If an enemy has 3 Marks, your next Multihit or Damaging Powder Special will deal double damage. (20s Cooldown, per enemy)",
|
||||
"archetype": "Shadestepper",
|
||||
"archetype_req": 13,
|
||||
"parents": [
|
||||
|
@ -9210,7 +9225,7 @@ const atrees = {
|
|||
},
|
||||
{
|
||||
"type": "stat",
|
||||
"name": "damMult.Satsujin:0.Melee",
|
||||
"name": "damMult.Satsujin:0.Powder Special",
|
||||
"value": 100
|
||||
}
|
||||
]
|
||||
|
@ -9222,7 +9237,7 @@ const atrees = {
|
|||
"desc": "Summon +3 additional Clones. (+15s Cooldown)",
|
||||
"archetype": "Trickster",
|
||||
"archetype_req": 8,
|
||||
"base_abil": "Dash",
|
||||
"base_abil": "Mirror Image",
|
||||
"parents": [
|
||||
"Cheaper Smoke Bomb 2"
|
||||
],
|
||||
|
@ -9237,7 +9252,14 @@ const atrees = {
|
|||
"icon": "node_2"
|
||||
},
|
||||
"properties": {},
|
||||
"effects": []
|
||||
"effects": [
|
||||
{
|
||||
"type": "stat_scaling",
|
||||
"slider": true,
|
||||
"slider_name": "Spell Copies",
|
||||
"slider_max": 3
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"display_name": "Diversion",
|
||||
|
@ -11564,17 +11586,17 @@ const atrees = {
|
|||
{
|
||||
"type": "stat",
|
||||
"name": "damMult.Mask",
|
||||
"value": 30
|
||||
"value": 35
|
||||
},
|
||||
{
|
||||
"type": "stat",
|
||||
"name": "defMult.Mask",
|
||||
"value": 30
|
||||
"value": 35
|
||||
},
|
||||
{
|
||||
"type": "stat",
|
||||
"name": "spd",
|
||||
"value": 25
|
||||
"value": 80
|
||||
},
|
||||
{
|
||||
"type": "stat",
|
||||
|
|
File diff suppressed because one or more lines are too long
|
@ -30,7 +30,8 @@ let atree_data = null;
|
|||
const wynn_version_names = [
|
||||
'2.0.1.1',
|
||||
'2.0.1.2',
|
||||
'2.0.2.1'
|
||||
'2.0.2.1',
|
||||
'2.0.2.3'
|
||||
];
|
||||
const WYNN_VERSION_LATEST = wynn_version_names.length - 1;
|
||||
// Default to the newest version.
|
||||
|
|
|
@ -117,7 +117,7 @@ class PowderSpecialDisplayNode extends ComputeNode {
|
|||
const powder_specials = input_map.get('powder-specials');
|
||||
const stats = input_map.get('stats');
|
||||
const weapon = input_map.get('build').weapon;
|
||||
displayPowderSpecials(document.getElementById("powder-special-stats"), powder_specials, stats, weapon.statMap, true);
|
||||
displayPowderSpecials(document.getElementById("powder-special-stats"), powder_specials, stats, weapon.statMap);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -136,8 +136,6 @@ function calculateCraft() {
|
|||
}
|
||||
let ingreds = [];
|
||||
for (i = 1; i < 7; i++) {
|
||||
console.log("ing-choice-"+i);
|
||||
// console.log(getValue("ing-choice-"+i));
|
||||
getValue("ing-choice-" + i) === "" ? ingreds.push(expandIngredient(ingMap.get("No Ingredient"))) : ingreds.push(expandIngredient(ingMap.get(getValue("ing-choice-" + i))));
|
||||
}
|
||||
let atkSpd = "NORMAL"; //default attack speed will be normal.
|
||||
|
|
|
@ -246,7 +246,6 @@ class Custom {
|
|||
}
|
||||
}
|
||||
let type = this.statMap.get("type").toLowerCase();
|
||||
console.log(type);
|
||||
if (weaponTypes.includes(type)) {
|
||||
for (const n of ["nDam", "eDam", "tDam", "wDam", "fDam", "aDam"]) {
|
||||
if (!(this.statMap.has(n) && this.statMap.get(n))) {
|
||||
|
|
|
@ -340,17 +340,3 @@ const default_spells = {
|
|||
]
|
||||
}]
|
||||
};
|
||||
|
||||
const spell_table = {
|
||||
"powder": [ //This is how instant-damage powder specials are implemented.
|
||||
{ title: "Quake", cost: 0, parts:[
|
||||
{ subtitle: "Total Damage", type: "damage", multiplier: [155, 220, 285, 350, 415], conversion: [0,100,0,0,0,0], summary: true},
|
||||
] },
|
||||
{ title: "Chain Lightning", cost: 0, parts: [
|
||||
{ subtitle: "Total Damage", type: "damage", multiplier: [200, 225, 250, 275, 300], conversion: [0,0,100,0,0,0], summary: true},
|
||||
]},
|
||||
{ title: "Courage", cost: 0, parts: [
|
||||
{ subtitle: "Total Damage", type: "damage", multiplier: [75, 87.5, 100, 112.5, 125], conversion: [0,0,0,0,100,0], summary: true},
|
||||
]}, //[75, 87.5, 100, 112.5, 125]
|
||||
]
|
||||
};
|
||||
|
|
103
js/display.js
103
js/display.js
|
@ -1231,7 +1231,7 @@ function displayDefenseStats(parent_elem, statMap, insertSummary){
|
|||
}
|
||||
}
|
||||
|
||||
function displayPowderSpecials(parent_elem, powderSpecials, stats, weapon, overall=false) {
|
||||
function displayPowderSpecials(parent_elem, powderSpecials, stats, weapon) {
|
||||
parent_elem.textContent = "";
|
||||
if (powderSpecials.length === 0) {
|
||||
parent_elem.style = "display: none";
|
||||
|
@ -1252,45 +1252,25 @@ function displayPowderSpecials(parent_elem, powderSpecials, stats, weapon, overa
|
|||
//each entry of powderSpecials is [ps, power]
|
||||
for (special of specials) {
|
||||
//iterate through the special and display its effects.
|
||||
let powder_special = make_elem("p", ["pt-3"]);
|
||||
let powder_special_elem = make_elem("p", ["pt-3"]);
|
||||
let specialSuffixes = new Map([ ["Duration", " sec"], ["Radius", " blocks"], ["Chains", ""], ["Damage", "%"], ["Damage Boost", "%"], ["Knockback", " blocks"] ]);
|
||||
let specialTitle = make_elem("p");
|
||||
let specialEffects = make_elem("p");
|
||||
specialTitle.classList.add(damageClasses[powderSpecialStats.indexOf(special[0]) + 1]);
|
||||
let effects = special[0]["weaponSpecialEffects"];
|
||||
// TODO janky and depends on the order of powder specials being ETWFA. This should be encoded in the powder special object.
|
||||
let element_num = powderSpecialStats.indexOf(special[0]) + 1;
|
||||
specialTitle.classList.add(damageClasses[element_num]);
|
||||
let powder_special = special[0];
|
||||
let power = special[1];
|
||||
specialTitle.textContent = special[0]["weaponSpecialName"] + " " + Math.floor((power-1)*0.5 + 4) + (power % 2 == 0 ? ".5" : "");
|
||||
specialTitle.textContent = powder_special.weaponSpecialName + " " + Math.floor((power-1)*0.5 + 4) + (power % 2 == 0 ? ".5" : "");
|
||||
|
||||
if (!overall || powderSpecialStats.indexOf(special[0]) == 2 || powderSpecialStats.indexOf(special[0]) == 3 || powderSpecialStats.indexOf(special[0]) == 4) {
|
||||
for (const [key,value] of effects) {
|
||||
let effect = document.createElement("p");
|
||||
effect.textContent += key + ": " + value[power-1] + specialSuffixes.get(key);
|
||||
for (const [key,value] of powder_special.weaponSpecialEffects) {
|
||||
if(key === "Damage"){
|
||||
effect.textContent += elementIcons[powderSpecialStats.indexOf(special[0])];
|
||||
}
|
||||
if(special[0]["weaponSpecialName"] === "Wind Prison" && key === "Damage Boost") {
|
||||
effect.textContent += " (only 1st hit)";
|
||||
}
|
||||
specialEffects.appendChild(effect);
|
||||
}
|
||||
}
|
||||
powder_special.appendChild(specialTitle);
|
||||
powder_special.appendChild(specialEffects);
|
||||
|
||||
//if this special is an instant-damage special (Quake, Chain Lightning, Courage Burst), display the damage.
|
||||
let specialDamage = document.createElement("p");
|
||||
// specialDamage.classList.add("item-margin");
|
||||
let spells = spell_table["powder"];
|
||||
if (powderSpecialStats.indexOf(special[0]) == 0 || powderSpecialStats.indexOf(special[0]) == 1 || powderSpecialStats.indexOf(special[0]) == 3) { //Quake, Chain Lightning, or Courage
|
||||
let spell = (powderSpecialStats.indexOf(special[0]) == 3 ? spells[2] : spells[powderSpecialStats.indexOf(special[0])]);
|
||||
let part = spell["parts"][0];
|
||||
|
||||
let tmp_conv = [];
|
||||
for (let i in part.conversion) {
|
||||
tmp_conv.push(part.conversion[i] * part.multiplier[power-1] / 100);
|
||||
}
|
||||
console.log(tmp_conv);
|
||||
let _results = calculateSpellDamage(stats, weapon, tmp_conv, false, true);
|
||||
let conversions = [0, 0, 0, 0, 0, 0];
|
||||
conversions[element_num] = powder_special.weaponSpecialEffects.get("Damage")[power-1];
|
||||
let _results = calculateSpellDamage(stats, weapon, conversions, false, true, "0.Powder Special");
|
||||
|
||||
let critChance = skillPointsToPercentage(skillpoints[1]);
|
||||
let save_damages = [];
|
||||
|
@ -1319,62 +1299,19 @@ function displayPowderSpecials(parent_elem, powderSpecials, stats, weapon, overa
|
|||
averageWrap.appendChild(averageLabelDmg);
|
||||
specialDamage.appendChild(averageWrap);
|
||||
|
||||
if (!overall) {
|
||||
let nonCritLabel = document.createElement("p");
|
||||
nonCritLabel.textContent = "Non-Crit Average: "+nonCritAverage.toFixed(2);
|
||||
nonCritLabel.classList.add("damageSubtitle");
|
||||
nonCritLabel.classList.add("item-margin");
|
||||
specialDamage.append(nonCritLabel);
|
||||
|
||||
for (let i = 0; i < 6; i++){
|
||||
if (results[i][1] > 0){
|
||||
let p = document.createElement("p");
|
||||
p.classList.add("damagep");
|
||||
p.classList.add(damageClasses[i]);
|
||||
p.textContent = results[i][0]+"-"+results[i][1];
|
||||
specialDamage.append(p);
|
||||
specialEffects.append(specialDamage);
|
||||
}
|
||||
else {
|
||||
let effect = document.createElement("p");
|
||||
effect.textContent += key + ": " + value[power-1] + specialSuffixes.get(key);
|
||||
specialEffects.appendChild(effect);
|
||||
}
|
||||
}
|
||||
let normalDamage = document.createElement("p");
|
||||
normalDamage.textContent = "Total: " + totalDamNormal[0].toFixed(2) + "-" + totalDamNormal[1].toFixed(2);
|
||||
normalDamage.classList.add("itemp");
|
||||
specialDamage.append(normalDamage);
|
||||
|
||||
let nonCritChanceLabel = document.createElement("p");
|
||||
nonCritChanceLabel.textContent = "Non-Crit Chance: " + ((1-critChance)*100).toFixed(2) + "%";
|
||||
specialDamage.append(nonCritChanceLabel);
|
||||
powder_special_elem.appendChild(specialTitle);
|
||||
powder_special_elem.appendChild(specialEffects);
|
||||
|
||||
let critLabel = document.createElement("p");
|
||||
critLabel.textContent = "Crit Average: "+critAverage.toFixed(2);
|
||||
critLabel.classList.add("damageSubtitle");
|
||||
critLabel.classList.add("item-margin");
|
||||
|
||||
specialDamage.append(critLabel);
|
||||
for (let i = 0; i < 6; i++){
|
||||
if (results[i][1] > 0){
|
||||
let p = document.createElement("p");
|
||||
p.classList.add("damagep");
|
||||
p.classList.add(damageClasses[i]);
|
||||
p.textContent = results[i][2]+"-"+results[i][3];
|
||||
specialDamage.append(p);
|
||||
}
|
||||
}
|
||||
let critDamage = document.createElement("p");
|
||||
critDamage.textContent = "Total: " + totalDamCrit[0].toFixed(2) + "-" + totalDamCrit[1].toFixed(2);
|
||||
critDamage.classList.add("itemp");
|
||||
specialDamage.append(critDamage);
|
||||
|
||||
let critChanceLabel = document.createElement("p");
|
||||
critChanceLabel.textContent = "Crit Chance: " + (critChance*100).toFixed(2) + "%";
|
||||
specialDamage.append(critChanceLabel);
|
||||
|
||||
save_damages.push(averageDamage);
|
||||
}
|
||||
|
||||
powder_special.append(specialDamage);
|
||||
}
|
||||
|
||||
parent_elem.appendChild(powder_special);
|
||||
parent_elem.appendChild(powder_special_elem);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -50,6 +50,14 @@ const ExprParser = (function() {
|
|||
case '=':
|
||||
pushSymbol(exprStr[col]);
|
||||
continue;
|
||||
case 'or':
|
||||
tokens.push({ type: '|' });
|
||||
col += 2;
|
||||
continue;
|
||||
case 'and':
|
||||
tokens.push({ type: '&' });
|
||||
col += 2;
|
||||
continue;
|
||||
case '>':
|
||||
pushSymbol(exprStr[col + 1] === '=' ? '>=' : '>');
|
||||
continue;
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
const DB_VERSION = 122;
|
||||
const DB_VERSION = 126;
|
||||
// @See https://github.com/mdn/learning-area/blob/master/javascript/apis/client-side-storage/indexeddb/video-store/index.jsA
|
||||
|
||||
let db;
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
const ING_DB_VERSION = 20;
|
||||
const ING_DB_VERSION = 21;
|
||||
|
||||
// @See https://github.com/mdn/learning-area/blob/master/javascript/apis/client-side-storage/indexeddb/video-store/index.js
|
||||
|
||||
|
@ -201,39 +201,29 @@ function init_ing_maps() {
|
|||
ingList.push(ing.displayName);
|
||||
ingIDMap.set(ing.id, ing.displayName);
|
||||
let numerals = new Map([[1, "I"], [2, "II"], [3, "III"], [4, "IV"], [5, "V"], [6, "VI"]]);
|
||||
|
||||
// pairs of (dura, req)
|
||||
let powder_ing_info = [
|
||||
[-35,0],[-52.5,0],[-70,10],[-91,20],[-112,28],[-133,36]
|
||||
];
|
||||
for (let i = 0; i < 5; i ++) {
|
||||
for (const powderIng of powderIngreds) {
|
||||
for (let powder_tier = 0; powder_tier < 6; ++powder_tier) {
|
||||
powder_info = powder_ing_info[powder_tier];
|
||||
let ing = {
|
||||
name: "" + damageClasses[i+1] + " Powder " + numerals.get(powderIngreds.indexOf(powderIng) + 1),
|
||||
name: "" + damageClasses[i+1] + " Powder " + numerals.get(powder_tier + 1),
|
||||
tier: 0,
|
||||
lvl: 0,
|
||||
skills: ["ARMOURING", "TAILORING", "WEAPONSMITHING", "WOODWORKING", "JEWELING"],
|
||||
ids: {},
|
||||
isPowder: true,
|
||||
pid: 6*i + powderIngreds.indexOf(powderIng),
|
||||
itemIDs: {"dura": powderIng["durability"], "strReq": 0, "dexReq": 0,"intReq": 0,"defReq": 0,"agiReq": 0},
|
||||
pid: 6*i + powder_tier,
|
||||
itemIDs: {"dura": powder_info[0], "strReq": 0, "dexReq": 0,"intReq": 0,"defReq": 0,"agiReq": 0},
|
||||
consumableIDs: {"dura": 0, "charges": 0},
|
||||
posMods: {"left": 0, "right": 0, "above": 0, "under": 0, "touching": 0, "notTouching": 0}
|
||||
};
|
||||
ing.id = 4001 + ing.pid;
|
||||
ing.displayName = ing.name;
|
||||
switch(i) {
|
||||
case 0:
|
||||
ing.itemIDs["strReq"] = powderIng["skpReq"];
|
||||
break;
|
||||
case 1:
|
||||
ing.itemIDs["dexReq"] = powderIng["skpReq"];
|
||||
break;
|
||||
case 2:
|
||||
ing.itemIDs["intReq"] = powderIng["skpReq"];
|
||||
break;
|
||||
case 3:
|
||||
ing.itemIDs["defReq"] = powderIng["skpReq"];
|
||||
break;
|
||||
case 4:
|
||||
ing.itemIDs["agiReq"] = powderIng["skpReq"];
|
||||
break;
|
||||
}
|
||||
ing.itemIDs[skp_order[i] + "Req"] = powder_info[1];
|
||||
ingMap.set(ing.displayName, ing);
|
||||
ingList.push(ing.displayName);
|
||||
ingIDMap.set(ing.id, ing.displayName);
|
||||
|
|
|
@ -31,17 +31,6 @@ let powderStats = [
|
|||
_p(2,6,11,3,1), _p(3,10,14,6,2), _p(4,11,17,10,3), _p(5,11,22,16,5), _p(7,12,28,24,9), _p(8,14,35,34,13)
|
||||
];
|
||||
|
||||
class PowderIngredient {
|
||||
constructor(durability, skpReq) {
|
||||
this.durability = durability;
|
||||
this.skpReq = skpReq;
|
||||
}
|
||||
}
|
||||
function _pi(a,b) { return new PowderIngredient(a,b)}
|
||||
|
||||
let powderIngreds = [
|
||||
_pi(-35,0),_pi(-52.5,0),_pi(-70,10),_pi(-91,20),_pi(-112,28),_pi(-133,36)
|
||||
];
|
||||
//Ordering: [weapon special name, weapon special effects, armor special name, armor special effects]
|
||||
class PowderSpecial{
|
||||
constructor(wSpName, wSpEff, aSpName, aSpEff, cap){
|
||||
|
|
|
@ -240,15 +240,31 @@ function construct_scc_graph(items_to_consider) {
|
|||
parents: [],
|
||||
};
|
||||
for (const item of items_to_consider) {
|
||||
nodes.push({item: item, children: [terminal_node], parents: [root_node]});
|
||||
const set_neg = [false, false, false, false, false];
|
||||
const set_pos = [false, false, false, false, false];
|
||||
const set_name = item.set;
|
||||
if (set_name) {
|
||||
const bonuses = sets.get(set_name).bonuses;
|
||||
for (const bonus of bonuses) {
|
||||
for (const i in skp_order) {
|
||||
if (bonus[skp_order[i]] > 0) { set_pos[i] = true; }
|
||||
if (bonus[skp_order[i]] < 0) { set_neg[i] = true; }
|
||||
}
|
||||
}
|
||||
}
|
||||
nodes.push({item: item, children: [terminal_node], parents: [root_node], set_pos: set_pos, set_neg: set_neg});
|
||||
}
|
||||
// Dependency graph construction.
|
||||
for (const node_a of nodes) {
|
||||
const {item: a, children: a_children} = node_a;
|
||||
const {item: a, children: a_children, set_pos: a_set_pos} = node_a;
|
||||
for (const node_b of nodes) {
|
||||
const {item: b, parents: b_parents} = node_b;
|
||||
const {item: b, parents: b_parents, set_neg: b_set_neg} = node_b;
|
||||
|
||||
const setName = b.set;
|
||||
|
||||
for (let i = 0; i < 5; ++i) {
|
||||
if (a.skillpoints[i] > 0 && (a.reqs[i] < b.reqs[i] || b.skillpoints[i] < 0)) {
|
||||
if ((a.skillpoints[i] > 0 || a_set_pos[i] > 0)
|
||||
&& (a.reqs[i] < b.reqs[i] || b.skillpoints[i] < 0 || b_set_neg[i] < 0)) {
|
||||
a_children.push(node_b);
|
||||
b_parents.push(node_a);
|
||||
break;
|
||||
|
@ -259,3 +275,4 @@ function construct_scc_graph(items_to_consider) {
|
|||
const sccs = make_SCC_graph(root_node, nodes);
|
||||
return [root_node, terminal_node, sccs];
|
||||
}
|
||||
|
||||
|
|
|
@ -278,7 +278,7 @@ Base64 = (function () {
|
|||
let b64_str = "";
|
||||
let i = 0;
|
||||
while (i < this.length) {
|
||||
b64_str += Base64.fromIntV(this.slice(i, i + 6), 1);
|
||||
b64_str += Base64.fromIntN(this.slice(i, i + 6), 1);
|
||||
i += 6;
|
||||
}
|
||||
|
||||
|
|
|
@ -3798,5 +3798,9 @@
|
|||
"Athanasia": 3796,
|
||||
"Provenance": 3797,
|
||||
"Veneration": 3798,
|
||||
"Reckoning": 3799
|
||||
"Reckoning": 3799,
|
||||
"Eleventh Hour": 3800,
|
||||
"Epilogue": 3801,
|
||||
"Prologue": 3802,
|
||||
"Gleeman's Tale": 3803
|
||||
}
|
137
testing/optimization/analyze_items.py
Normal file
137
testing/optimization/analyze_items.py
Normal file
|
@ -0,0 +1,137 @@
|
|||
import json
|
||||
|
||||
import numpy as np
|
||||
import matplotlib.pyplot as plt
|
||||
|
||||
def max_id(item, id_name, invert=False):
|
||||
"""
|
||||
Calculate the "max roll" for a given ID.
|
||||
|
||||
Parameters
|
||||
Name type desc
|
||||
----------------------------------------------------------
|
||||
item json Item json data
|
||||
id_name string name of the ID to get
|
||||
invert bool Whether to "invert" (raw cost and %cost have funny
|
||||
0.7-1.3 positive roll and 0.3-1.3 negative roll)
|
||||
|
||||
Return:
|
||||
val: float -- max roll id value.
|
||||
"""
|
||||
id_val = item.get(id_name, 0)
|
||||
if id_val == 0: # if the ID isn't present, its just going to be zero
|
||||
return 0
|
||||
|
||||
if item.get('fixID', False):
|
||||
# If the item is a fixed roll item, don't roll the ID.
|
||||
return id_val
|
||||
|
||||
# roll the ID. Negative roll (and invert) max roll is 0.7; positive max is 1.3.
|
||||
if bool(id_val < 0) != bool(invert): # logical XOR
|
||||
val = round(id_val * 0.7)
|
||||
else: #if bool(id_val > 0) != bool(invert):
|
||||
val = round(id_val * 1.3)
|
||||
|
||||
if val == 0: # if we rounded to zero, then restore the id as sign(base_val).
|
||||
val = id_val / abs(id_val)
|
||||
return val
|
||||
|
||||
def mv(item, base_costs):
|
||||
"""
|
||||
Compute mana value for an item.
|
||||
Takes a maximum mana value
|
||||
- assuming 1 melee value (3/3 mana steal = 1 mana value)
|
||||
- assuming spells 1, 3, and 4 are cycle spells.
|
||||
Ignores spell 2 for spell cost purposes.
|
||||
|
||||
Parameters
|
||||
Name type desc
|
||||
----------------------------------------------------------
|
||||
item json Item json data
|
||||
base_costs list[float] base spell cost [spell1, spell2, spell3, spell4]
|
||||
|
||||
Return:
|
||||
val: float -- mana value.
|
||||
"""
|
||||
cost_reductions = sorted([
|
||||
max_id(item, 'spRaw1', True) + base_costs[0]*max_id(item, 'spPct1', True)/100,
|
||||
#max_id(item, 'spRaw2', True) + base_costs[1]*max_id(item, 'spPct2', True)/100,
|
||||
max_id(item, 'spRaw3', True) + base_costs[2]*max_id(item, 'spPct3', True)/100,
|
||||
max_id(item, 'spRaw4', True) + base_costs[3]*max_id(item, 'spPct4', True)/100,
|
||||
])
|
||||
cost_mv = -sum(cost_reductions[:2])
|
||||
|
||||
return (
|
||||
max_id(item, 'ms')/3
|
||||
+ max_id(item, 'mr')/5
|
||||
+ cost_mv
|
||||
)
|
||||
|
||||
###########################
|
||||
# constants for damage calc.
|
||||
elements = 'rnetwfa'
|
||||
raw_ids = ['sdRaw'] + [x+'SdRaw' for x in elements] + [x+'DamRaw' for x in elements]
|
||||
|
||||
# these %boosts apply to all damages.
|
||||
percent_all_ids = ['sdPct', 'rSdPct']
|
||||
|
||||
# this one is a list of lists.
|
||||
# the mini lists are sub-sums, the big list gets max'd over (elemental damage works like this.)
|
||||
percent_max_id_groups = list(zip([x+'DamPct' for x in 'etwfa'] + [x+'SdPct' for x in 'etwfa'])) # exclude neutral lel
|
||||
###########################
|
||||
def damage(item, weapon_base):
|
||||
"""
|
||||
Compute effective damage bonus.
|
||||
Note that this assumes the weapon aligns with whatever bonus this item is giving.
|
||||
|
||||
Parameters
|
||||
Name type desc
|
||||
----------------------------------------------------------
|
||||
item json Item json data
|
||||
weapon_base float weapon base dps
|
||||
|
||||
Return:
|
||||
val: float -- raw damage bonus given (approximate) for the weapon.
|
||||
"""
|
||||
total = sum(max_id(item, x) for x in raw_ids)
|
||||
total += weapon_base * sum(max_id(item, x) for x in percent_all_ids) / 100
|
||||
total += weapon_base * max(sum(max_id(item, y) for y in x) for x in percent_max_id_groups) / 100
|
||||
return total
|
||||
|
||||
|
||||
#################################
|
||||
# NOTE: Edit these parameters! LOL i was lazy to make a CLI
|
||||
level_threshold = 80
|
||||
weapon_base = 700
|
||||
base_costs = [35, 20, 35, 35]
|
||||
item_type = 'leggings'
|
||||
|
||||
# TODO: Changeme to point to a copy of wynnbuilder's compress.json file!
|
||||
items = json.load(open("../../compress.json"))['items']
|
||||
#################################
|
||||
|
||||
|
||||
# collect data from items.
|
||||
points = []
|
||||
names = dict()
|
||||
for item in items:
|
||||
if item['type'] == item_type and item['lvl'] > level_threshold:
|
||||
# Edit me to see other comparisons!
|
||||
#point = (mv(item, base_costs), damage(item, weapon_base))
|
||||
point = (max_id(item, 'spd'), item.get('hp', 0) + max_id(item, 'hpBonus'))
|
||||
|
||||
points.append(point)
|
||||
# just some shenanigans to aggregate text that happens to fall on the same point.
|
||||
if point in names:
|
||||
names[point] += '\n'+item.get('displayName', item['name'])
|
||||
else:
|
||||
names[point] = item.get('displayName', item['name'])
|
||||
points = np.array(points)
|
||||
|
||||
# plot points.
|
||||
plt.figure()
|
||||
plt.scatter(points[:, 0], points[:, 1])
|
||||
# and add annotations.
|
||||
for point, txt in names.items():
|
||||
plt.annotate(txt, point)
|
||||
plt.show()
|
Loading…
Reference in a new issue