Compare commits
15 commits
Author | SHA1 | Date | |
---|---|---|---|
68dda3a649 | |||
73a456ddf5 | |||
11842d4fce | |||
0a6a6aea8b | |||
785400de41 | |||
09e4d858e6 | |||
4147bd813e | |||
bfe19da7c1 | |||
02c4ace7ae | |||
f3b4429b2e | |||
df9412e994 | |||
165adf6dcc | |||
95a7160dcb | |||
47368aab9f | |||
5b623260e5 |
|
@ -82,7 +82,7 @@
|
|||
<div class="container-fluid overall-box mt-lg-2" style="margin-top: 6vh;">
|
||||
<!-- REMOVE THIS DIV AT SOME POINT. -->
|
||||
<div class = "row scaled-font mx-auto" id = "discord-banner-dev">
|
||||
<div class = "col text-center item-title">Join the <a class = "link" href = "https://discord.gg/CGavnAnerv" target = "_blank">discord</a> today to suggest new features, submit bug reports, and hangout/talk to devs!</div>
|
||||
<div id='discord-banner' class = "col text-center item-title">Join the <a class = "link" href = "https://discord.gg/CGavnAnerv" target = "_blank">discord</a> today to suggest new features, submit bug reports, and hangout/talk to devs!</div>
|
||||
</div>
|
||||
<div class="row h-100 gx-lg-5 gy-3 mx-2 mx-lg-3 py-3 gx-0">
|
||||
<div class="col-xl-6">
|
||||
|
|
180859
clean.json
|
@ -2,6 +2,13 @@ main {
|
|||
margin: 24px 0 48px;
|
||||
}
|
||||
|
||||
main h1 {
|
||||
margin: 0 0 8px;
|
||||
color: #bbb;
|
||||
/* font-size: 24pt; */
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
main h2 {
|
||||
margin: 0 0 8px;
|
||||
color: #bbb;
|
||||
|
@ -18,6 +25,20 @@ main p {
|
|||
font-weight: normal;
|
||||
}
|
||||
|
||||
main span {
|
||||
font-size: 13pt;
|
||||
font-weight: normal;
|
||||
}
|
||||
main li {
|
||||
margin-left: 6%;
|
||||
font-size: 13pt;
|
||||
font-weight: normal;
|
||||
}
|
||||
main ul {
|
||||
font-size: 13pt;
|
||||
font-weight: normal;
|
||||
}
|
||||
|
||||
main .footer {
|
||||
font-size: 10pt;
|
||||
text-align: center;
|
||||
|
@ -86,6 +107,13 @@ main .heart {
|
|||
color: #e44078;
|
||||
}
|
||||
|
||||
.fig {
|
||||
margin: 16px 0 16px;
|
||||
}
|
||||
div.caption {
|
||||
font-style: italic;
|
||||
}
|
||||
|
||||
@keyframes scroll-bg {
|
||||
0% {
|
||||
background-position-x: 0;
|
||||
|
@ -108,7 +136,7 @@ main .heart {
|
|||
}
|
||||
|
||||
.section {
|
||||
margin: 0 25vw 28px;
|
||||
margin: 0 15vw 28px;
|
||||
}
|
||||
|
||||
.docs {
|
||||
|
|
27
css/docs_home.css
Normal file
|
@ -0,0 +1,27 @@
|
|||
article {
|
||||
background-color: #212529;
|
||||
margin: 0 0 30px;
|
||||
padding: 10px 10px 10px;
|
||||
border-radius: 5px;
|
||||
display: block;
|
||||
|
||||
position: relative;
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
article h2 {
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
article a {
|
||||
/* display: inline-block;
|
||||
width:100%;
|
||||
height: 100%; */
|
||||
box-sizing: border-box;
|
||||
|
||||
position: absolute;
|
||||
left: 0;
|
||||
right: 0;
|
||||
top: 0;
|
||||
bottom: 0;
|
||||
}
|
|
@ -141,43 +141,43 @@ Wynn-Related CSS
|
|||
color: rgb(255, 198, 85)
|
||||
}
|
||||
|
||||
.nDam, .Neutral {
|
||||
.nDam, .Neutral, Neutral {
|
||||
color: #FFAA00;
|
||||
}
|
||||
|
||||
.nDam:before, .Neutral:before {
|
||||
.nDam:before, .Neutral:before, Neutral:before {
|
||||
content: "\2724" ' ';
|
||||
}
|
||||
|
||||
.eDam, .Earth, .Earth_powder {
|
||||
.eDam, .Earth, .Earth_powder, Earth {
|
||||
color: #00AA00;
|
||||
}
|
||||
|
||||
.eDam:before, .Earth:before, .Earth_powder:before { content: "\2724" ' '; }
|
||||
.eDam:before, .Earth:before, .Earth_powder:before, Earth:before { content: "\2724" ' '; }
|
||||
|
||||
.tDam, .Thunder, .Thunder_powder {
|
||||
.tDam, .Thunder, .Thunder_powder, Thunder{
|
||||
color: #FFFF55;
|
||||
}
|
||||
|
||||
.tDam:before, .Thunder:before, .Thunder_powder:before { content: "\2726" ' '; }
|
||||
.tDam:before, .Thunder:before, .Thunder_powder:before, Thunder:before { content: "\2726" ' '; }
|
||||
|
||||
.wDam, .Water, .Water_powder {
|
||||
.wDam, .Water, .Water_powder, Water {
|
||||
color: #55FFFF
|
||||
}
|
||||
|
||||
.wDam:before, .Water:before, .Water_powder:before { content: "\2749" ' '; }
|
||||
.wDam:before, .Water:before, .Water_powder:before, Water:before { content: "\2749" ' '; }
|
||||
|
||||
.fDam, .Fire, .Fire_powder {
|
||||
.fDam, .Fire, .Fire_powder, Fire {
|
||||
color: #FF5555;
|
||||
}
|
||||
|
||||
.fDam:before, .Fire:before, .Fire_powder:before { content: "\2739" ' '; }
|
||||
.fDam:before, .Fire:before, .Fire_powder:before, Fire:before { content: "\2739" ' '; }
|
||||
|
||||
.aDam, .Air, .Air_powder {
|
||||
.aDam, .Air, .Air_powder, Air {
|
||||
color: #FFFFFF
|
||||
}
|
||||
|
||||
.aDam:before, .Air:before, .Air_powder:before { content: "\274b" ' '; }
|
||||
.aDam:before, .Air:before, .Air_powder:before, Air:before { content: "\274b" ' '; }
|
||||
|
||||
.restrict {
|
||||
color: #ff8180;
|
||||
|
|
1
data/2.0.4.3/atree.json
Normal file
1
data/2.0.4.3/ingreds.json
Normal file
1
data/2.0.4.3/items.json
Normal file
1
data/2.0.4.3/majid.json
Executable file
1
data/2.0.4.3/recipes.json
Normal file
1069
data/2.0.4.3/tomes.json
Normal file
59962
ingreds_clean.json
|
@ -22,13 +22,13 @@
|
|||
</head>
|
||||
<body class = "text-light d-flex justify-content-center" id = "body">
|
||||
<div id="main-sidebar" class="sidebar dark-7 dark-shadow">
|
||||
<a href = "../builder/"><img src="../media/icons/new/builder.png" alt = "WynnBuilder" title = "WynnBuilder"><b>WynnBuilder</b></a>
|
||||
<a href = "../crafter/"><img src = "../media/icons/new/crafter.png" alt = "WynnCrafter" title = "WynnCrafter"><b>WynnCrafter</b></a>
|
||||
<a href = "../items/"><img src = "../media/icons/new/searcher.png" alt = "WynnAtlas" title = "WynnAtlas"><b>WynnAtlas</b></a>
|
||||
<a href = "/customizer.html"><img src = "../media/icons/new/custom.png" alt = "WynnCustom" title = "WynnCustom"><b>WynnCustom</b></a>
|
||||
<a href = "/map.html"><img src = "../media/icons/new/compass.png" alt = "WynnGPS" title = "WynnGPS"><b>WynnGPS</b></a>
|
||||
<a href = "/wynnfo/index.html"><img src = "../media/icons/new/book.png" alt = "Wynnfo" title = "WynnCrafter"><b>WynnCrafter</b></a>
|
||||
<a onclick = "toggleIcons()"><img src = "../media/icons/new/reload.png" alt = "" title = "Swap items on page"><b>Swap Icon Style</b></a>
|
||||
<a href = "/builder/"><img src="/media/icons/new/builder.png" alt = "WynnBuilder" title = "WynnBuilder"><b>WynnBuilder</b></a>
|
||||
<a href = "/crafter/"><img src = "/media/icons/new/crafter.png" alt = "WynnCrafter" title = "WynnCrafter"><b>WynnCrafter</b></a>
|
||||
<a href = "/items/"><img src = "/media/icons/new/searcher.png" alt = "WynnAtlas" title = "WynnAtlas"><b>WynnAtlas</b></a>
|
||||
<a href = "/customizer.html"><img src = "/media/icons/new/custom.png" alt = "WynnCustom" title = "WynnCustom"><b>WynnCustom</b></a>
|
||||
<a href = "/map.html"><img src = "/media/icons/new/compass.png" alt = "WynnGPS" title = "WynnGPS"><b>WynnGPS</b></a>
|
||||
<a href = "/wynnfo/"><img src = "/media/icons/new/book.png" alt = "Wynnfo" title = "Wynnfo"><b>Wynnfo</b></a>
|
||||
<a onclick = "toggleIcons()"><img src = "/media/icons/new/reload.png" alt = "" title = "Swap items on page"><b>Swap Icon Style</b></a>
|
||||
<hr/>
|
||||
<a href = "https://discord.gg/CGavnAnerv" target = "_blank"><img src = "../media/icons/discord.png" alt = "WB Discord" title = "WB Discord"><b>WB Discord</b></a>
|
||||
</div>
|
||||
|
@ -39,7 +39,7 @@
|
|||
<a href="../credits.txt" class="link">Additional credits</a>
|
||||
</div>
|
||||
<div class = "col text-center" id = "help">
|
||||
<a href="items_adv_help.html" class="link" target="_blank">Search Guide</a>
|
||||
<a href="/wynnfo/items_adv_help/" class="link" target="_blank">Search Guide</a>
|
||||
</div>
|
||||
<div class = "col text-end">
|
||||
<a href = "../items/">Basic Item Search</a>
|
||||
|
|
196538
items_clean.json
Normal file
1
items_compress.json
Normal file
|
@ -805,7 +805,6 @@ const atrees = {
|
|||
"name": "Phantom Ray",
|
||||
"base_spell": 1,
|
||||
"spell_type": "damage",
|
||||
"scaling": "spell",
|
||||
"display": "Total Damage",
|
||||
"parts": [
|
||||
{
|
||||
|
@ -2890,7 +2889,6 @@ const atrees = {
|
|||
"cost": 40,
|
||||
"base_spell": 1,
|
||||
"spell_type": "damage",
|
||||
"scaling": "spell",
|
||||
"display": "Total Damage",
|
||||
"parts": [
|
||||
{
|
||||
|
@ -3018,7 +3016,6 @@ const atrees = {
|
|||
"cost": 25,
|
||||
"base_spell": 2,
|
||||
"spell_type": "damage",
|
||||
"scaling": "spell",
|
||||
"display": "",
|
||||
"parts": []
|
||||
}
|
||||
|
@ -3281,7 +3278,6 @@ const atrees = {
|
|||
"cost": 30,
|
||||
"base_spell": 4,
|
||||
"spell_type": "damage",
|
||||
"scaling": "spell",
|
||||
"display": "Total Damage",
|
||||
"parts": [
|
||||
{
|
||||
|
@ -7361,9 +7357,6 @@ const atrees = {
|
|||
"name": "Spin Attack",
|
||||
"cost": 40,
|
||||
"base_spell": 1,
|
||||
"spell_type": "damage",
|
||||
"scaling": "spell",
|
||||
"use_atkspd": true,
|
||||
"display": "Spin Attack",
|
||||
"parts": [
|
||||
{
|
||||
|
@ -9052,7 +9045,7 @@ const atrees = {
|
|||
},
|
||||
{
|
||||
"display_name": "Parry",
|
||||
"desc": "After dodging damage, gain a brief damage buff, and make your next spell within 1.5 free. (3s Cooldown)",
|
||||
"desc": "After dodging damage, gain a brief damage buff, and make your next spell within 1.5s free. (3s Cooldown)",
|
||||
"archetype": "Acrobat",
|
||||
"archetype_req": 5,
|
||||
"parents": [
|
||||
|
@ -9119,7 +9112,8 @@ const atrees = {
|
|||
"Cheaper Dash II"
|
||||
],
|
||||
"dependencies": [
|
||||
"Vanish"
|
||||
"Vanish",
|
||||
"Marked"
|
||||
],
|
||||
"blockers": [],
|
||||
"cost": 2,
|
||||
|
@ -9771,7 +9765,7 @@ const atrees = {
|
|||
},
|
||||
{
|
||||
"display_name": "Nightcloak Knife",
|
||||
"desc": "If cast while in Vanish, Spin Attack will consume all Marks from nearby enemies to summon the Nightcloak Knife.\n The Knife will mimic your attacks on enemies within 6 blocks of you, dealing 4% of your damage for every 1 Mark consumed. (Max 10 Marks)\n The Knife will vanish after 8s",
|
||||
"desc": "If cast while in Vanish, Spin Attack will consume all Marks from nearby enemies to summon the Nightcloak Knife.\n The Knife will mimic your attacks on enemies within 6 blocks of you, dealing 4% of your damage for every 1 Mark consumed. (Max 10 Marks)\n The Knife will vanish after 15s",
|
||||
"archetype": "Shadestepper",
|
||||
"archetype_req": 0,
|
||||
"parents": [
|
||||
|
@ -9975,8 +9969,8 @@ const atrees = {
|
|||
"type": "replace_spell",
|
||||
"name": "Relik Melee",
|
||||
"base_spell": 0,
|
||||
"spell_type": "damage",
|
||||
"scaling": "melee", "use_atkspd": false,
|
||||
"scaling": "melee",
|
||||
"use_atkspd": false,
|
||||
"display": "Total",
|
||||
"parts": [
|
||||
{ "name": "Single Beam", "multipliers": [35, 0, 0, 0, 0, 0] },
|
||||
|
@ -10090,8 +10084,8 @@ const atrees = {
|
|||
"type": "replace_spell",
|
||||
"name": "Relik Melee",
|
||||
"base_spell": 0,
|
||||
"spell_type": "damage",
|
||||
"scaling": "melee", "use_atkspd": false,
|
||||
"scaling": "melee",
|
||||
"use_atkspd": false,
|
||||
"display": "Total",
|
||||
"parts": [
|
||||
{ "name": "Single Beam", "multipliers": [34, 0, 0, 0, 0, 0] },
|
||||
|
@ -10610,7 +10604,6 @@ const atrees = {
|
|||
"type": "replace_spell",
|
||||
"name": "Puppet Damage",
|
||||
"base_spell": 6,
|
||||
"scaling": "spell",
|
||||
"display": "Total Puppet DPS",
|
||||
"parts": [
|
||||
{
|
||||
|
@ -11401,7 +11394,6 @@ const atrees = {
|
|||
"type": "replace_spell",
|
||||
"name": "Twisted Tether",
|
||||
"base_spell": 8,
|
||||
"scaling": "spell",
|
||||
"display": "Tether Tick",
|
||||
"parts": [
|
||||
{
|
||||
|
@ -11588,7 +11580,7 @@ const atrees = {
|
|||
"display_name": "Fluid Healing",
|
||||
"desc": "For every 1% Water Damage you have from items, buff Aura's healing power by +0.3%.",
|
||||
"parents": ["Twisted Tether", "Mask of the Coward", "Larger Blood Pool II"],
|
||||
"dependencies": [],
|
||||
"dependencies": [ "Sacrificial Shrine" ],
|
||||
"blockers": [],
|
||||
"cost": 2,
|
||||
"display": {
|
||||
|
|
|
@ -33,7 +33,8 @@ const wynn_version_names = [
|
|||
'2.0.2.1',
|
||||
'2.0.2.3',
|
||||
'2.0.3.1',
|
||||
'2.0.4.1'
|
||||
'2.0.4.1',
|
||||
'2.0.4.3'
|
||||
];
|
||||
const WYNN_VERSION_LATEST = wynn_version_names.length - 1;
|
||||
// Default to the newest version.
|
||||
|
|
|
@ -827,9 +827,13 @@ class AggregateStatsNode extends ComputeNode {
|
|||
}
|
||||
}
|
||||
|
||||
let radiance_affected = [ /*"hp"*/, "fDef", "wDef", "aDef", "tDef", "eDef", "hprPct", "mr", "sdPct", "mdPct", "ls", "ms", "xpb", "lb", "ref",
|
||||
/*"str", "dex", "int", "agi", "def",*/
|
||||
"thorns", "expd", "spd", "atkTier", "poison", "hpBonus", "spRegen", "eSteal", "hprRaw", "sdRaw", "mdRaw", "fDamPct", "wDamPct", "aDamPct", "tDamPct", "eDamPct", "fDefPct", "wDefPct", "aDefPct", "tDefPct", "eDefPct", "fixID", "category", "spPct1", "spRaw1", "spPct2", "spRaw2", "spPct3", "spRaw3", "spPct4", "spRaw4", "rSdRaw", "sprint", "sprintReg", "jh", "lq", "gXp", "gSpd",
|
||||
let radiance_affected = [ /*"hp"*/, "fDef", "wDef", "aDef", "tDef", "eDef", "hprPct", "mr", "sdPct", "mdPct", "ls", "ms",
|
||||
// "xpb", "lb",
|
||||
"ref",
|
||||
/*"str", "dex", "int", "agi", "def",*/ // TODO its affected but i have to make it not affect req
|
||||
"thorns", "expd", "spd", "atkTier", "poison", "hpBonus", "spRegen", "eSteal", "hprRaw", "sdRaw", "mdRaw", "fDamPct", "wDamPct", "aDamPct", "tDamPct", "eDamPct", "fDefPct", "wDefPct", "aDefPct", "tDefPct", "eDefPct", "fixID", "category", "spPct1", "spRaw1", "spPct2", "spRaw2", "spPct3", "spRaw3", "spPct4", "spRaw4", "rSdRaw", "sprint", "sprintReg", "jh",
|
||||
|
||||
// "lq", "gXp", "gSpd",
|
||||
|
||||
// wynn2 damages.
|
||||
"eMdPct","eMdRaw","eSdPct","eSdRaw",/*"eDamPct,"*/"eDamRaw",//"eDamAddMin","eDamAddMax",
|
||||
|
@ -868,12 +872,12 @@ const radiance_node = new (class extends ComputeNode {
|
|||
}
|
||||
}
|
||||
}
|
||||
const dam_mults = new Map(ret.get('damMult'));
|
||||
dam_mults.set('tome', dam_mults.get('tome') * 1.2)
|
||||
ret.set('damMult', dam_mults)
|
||||
const def_mults = new Map(ret.get('defMult'));
|
||||
def_mults.set('tome', def_mults.get('tome') * 1.2)
|
||||
ret.set('defMult', def_mults)
|
||||
// const dam_mults = new Map(ret.get('damMult'));
|
||||
// dam_mults.set('tome', dam_mults.get('tome') * 1.2)
|
||||
// ret.set('damMult', dam_mults)
|
||||
// const def_mults = new Map(ret.get('defMult'));
|
||||
// def_mults.set('tome', def_mults.get('tome') * 1.2)
|
||||
// ret.set('defMult', def_mults)
|
||||
return ret;
|
||||
}
|
||||
else {
|
||||
|
|
|
@ -1,4 +1,14 @@
|
|||
{
|
||||
"FISSION": {
|
||||
"displayName": "Fission",
|
||||
"description": "Explosions from your Exploding ID are twice as big and twice as strong",
|
||||
"abilities": []
|
||||
},
|
||||
"EXPLOSIVE_IMPACT": {
|
||||
"displayName": "Explosive Impact",
|
||||
"description": "Your Exploding ID can trigger when hitting mobs with your Main Attack",
|
||||
"abilities": []
|
||||
},
|
||||
"MAGNET": {
|
||||
"displayName": "Magnet",
|
||||
"description": "Pulls items within an 8 block radius towards you",
|
||||
|
@ -214,7 +224,7 @@
|
|||
"abilities": []
|
||||
},
|
||||
"DESC_FESTIVESPIRIT": {
|
||||
"displayName": "Festive Spirits",
|
||||
"displayName": "Festive Spirit",
|
||||
"description": "Plays wintery tunes",
|
||||
"abilities": []
|
||||
},
|
||||
|
@ -260,7 +270,7 @@
|
|||
}]
|
||||
},
|
||||
"ALTEREGO": {
|
||||
"displayName": "Alterego",
|
||||
"displayName": "Alter Ego",
|
||||
"description": "Awakened can be activated after saving 40% less mana, but its duration is reduced by 25%.",
|
||||
"abilities": []
|
||||
},
|
||||
|
@ -296,7 +306,7 @@
|
|||
}]
|
||||
},
|
||||
"SOUL_EATER": {
|
||||
"displayName": "Soul eater",
|
||||
"displayName": "Soul Eater",
|
||||
"description": "Devour and Harvester grant double mana, but your maximum Marks are decreased by 1.",
|
||||
"abilities": [{
|
||||
"class": "Assassin",
|
||||
|
@ -398,7 +408,7 @@
|
|||
},
|
||||
"DIVINE_HONOR": {
|
||||
"displayName": "Divine Honor",
|
||||
"description": "Increase the bonus from Radiance by 5%. Decrease the Neutral damage of Bash by -15%.",
|
||||
"description": "Increase the bonus from Radiance by 5%. Decrease the Earth damage of Bash by -15%.",
|
||||
"abilities": [{
|
||||
"class": "Warrior",
|
||||
"base_abil": "Bash",
|
||||
|
@ -408,7 +418,7 @@
|
|||
"base_spell": 1,
|
||||
"target_part": "Single Hit",
|
||||
"behavior": "modify",
|
||||
"multipliers": [-15, 0, 0, 0, 0, 0]
|
||||
"multipliers": [0, -15, 0, 0, 0, 0]
|
||||
}
|
||||
]
|
||||
}]
|
||||
|
@ -456,5 +466,67 @@
|
|||
}
|
||||
]
|
||||
}]
|
||||
},
|
||||
"GRUESOME_KNOTS": {
|
||||
"displayName": "Gruesome Knots",
|
||||
"description":"Twisted Tether spends twice as much of your Blood Pool to deal triple damage",
|
||||
"abilities": [{
|
||||
"class": "Shaman",
|
||||
"base_abil": "Twisted Tether",
|
||||
"effects": [{
|
||||
"type": "raw_stat",
|
||||
"bonuses": [
|
||||
{
|
||||
"type": "stat",
|
||||
"name": "damMult.GruesomeKnots:8.Tether Tick",
|
||||
"value": 200
|
||||
}
|
||||
]
|
||||
}]
|
||||
}]
|
||||
},
|
||||
"COAGULATE": {
|
||||
"displayName": "Coagulate",
|
||||
"description":"Blood Connection launches you further and higher upon teleporting to a nearby Totem",
|
||||
"abilities": []
|
||||
},
|
||||
"DEADWEIGHT": {
|
||||
"displayName": "Dead Weight",
|
||||
"description":"Totem's horizontal velocity is greatly increased at the cost of vertical movement",
|
||||
"abilities": []
|
||||
},
|
||||
"EXPUNGE": {
|
||||
"displayName": "Expunge",
|
||||
"description":"When using Heal, instead cast one instant pulse that heals 20% of your max health",
|
||||
"abilities": [{
|
||||
"class": "Mage",
|
||||
"base_abil": "Heal",
|
||||
"effects": [
|
||||
{
|
||||
"type": "add_spell_prop",
|
||||
"base_spell": 1,
|
||||
"target_part": "Second and Third Pulses",
|
||||
"behavior": "modify",
|
||||
"power": -0.20
|
||||
},
|
||||
{
|
||||
"type": "add_spell_prop",
|
||||
"base_spell": 1,
|
||||
"target_part": "Heal",
|
||||
"behavior": "modify",
|
||||
"power": 0.05
|
||||
}
|
||||
]
|
||||
}]
|
||||
},
|
||||
"LUNGE": {
|
||||
"displayName": "Lunge",
|
||||
"description":"Hop's horizontal velocity is greatly increased",
|
||||
"abilities": []
|
||||
},
|
||||
"WINDSURF": {
|
||||
"displayName": "Windsurf",
|
||||
"description":"Righting Reflex lasts twice as long and is affected stronger by movement speed",
|
||||
"abilities": []
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
let recipeTypes = ["HELMET","CHESTPLATE","LEGGINGS","BOOTS","RELIK","WAND","SPEAR","DAGGER","BOW","RING","NECKLACE","BRACELET","SCROLL","FOOD","POTION"];
|
||||
let recipeTypes = ["HELMET","CHESTPLATE","LEGGINGS","BOOTS","RELIK","WAND","SPEAR","DAGGER","BOW","RING","NECKLACE","BRACELET","POTION", "SCROLL","FOOD"];
|
||||
let levelTypes = ["1-3","3-5","5-7","7-9","10-13","13-15","15-17","17-19","20-23","23-25","25-27","27-29","30-33","33-35","35-37","37-39","40-43","43-45","45-47","47-49","50-53","53-55","55-57","57-59","60-63","63-65","65-67","67-69","70-73","73-75","75-77","77-79","80-83","83-85","85-87","87-89","90-93","93-95","95-97","97-99","100-103","103-105",]
|
||||
|
||||
function encodeCraft(craft) {
|
||||
|
|
|
@ -144,8 +144,8 @@ function calculateSpellDamage(stats, weapon, _conversions, use_spell_damage, ign
|
|||
// Collect total damage post %boost
|
||||
}
|
||||
|
||||
let total_elem_min = total_min - damages[0][0];
|
||||
let total_elem_max = total_max - damages[0][1];
|
||||
let total_elem_min = total_min - save_prop[0][0];
|
||||
let total_elem_max = total_max - save_prop[0][1];
|
||||
|
||||
// 5.2: Raw application.
|
||||
let prop_raw = stats.get(specific_boost_str.toLowerCase()+'Raw') + stats.get('damRaw');
|
||||
|
|
105
js/docs.js
Normal file
|
@ -0,0 +1,105 @@
|
|||
/** Vanilla JS does not allow dynamically fetching files in a local directory. We have to hard code the list to loop over.
|
||||
* Each entry is the name of a subfolder in /docs/.
|
||||
*/
|
||||
const docs_post_names = [
|
||||
"items_adv_help",
|
||||
"damage_calc",
|
||||
"powders"
|
||||
]
|
||||
|
||||
/** Map of
|
||||
* Key: post_name - the subdirectory name also present in docs_post_names
|
||||
* Value: [Title, Summary, Author(s)]
|
||||
*/
|
||||
docs_post_thumbnails = new Map();
|
||||
docs_post_thumbnails.set("items_adv_help", ["Advanced Item Search Help", "A practical guide on how to use WynnBuilder's advanced item search feature.", "Phanta"]);
|
||||
docs_post_thumbnails.set("damage_calc", ["Damage Calculation", "All the ins and outs of Wynncraft damage calculation. Includes spells, powder specials, abilities, and major IDs!", "hppeng, ferricles"]);
|
||||
docs_post_thumbnails.set("powders", ["Weapon Powder Application", "Read this to learn the mechanics of powder application on weapons!", "ferricles, hppeng"]);
|
||||
|
||||
/** Populates the HTML element with the id 'post-list'
|
||||
*
|
||||
*/
|
||||
function populate_post_previews() {
|
||||
post_list_parent = document.getElementById('post-list');
|
||||
|
||||
docs_post_names.forEach((post_name) => {
|
||||
post = document.createElement('article');
|
||||
post_info = docs_post_thumbnails.get(post_name);
|
||||
console.log(post_info);
|
||||
if (post_info == undefined) {
|
||||
return;
|
||||
}
|
||||
|
||||
title = document.createElement('h2');
|
||||
title.innerHTML = post_info[0];
|
||||
post.appendChild(title);
|
||||
|
||||
summary = document.createElement('p');
|
||||
summary.innerHTML = post_info[1];
|
||||
post.appendChild(summary);
|
||||
|
||||
authors = document.createElement('p');
|
||||
authors.innerHTML = "Author(s): " + post_info[2];
|
||||
post.appendChild(authors);
|
||||
|
||||
link = document.createElement("a");
|
||||
link.setAttribute('href', `/wynnfo/${post_name}/`);
|
||||
post.appendChild(link);
|
||||
|
||||
post_list_parent.appendChild(post);
|
||||
});
|
||||
}
|
||||
|
||||
function initDropdownSections() {
|
||||
dropdowns = document.querySelectorAll('span.dropdown');
|
||||
for (const dropdown of dropdowns) {
|
||||
let inner_content = dropdown.children[0]
|
||||
|
||||
dropdown.classList.add("up", "row");
|
||||
let title = document.createElement("div");
|
||||
title.classList.add("col-10", "item-title", "text-start", "dropdown-title")
|
||||
title.style.margin = "0 0 0";
|
||||
title.style.fontWeight = "bold";
|
||||
title.style.fontSize = 18;
|
||||
title.style.textDecoration = "underline";
|
||||
title.textContent = dropdown.title;
|
||||
dropdown.textContent = "";
|
||||
let indicator = document.createElement("div");
|
||||
indicator.classList.add("col-auto", "fw-bold", "box-title");
|
||||
indicator.textContent = "+";
|
||||
dropdown.prepend(indicator);
|
||||
dropdown.prepend(title);
|
||||
dropdown.appendChild(inner_content);
|
||||
inner_content.style.display = "none";
|
||||
|
||||
title.addEventListener("click", function(){
|
||||
if (dropdown.classList.contains("up")) {
|
||||
dropdown.classList.remove("up");
|
||||
dropdown.classList.add("down");
|
||||
indicator.textContent = "-";
|
||||
|
||||
inner_content.style.display = "";
|
||||
} else {
|
||||
dropdown.classList.remove("down");
|
||||
dropdown.classList.add("up");
|
||||
indicator.textContent = "+";
|
||||
|
||||
inner_content.style.display = "none";
|
||||
}
|
||||
});
|
||||
title.addEventListener("mouseover", function(){
|
||||
title.style.color = "#ddd";
|
||||
// title.style.fontWeight = "bold";
|
||||
indicator.style.color = "#ddd";
|
||||
// indicator.style.fontWeight = "bold";
|
||||
});
|
||||
title.addEventListener("mouseleave", function(){
|
||||
title.style.color = "";
|
||||
// title.style.fontWeight = "normal";
|
||||
indicator.style.color = "";
|
||||
// indicator.style.fontWeight = "normal";
|
||||
});
|
||||
|
||||
|
||||
}
|
||||
}
|
|
@ -47,54 +47,54 @@ const translate_mappings = {
|
|||
"Soul Point Regen": "spRegen",
|
||||
"Stealing": "eSteal",
|
||||
"Raw Health Regen": "hprRaw",
|
||||
"Spell Damage Raw: ": "sdRaw",
|
||||
"Elem. Spell Damage Raw: ": "rSdRaw",
|
||||
"Neut. Spell Damage Raw: ": "nSdRaw",
|
||||
"Earth Spell Damage Raw: ": "eSdRaw",
|
||||
"Thunder Spell Damage Raw: ": "tSdRaw",
|
||||
"Water Spell Damage Raw: ": "wSdRaw",
|
||||
"Fire Spell Damage Raw: ": "fSdRaw",
|
||||
"Air Spell Damage Raw: ": "aSdRaw",
|
||||
"Spell Damage %: ": "sdPct",
|
||||
"Elem. Spell Damage %: ": "rSdPct",
|
||||
"Neut. Spell Damage %: ": "nSdPct",
|
||||
"Earth Spell Damage %: ": "eSdPct",
|
||||
"Thunder Spell Damage %: ": "tSdPct",
|
||||
"Water Spell Damage %: ": "wSdPct",
|
||||
"Fire Spell Damage %: ": "fSdPct",
|
||||
"Air Spell Damage %: ": "aSdPct",
|
||||
"Melee Damage Raw: ": "mdRaw",
|
||||
"Elem. Melee Damage Raw: ": "rMdRaw",
|
||||
"Neut. Melee Damage Raw: ": "nMdRaw",
|
||||
"Earth Melee Damage Raw: ": "eMdRaw",
|
||||
"Thunder Melee Damage Raw: ": "tMdRaw",
|
||||
"Water Melee Damage Raw: ": "wMdRaw",
|
||||
"Fire Melee Damage Raw: ": "fMdRaw",
|
||||
"Air Melee Damage Raw: ": "aMdRaw",
|
||||
"Melee Damage %: ": "mdPct",
|
||||
"Elem. Melee Damage %: ": "rMdPct",
|
||||
"Neut. Melee Damage %: ": "nMdPct",
|
||||
"Earth Melee Damage %: ": "eMdPct",
|
||||
"Thunder Melee Damage %: ": "tMdPct",
|
||||
"Water Melee Damage %: ": "wMdPct",
|
||||
"Fire Melee Damage %: ": "fMdPct",
|
||||
"Air Melee Damage %: ": "aMdPct",
|
||||
"Damage Raw: ": "damRaw",
|
||||
"Elemental Damage Raw: ": "rDamRaw",
|
||||
"Neutral Damage Raw: ": "nDamRaw",
|
||||
"Earth Damage Raw: ": "eDamRaw",
|
||||
"Thunder Damage Raw: ": "tDamRaw",
|
||||
"Water Damage Raw: ": "wDamRaw",
|
||||
"Fire Damage Raw: ": "fDamRaw",
|
||||
"Air Damage Raw: ": "aDamRaw",
|
||||
"Damage %: ": "damPct",
|
||||
"Elemental Damage %: ": "rDamPct",
|
||||
"Neutral Damage %: ": "nDamPct",
|
||||
"Earth Damage %: ": "eDamPct",
|
||||
"Thunder Damage %: ": "tDamPct",
|
||||
"Water Damage %: ": "wDamPct",
|
||||
"Fire Damage %: ": "fDamPct",
|
||||
"Air Damage %: ": "aDamPct",
|
||||
"Spell Damage Raw": "sdRaw",
|
||||
"Elem. Spell Damage Raw": "rSdRaw",
|
||||
"Neut. Spell Damage Raw": "nSdRaw",
|
||||
"Earth Spell Damage Raw": "eSdRaw",
|
||||
"Thunder Spell Damage Raw": "tSdRaw",
|
||||
"Water Spell Damage Raw": "wSdRaw",
|
||||
"Fire Spell Damage Raw": "fSdRaw",
|
||||
"Air Spell Damage Raw": "aSdRaw",
|
||||
"Spell Damage %": "sdPct",
|
||||
"Elem. Spell Damage %": "rSdPct",
|
||||
"Neut. Spell Damage %": "nSdPct",
|
||||
"Earth Spell Damage %": "eSdPct",
|
||||
"Thunder Spell Damage %": "tSdPct",
|
||||
"Water Spell Damage %": "wSdPct",
|
||||
"Fire Spell Damage %": "fSdPct",
|
||||
"Air Spell Damage %": "aSdPct",
|
||||
"Melee Damage Raw": "mdRaw",
|
||||
"Elem. Melee Damage Raw": "rMdRaw",
|
||||
"Neut. Melee Damage Raw": "nMdRaw",
|
||||
"Earth Melee Damage Raw": "eMdRaw",
|
||||
"Thunder Melee Damage Raw": "tMdRaw",
|
||||
"Water Melee Damage Raw": "wMdRaw",
|
||||
"Fire Melee Damage Raw": "fMdRaw",
|
||||
"Air Melee Damage Raw": "aMdRaw",
|
||||
"Melee Damage %": "mdPct",
|
||||
"Elem. Melee Damage %": "rMdPct",
|
||||
"Neut. Melee Damage %": "nMdPct",
|
||||
"Earth Melee Damage %": "eMdPct",
|
||||
"Thunder Melee Damage %": "tMdPct",
|
||||
"Water Melee Damage %": "wMdPct",
|
||||
"Fire Melee Damage %": "fMdPct",
|
||||
"Air Melee Damage %": "aMdPct",
|
||||
"Damage Raw": "damRaw",
|
||||
"Elemental Damage Raw": "rDamRaw",
|
||||
"Neutral Damage Raw": "nDamRaw",
|
||||
"Earth Damage Raw": "eDamRaw",
|
||||
"Thunder Damage Raw": "tDamRaw",
|
||||
"Water Damage Raw": "wDamRaw",
|
||||
"Fire Damage Raw": "fDamRaw",
|
||||
"Air Damage Raw": "aDamRaw",
|
||||
"Damage %": "damPct",
|
||||
"Elemental Damage %": "rDamPct",
|
||||
"Neutral Damage %": "nDamPct",
|
||||
"Earth Damage %": "eDamPct",
|
||||
"Thunder Damage %": "tDamPct",
|
||||
"Water Damage %": "wDamPct",
|
||||
"Fire Damage %": "fDamPct",
|
||||
"Air Damage %": "aDamPct",
|
||||
|
||||
"% Fire Defense": "fDefPct",
|
||||
"% Water Defense": "wDefPct",
|
||||
|
|
96
js/items.js
|
@ -56,54 +56,54 @@ const translate_mappings = {
|
|||
"Soul Point Regen": "spRegen",
|
||||
"Stealing": "eSteal",
|
||||
"Raw Health Regen": "hprRaw",
|
||||
"Spell Damage Raw: ": "sdRaw",
|
||||
"Elem. Spell Damage Raw: ": "rSdRaw",
|
||||
"Neut. Spell Damage Raw: ": "nSdRaw",
|
||||
"Earth Spell Damage Raw: ": "eSdRaw",
|
||||
"Thunder Spell Damage Raw: ": "tSdRaw",
|
||||
"Water Spell Damage Raw: ": "wSdRaw",
|
||||
"Fire Spell Damage Raw: ": "fSdRaw",
|
||||
"Air Spell Damage Raw: ": "aSdRaw",
|
||||
"Spell Damage %: ": "sdPct",
|
||||
"Elem. Spell Damage %: ": "rSdPct",
|
||||
"Neut. Spell Damage %: ": "nSdPct",
|
||||
"Earth Spell Damage %: ": "eSdPct",
|
||||
"Thunder Spell Damage %: ": "tSdPct",
|
||||
"Water Spell Damage %: ": "wSdPct",
|
||||
"Fire Spell Damage %: ": "fSdPct",
|
||||
"Air Spell Damage %: ": "aSdPct",
|
||||
"Melee Damage Raw: ": "mdRaw",
|
||||
"Elem. Melee Damage Raw: ": "rMdRaw",
|
||||
"Neut. Melee Damage Raw: ": "nMdRaw",
|
||||
"Earth Melee Damage Raw: ": "eMdRaw",
|
||||
"Thunder Melee Damage Raw: ": "tMdRaw",
|
||||
"Water Melee Damage Raw: ": "wMdRaw",
|
||||
"Fire Melee Damage Raw: ": "fMdRaw",
|
||||
"Air Melee Damage Raw: ": "aMdRaw",
|
||||
"Melee Damage %: ": "mdPct",
|
||||
"Elem. Melee Damage %: ": "rMdPct",
|
||||
"Neut. Melee Damage %: ": "nMdPct",
|
||||
"Earth Melee Damage %: ": "eMdPct",
|
||||
"Thunder Melee Damage %: ": "tMdPct",
|
||||
"Water Melee Damage %: ": "wMdPct",
|
||||
"Fire Melee Damage %: ": "fMdPct",
|
||||
"Air Melee Damage %: ": "aMdPct",
|
||||
"Damage Raw: ": "damRaw",
|
||||
"Elemental Damage Raw: ": "rDamRaw",
|
||||
"Neutral Damage Raw: ": "nDamRaw",
|
||||
"Earth Damage Raw: ": "eDamRaw",
|
||||
"Thunder Damage Raw: ": "tDamRaw",
|
||||
"Water Damage Raw: ": "wDamRaw",
|
||||
"Fire Damage Raw: ": "fDamRaw",
|
||||
"Air Damage Raw: ": "aDamRaw",
|
||||
"Damage %: ": "damPct",
|
||||
"Elemental Damage %: ": "rDamPct",
|
||||
"Neutral Damage %: ": "nDamPct",
|
||||
"Earth Damage %: ": "eDamPct",
|
||||
"Thunder Damage %: ": "tDamPct",
|
||||
"Water Damage %: ": "wDamPct",
|
||||
"Fire Damage %: ": "fDamPct",
|
||||
"Air Damage %: ": "aDamPct",
|
||||
"Spell Damage Raw": "sdRaw",
|
||||
"Elem. Spell Damage Raw": "rSdRaw",
|
||||
"Neut. Spell Damage Raw": "nSdRaw",
|
||||
"Earth Spell Damage Raw": "eSdRaw",
|
||||
"Thunder Spell Damage Raw": "tSdRaw",
|
||||
"Water Spell Damage Raw": "wSdRaw",
|
||||
"Fire Spell Damage Raw": "fSdRaw",
|
||||
"Air Spell Damage Raw": "aSdRaw",
|
||||
"Spell Damage %": "sdPct",
|
||||
"Elem. Spell Damage %": "rSdPct",
|
||||
"Neut. Spell Damage %": "nSdPct",
|
||||
"Earth Spell Damage %": "eSdPct",
|
||||
"Thunder Spell Damage %": "tSdPct",
|
||||
"Water Spell Damage %": "wSdPct",
|
||||
"Fire Spell Damage %": "fSdPct",
|
||||
"Air Spell Damage %": "aSdPct",
|
||||
"Melee Damage Raw": "mdRaw",
|
||||
"Elem. Melee Damage Raw": "rMdRaw",
|
||||
"Neut. Melee Damage Raw": "nMdRaw",
|
||||
"Earth Melee Damage Raw": "eMdRaw",
|
||||
"Thunder Melee Damage Raw": "tMdRaw",
|
||||
"Water Melee Damage Raw": "wMdRaw",
|
||||
"Fire Melee Damage Raw": "fMdRaw",
|
||||
"Air Melee Damage Raw": "aMdRaw",
|
||||
"Melee Damage %": "mdPct",
|
||||
"Elem. Melee Damage %": "rMdPct",
|
||||
"Neut. Melee Damage %": "nMdPct",
|
||||
"Earth Melee Damage %": "eMdPct",
|
||||
"Thunder Melee Damage %": "tMdPct",
|
||||
"Water Melee Damage %": "wMdPct",
|
||||
"Fire Melee Damage %": "fMdPct",
|
||||
"Air Melee Damage %": "aMdPct",
|
||||
"Damage Raw": "damRaw",
|
||||
"Elemental Damage Raw": "rDamRaw",
|
||||
"Neutral Damage Raw": "nDamRaw",
|
||||
"Earth Damage Raw": "eDamRaw",
|
||||
"Thunder Damage Raw": "tDamRaw",
|
||||
"Water Damage Raw": "wDamRaw",
|
||||
"Fire Damage Raw": "fDamRaw",
|
||||
"Air Damage Raw": "aDamRaw",
|
||||
"Damage %": "damPct",
|
||||
"Elemental Damage %": "rDamPct",
|
||||
"Neutral Damage %": "nDamPct",
|
||||
"Earth Damage %": "eDamPct",
|
||||
"Thunder Damage %": "tDamPct",
|
||||
"Water Damage %": "wDamPct",
|
||||
"Fire Damage %": "fDamPct",
|
||||
"Air Damage %": "aDamPct",
|
||||
|
||||
"% Fire Defense": "fDefPct",
|
||||
"% Water Defense": "wDefPct",
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
const DB_VERSION = 129;
|
||||
const DB_VERSION = 130;
|
||||
// @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 = 28;
|
||||
const ING_DB_VERSION = 31;
|
||||
|
||||
// @See https://github.com/mdn/learning-area/blob/master/javascript/apis/client-side-storage/indexeddb/video-store/index.js
|
||||
|
||||
|
|
|
@ -167,6 +167,14 @@ const itemQueryProps = (function() {
|
|||
maxId(['lootbonus', 'lb'], 'lb');
|
||||
maxId(['xpbonus', 'xpb', 'xb'], 'xpb');
|
||||
maxId(['stealing', 'esteal'], 'eSteal');
|
||||
maxId(['lq', 'quality'], 'lq');
|
||||
maxId('gxp', 'gXp');
|
||||
maxId('gspd', 'gSpd');
|
||||
maxId(['healeff', 'healpct'], 'healPct');
|
||||
maxId('kb', 'kb');
|
||||
maxId('weakenenemy', 'weakenEnemy');
|
||||
maxId('slowenemy', 'slowEnemy');
|
||||
|
||||
prop(['powderslots', 'powders', 'slots', 'sockets'], 'number', (i, ie) => i.slots || 0);
|
||||
|
||||
return props;
|
||||
|
|
|
@ -3847,5 +3847,26 @@
|
|||
"Pain Cycle": 3845,
|
||||
"Psionic Pretense": 3846,
|
||||
"Propeller Hat": 3847,
|
||||
"Tremorcaller": 3848
|
||||
"Tremorcaller": 3848,
|
||||
"Black Skull": 3849,
|
||||
"Replica Hallowynn Mask": 3850,
|
||||
"Esteemed Bronze Mask of Legendary Victory": 3851,
|
||||
"Swashbuckler's Brogues": 3852,
|
||||
"Outlandish Replica Face Mask of Legendary Victory": 3853,
|
||||
"Mystical Tags": 3854,
|
||||
"Future Shock Plating": 3855,
|
||||
"Spider Leg Suit": 3856,
|
||||
"Ceremonial Skirt": 3857,
|
||||
"Runebound Chains": 3858,
|
||||
"Ice-cold Robe": 3859,
|
||||
"Blob Monster Mask": 3860,
|
||||
"Psychopomp's Pileus": 3861,
|
||||
"Revered Silver Mask of Legendary Victory": 3862,
|
||||
"Treasured Diamond Mask of Legendary Victory": 3863,
|
||||
"Venerated Gold Mask of Legendary Victory": 3864,
|
||||
"Beige Wynnter Sweater": 3865,
|
||||
"Scarlet Wynnter Sweater": 3866,
|
||||
"Orange Wynnter Sweater": 3867,
|
||||
"Pine Wynnter Sweater": 3868,
|
||||
"Indigo Wynnter Sweater": 3869
|
||||
}
|
231
py_script/item_metadata.json
Normal file
|
@ -0,0 +1,231 @@
|
|||
{
|
||||
"identifications": [
|
||||
"rawMainAttackDamage",
|
||||
"rawSpellDamage",
|
||||
"healthRegenRaw",
|
||||
"manaSteal",
|
||||
"walkSpeed",
|
||||
"thunderDamage",
|
||||
"rawStrength",
|
||||
"rawDexterity",
|
||||
"rawIntelligence",
|
||||
"rawDefence",
|
||||
"rawAgility",
|
||||
"lootBonus",
|
||||
"fireDefence",
|
||||
"airDefence",
|
||||
"mainAttackDamage",
|
||||
"spellDamage",
|
||||
"exploding",
|
||||
"airDamage",
|
||||
"rawHealth",
|
||||
"reflection",
|
||||
"earthDefence",
|
||||
"earthDamage",
|
||||
"waterDamage",
|
||||
"waterDefence",
|
||||
"healthRegen",
|
||||
"manaRegen",
|
||||
"fireDamage",
|
||||
"lifeSteal",
|
||||
"rawAttackSpeed",
|
||||
"xpBonus",
|
||||
"thunderDefence",
|
||||
"thorns",
|
||||
"soulPointRegen",
|
||||
"stealing",
|
||||
"1stSpellCost",
|
||||
"2ndSpellCost",
|
||||
"raw1stSpellCost",
|
||||
"raw3rdSpellCost",
|
||||
"jumpHeight",
|
||||
"airSpellDamage",
|
||||
"poison",
|
||||
"elementalDamage",
|
||||
"raw4thSpellCost",
|
||||
"raw2ndSpellCost",
|
||||
"sprintRegen",
|
||||
"slowEnemy",
|
||||
"3rdSpellCost",
|
||||
"sprint",
|
||||
"elementalSpellDamage",
|
||||
"rawNeutralSpellDamage",
|
||||
"4thSpellCost",
|
||||
"healingEfficiency",
|
||||
"knockback",
|
||||
"waterSpellDamage",
|
||||
"fireSpellDamage",
|
||||
"rawAirMainAttackDamage",
|
||||
"rawAirSpellDamage",
|
||||
"earthSpellDamage",
|
||||
"rawThunderDamage",
|
||||
"rawWaterDamage",
|
||||
"rawElementalDamage",
|
||||
"rawEarthSpellDamage",
|
||||
"elementalDefence",
|
||||
"rawThunderMainAttackDamage",
|
||||
"thunderSpellDamage",
|
||||
"rawThunderSpellDamage",
|
||||
"rawFireMainAttackDamage",
|
||||
"weakenEnemy",
|
||||
"rawWaterSpellDamage",
|
||||
"earthMainAttackDamage",
|
||||
"rawFireSpellDamage",
|
||||
"rawElementalSpellDamage",
|
||||
"rawElementalMainAttackDamage",
|
||||
"airMainAttackDamage",
|
||||
"thunderMainAttackDamage",
|
||||
"leveledLootBonus",
|
||||
"damageFromMobs",
|
||||
"leveledXpBonus",
|
||||
"elementalDefense",
|
||||
"rawAirDamage",
|
||||
"rawEarthDamage",
|
||||
"rawFireDamage",
|
||||
"rawNeutralDamage",
|
||||
"lootQuality",
|
||||
"gatherXpBonus",
|
||||
"gatherSpeed",
|
||||
"rawWaterMainAttackDamage"
|
||||
],
|
||||
"majorIds": [
|
||||
"Divine Honor",
|
||||
"Greed",
|
||||
"Magnet",
|
||||
"Plague",
|
||||
"Saviour\u2019s Sacrifice",
|
||||
"Sorcery",
|
||||
"Soul Eater",
|
||||
"Cherry Bombs",
|
||||
"Expunge",
|
||||
"Flashfreeze",
|
||||
"Gentle Glow",
|
||||
"Gruesome Knots",
|
||||
"Peaceful Effigy",
|
||||
"Rally",
|
||||
"Reckless Abandon",
|
||||
"Gravity Well",
|
||||
"Perfect Recall",
|
||||
"Cavalryman",
|
||||
"Entropy",
|
||||
"Escape Route",
|
||||
"Lightweight",
|
||||
"Snowy Steps",
|
||||
"Taunt",
|
||||
"Dead Weight",
|
||||
"Furious Effigy",
|
||||
"Geocentrism",
|
||||
"Strings of Fate",
|
||||
"Alter Ego",
|
||||
"Explosive Impact",
|
||||
"Festive Spirit",
|
||||
"Freerunner",
|
||||
"Hawkeye",
|
||||
"Windsurf",
|
||||
"Juggle",
|
||||
"Roving Assassin",
|
||||
"Transcendence",
|
||||
"Fission",
|
||||
"Forest's Blessing",
|
||||
"Heart of the Pack",
|
||||
"Coagulate",
|
||||
"Guardian",
|
||||
"Overwhelm",
|
||||
"Temblor",
|
||||
"Lunge",
|
||||
"Madness"
|
||||
],
|
||||
"filters": {
|
||||
"type": [
|
||||
"weapons",
|
||||
"armour",
|
||||
"accessories",
|
||||
"tomes",
|
||||
"charms",
|
||||
"tools",
|
||||
"ingredients",
|
||||
"materials"
|
||||
],
|
||||
"advanced": {
|
||||
"attackSpeed": [
|
||||
"super_slow",
|
||||
"very_slow",
|
||||
"slow",
|
||||
"normal",
|
||||
"fast",
|
||||
"very_fast",
|
||||
"super_fast"
|
||||
],
|
||||
"weapons": [
|
||||
"bow",
|
||||
"relik",
|
||||
"wand",
|
||||
"dagger",
|
||||
"spear"
|
||||
],
|
||||
"armour": [
|
||||
"helmet",
|
||||
"chestplate",
|
||||
"leggings",
|
||||
"boots"
|
||||
],
|
||||
"accessories": [
|
||||
"necklace",
|
||||
"ring",
|
||||
"bracelet"
|
||||
],
|
||||
"tomes": [
|
||||
"weaponTome",
|
||||
"armourTome",
|
||||
"slayingTome",
|
||||
"dungeonTome",
|
||||
"gatheringTome",
|
||||
"guildTome",
|
||||
"lootrunTome"
|
||||
],
|
||||
"tools": [
|
||||
"axe",
|
||||
"pickaxe",
|
||||
"rod",
|
||||
"scythe"
|
||||
],
|
||||
"crafting": [
|
||||
"alchemism",
|
||||
"armouring",
|
||||
"cooking",
|
||||
"jeweling",
|
||||
"scribing",
|
||||
"tailoring",
|
||||
"weaponsmithing",
|
||||
"woodworking"
|
||||
],
|
||||
"gathering": [
|
||||
"mining",
|
||||
"fishing",
|
||||
"farming",
|
||||
"woodcutting"
|
||||
]
|
||||
},
|
||||
"tier": {
|
||||
"items": [
|
||||
"common",
|
||||
"fabled",
|
||||
"legendary",
|
||||
"mythic",
|
||||
"rare",
|
||||
"set",
|
||||
"unique"
|
||||
],
|
||||
"ingredients": [
|
||||
0,
|
||||
1,
|
||||
2,
|
||||
3
|
||||
]
|
||||
},
|
||||
"levelRange": {
|
||||
"items": 110,
|
||||
"ingredients": 105
|
||||
}
|
||||
}
|
||||
}
|
114
py_script/item_wrapper.py
Normal file
|
@ -0,0 +1,114 @@
|
|||
"""
|
||||
Description: Quick item save/search with v3 item database
|
||||
API Documentation: https://documentation.wynncraft.com/docs/
|
||||
Update item db: python item_wrapper.py update-item [file_directory]
|
||||
Item search: python item_wrapper.py search -keyword [War] -itemType [mythic] ...
|
||||
"""
|
||||
|
||||
import requests
|
||||
import json
|
||||
import argparse
|
||||
|
||||
|
||||
class Items:
|
||||
"""v3 item wrapping - Synchronous"""
|
||||
|
||||
def fetch(self, url):
|
||||
response = requests.get(url)
|
||||
return response.json()
|
||||
|
||||
def post(self, url, data=None):
|
||||
response = requests.post(url, json=data)
|
||||
return response.json()
|
||||
|
||||
def get_all_items(self):
|
||||
api_url = "https://api.wynncraft.com/v3/item/database?fullResult=True"
|
||||
return self.fetch(api_url)
|
||||
|
||||
def get_metadata(self):
|
||||
url = "https://api.wynncraft.com/v3/item/metadata"
|
||||
return self.fetch(url)
|
||||
|
||||
def item_query(self, data=None):
|
||||
api_url = "https://api.wynncraft.com/v3/item/search?fullResult=True"
|
||||
return self.post(api_url, data)
|
||||
|
||||
|
||||
def update_items(file_path):
|
||||
data = Items().get_all_items()
|
||||
update_file(data, file_path)
|
||||
print(f"{len(data)} items updated")
|
||||
|
||||
|
||||
def update_metadata(file_path):
|
||||
data = Items().get_metadata()
|
||||
update_file(data, file_path)
|
||||
print("Metadata updated")
|
||||
|
||||
|
||||
def update_file(input, output):
|
||||
try:
|
||||
with open(output, "w") as file:
|
||||
json.dump(input, file, indent=3)
|
||||
except Exception as error:
|
||||
print(f"File update error: {error}")
|
||||
|
||||
|
||||
def item_search_param(keyword=None, itemType=None, itemTier=None, atkSpeed=None, lvlRange=None, prof=None, ids=None, majorId=None):
|
||||
payload = {
|
||||
"query": [] if keyword is None else keyword,
|
||||
"type": [] if itemType is None else itemType,
|
||||
"tier": [] if itemTier is None else itemTier,
|
||||
"attackSpeed": [] if atkSpeed is None else atkSpeed,
|
||||
"levelRange": [] if lvlRange is None else lvlRange,
|
||||
"professions": [] if prof is None else prof,
|
||||
"identifications": [] if ids is None else ids,
|
||||
"majorIds": [] if majorId is None else majorId
|
||||
}
|
||||
try:
|
||||
response = Items().item_query(payload)
|
||||
print(json.dumps(response, indent=3))
|
||||
# Save the response as needed
|
||||
|
||||
except requests.RequestException as error:
|
||||
print(f"Request error: {error}")
|
||||
|
||||
|
||||
def main():
|
||||
parser = argparse.ArgumentParser(description='Wynncraft Item API Script')
|
||||
subparsers = parser.add_subparsers(dest='command', help='Pick your poison')
|
||||
update_items_parser = subparsers.add_parser('update-items', help='Update all items')
|
||||
update_items_parser.add_argument('file', help='File path for saving item json')
|
||||
update_metadata_parser = subparsers.add_parser('update-metadata', help='Update metadata')
|
||||
update_metadata_parser.add_argument('file', help='File path for saving metadata json')
|
||||
|
||||
search_parser = subparsers.add_parser('search', help='Search for items with parameters')
|
||||
search_parser.add_argument('-keyword', type=str, default=None, help='Keyword for item search')
|
||||
search_parser.add_argument('-itemType', type=str, default=None, help='Item type: wand, bow, etc')
|
||||
search_parser.add_argument('-itemTier', type=str, default=None, help='Item tier: mythic, legendary, etc')
|
||||
search_parser.add_argument('-atkSpeed', type=str, default=None, help='Attack speed param')
|
||||
search_parser.add_argument('-lvlRange', nargs=2, type=int, default=None, help='Level range for: min, max')
|
||||
search_parser.add_argument('-prof', type=str, default=None, help='Professions (Ing)')
|
||||
search_parser.add_argument('-ids', type=str, default=None, help='Identifications field')
|
||||
search_parser.add_argument('-majorId', type=str, default=None, help='Major IDs')
|
||||
|
||||
args = parser.parse_args()
|
||||
|
||||
if args.command == 'update-items':
|
||||
update_items(args.file)
|
||||
elif args.command == 'update-metadata':
|
||||
update_metadata(args.file)
|
||||
elif args.command == 'search':
|
||||
item_search_param(
|
||||
keyword=args.keyword,
|
||||
itemType=args.itemType,
|
||||
itemTier=args.itemTier,
|
||||
atkSpeed=args.atkSpeed,
|
||||
lvlRange=args.lvlRange,
|
||||
prof=args.prof,
|
||||
ids=args.ids,
|
||||
majorId=args.majorId
|
||||
)
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
|
@ -1,140 +1,6 @@
|
|||
translate_mappings = {
|
||||
#"name": "name",
|
||||
#"displayName": "displayName",
|
||||
#"tier": "tier",
|
||||
#"set": "set",
|
||||
"sockets": "slots",
|
||||
#"type": "type",
|
||||
#"armorType": "armorType", (deleted)
|
||||
"armorColor": "color", #(deleted)
|
||||
"addedLore": "lore", #(deleted)
|
||||
#"material": "material", (deleted)
|
||||
"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",
|
||||
#"bonusFireDamage": "fDamPct",
|
||||
#"bonusWaterDamage": "wDamPct",
|
||||
#"bonusAirDamage": "aDamPct",
|
||||
#"bonusThunderDamage": "tDamPct",
|
||||
#"bonusEarthDamage": "eDamPct",
|
||||
"fireDamageBonus": "fDamPct",
|
||||
"waterDamageBonus": "wDamPct",
|
||||
"airDamageBonus": "aDamPct",
|
||||
"thunderDamageBonus": "tDamPct",
|
||||
"earthDamageBonus": "eDamPct",
|
||||
"elementalDamageBonus": "rDamPct",
|
||||
"fireDamageBonusRaw": "fDamRaw",
|
||||
"waterDamageBonusRaw": "wDamRaw",
|
||||
"airDamageBonusRaw": "aDamRaw",
|
||||
"thunderDamageBonusRaw": "tDamRaw",
|
||||
"earthDamageBonusRaw": "eDamRaw",
|
||||
"elementalDamageBonusRaw": "rDamRaw",
|
||||
"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",
|
||||
|
||||
"healingEfficiency": "healPct",
|
||||
"knockback": "kb",
|
||||
"weakenEnemy": "weakenEnemy",
|
||||
"slowEnemy": "slowEnemy",
|
||||
"elementalDefense": "rDefPct",
|
||||
}
|
||||
import json
|
||||
with open("translate_mappings.json", 'r') as infile:
|
||||
translate_mappings = json.load(infile)
|
||||
|
||||
delete_keys = [
|
||||
#"addedLore",
|
||||
|
@ -143,3 +9,36 @@ delete_keys = [
|
|||
#"armorColor",
|
||||
#"material"
|
||||
]
|
||||
|
||||
if __name__ == "__main__":
|
||||
# SELF TEST: compare dict keys with `item_metadata.json`.
|
||||
from item_wrapper import Items
|
||||
local_metadata_file = "item_metadata.json"
|
||||
|
||||
def debug(*args, **kwargs):
|
||||
print(*args, **kwargs)
|
||||
|
||||
try:
|
||||
debug("updating item metadata...")
|
||||
metadata_check = Items().get_metadata()
|
||||
with open(local_metadata_file, 'w') as outfile:
|
||||
json.dump(metadata_check, outfile, indent=2)
|
||||
except:
|
||||
debug("Could not update item metadata. using local wynn metadata")
|
||||
with open(local_metadata_file, 'r') as infile:
|
||||
metadata_check = json.load(infile)
|
||||
|
||||
checklist = set(x for x in translate_mappings.keys())
|
||||
debug(f"Checking {len(checklist)} identifications")
|
||||
n = 0
|
||||
for identification in metadata_check['identifications']:
|
||||
if identification in checklist:
|
||||
checklist.remove(identification)
|
||||
else:
|
||||
print(f"WARNING: id not accounted for: {identification}")
|
||||
n += 1
|
||||
debug(f"{n} unmapped API identifications.")
|
||||
|
||||
for identification in checklist:
|
||||
print(f"WARNING: unused translate map entry {identification}")
|
||||
debug(f"{len(checklist)} unused translation entries.")
|
||||
|
|
|
@ -187,7 +187,7 @@ for ing in ings:
|
|||
"notTouching": 0
|
||||
}
|
||||
if 'itemIDs' not in ing:
|
||||
ing['consumableIDs'] = {
|
||||
ing['itemIDs'] = {
|
||||
"dura": 0,
|
||||
"strReq": 0,
|
||||
"dexReq": 0,
|
||||
|
|
|
@ -15,15 +15,16 @@ import sys
|
|||
import os
|
||||
import base64
|
||||
import argparse
|
||||
from items_common import translate_mappings, delete_keys
|
||||
#from items_common import translate_mappings, delete_keys
|
||||
|
||||
parser = argparse.ArgumentParser(description="Process raw pulled item data.")
|
||||
parser.add_argument('infile', help='input file to read data from')
|
||||
parser.add_argument('infile', help='input file to read data from', default=None, nargs='?')
|
||||
parser.add_argument('outfile', help='output file to dump clean data into')
|
||||
args = parser.parse_args()
|
||||
infile, outfile = args.infile, args.outfile
|
||||
if args.infile is None:
|
||||
print("Grabbing json data from wynn api")
|
||||
|
||||
with open(infile, "r") as in_file:
|
||||
with open(args.infile, "r") as in_file:
|
||||
data = json.loads(in_file.read())
|
||||
|
||||
|
||||
|
@ -65,8 +66,9 @@ for item in items:
|
|||
|
||||
for k, v in translate_mappings.items():
|
||||
if k in item:
|
||||
item[v] = item[k]
|
||||
tmp = item[k]
|
||||
del item[k]
|
||||
item[v] = tmp
|
||||
|
||||
if not (item["name"] in id_map):
|
||||
while max_id in used_ids:
|
||||
|
|
189
py_script/translate_mappings.json
Normal file
|
@ -0,0 +1,189 @@
|
|||
{
|
||||
"ingredient": {
|
||||
"name": "displayName",
|
||||
"internalName": "name",
|
||||
"tier": "tier",
|
||||
"material": "DELETE;",
|
||||
"skin": "DELETE;",
|
||||
"itemOnlyIDs": "RECURSE_ingredient.itemIDs;itemIDs",
|
||||
"consumableOnlyIDs": "RECURSE_ingredient.consumableIDs;consumableIDs",
|
||||
"ingredientPositionModifiers": "RECURSE_ingredient.posMods;posMods",
|
||||
"identifications": "RECURSE_identifications;ids",
|
||||
"droppedBy": "DELETE;",
|
||||
"___droppedBy_comment:": "Deleting for now because it is way too large and we cannot use it in a meaningful way. But this is nice data for when wynnatlas ever gets updated",
|
||||
"requirements": "UNWRAP;requirements"
|
||||
},
|
||||
"ingredient.itemIDs": {
|
||||
"durabilityModifier": "dura",
|
||||
"strengthRequirement": "strReq",
|
||||
"dexterityRequirement": "dexReq",
|
||||
"intelligenceRequirement": "intReq",
|
||||
"defenceRequirement": "defReq",
|
||||
"agilityRequirement": "agiReq",
|
||||
"attackSpeedModifier": "atkSpdMod",
|
||||
"powderSlotModifier": "slotMod"
|
||||
},
|
||||
"ingredient.consumableIDs": {
|
||||
"duration": "dura",
|
||||
"charges": "charges"
|
||||
},
|
||||
"ingredient.posMods": {
|
||||
"left": "left",
|
||||
"right": "right",
|
||||
"above": "above",
|
||||
"under": "under",
|
||||
"touching": "touching",
|
||||
"notTouching": "notTouching"
|
||||
},
|
||||
"item": {
|
||||
"name": "displayName",
|
||||
"internalName": "name",
|
||||
"tier": "CAPS;tier",
|
||||
"set": "set",
|
||||
"powderSlots": "slots",
|
||||
"type": "type",
|
||||
"armorType": "armorType",
|
||||
"material": "material",
|
||||
"dropRestriction": "drop",
|
||||
"dropMeta": "dropInfo",
|
||||
"quest": "quest",
|
||||
"restrictions": "restrict",
|
||||
"accessoryType": "type",
|
||||
"identified": "fixID",
|
||||
"skin": "skin",
|
||||
"category": "category",
|
||||
"attackSpeed": "ALLCAPS;atkSpd",
|
||||
"base": "UNWRAP;item.base",
|
||||
"requirements": "UNWRAP;requirements",
|
||||
"identifications": "UNWRAP;identifications"
|
||||
},
|
||||
"item.base": {
|
||||
"damage": "STR_RANGE;nDam",
|
||||
"fireDamage": "STR_RANGE;fDam",
|
||||
"waterDamage": "STR_RANGE;wDam",
|
||||
"airDamage": "STR_RANGE;aDam",
|
||||
"thunderDamage": "STR_RANGE;tDam",
|
||||
"earthDamage": "STR_RANGE;eDam",
|
||||
"health": "hp",
|
||||
"fireDefence": "fDef",
|
||||
"waterDefence": "wDef",
|
||||
"airDefence": "aDef",
|
||||
"thunderDefence": "tDef",
|
||||
"earthDefence": "eDef",
|
||||
"averageDPS": "DELETE;"
|
||||
},
|
||||
"requirements": {
|
||||
"level": "lvl",
|
||||
"levelRange": "lvRange",
|
||||
"classRequirement": "classReq",
|
||||
"strength": "strReq",
|
||||
"dexterity": "dexReq",
|
||||
"intelligence": "intReq",
|
||||
"agility": "agiReq",
|
||||
"defence": "defReq"
|
||||
},
|
||||
"identifications": {
|
||||
"healthRegen": "hprPct",
|
||||
"manaRegen": "mr",
|
||||
"spellDamage": "sdPct",
|
||||
"elementalSpellDamage": "rSdPct",
|
||||
"neutralSpellDamage": "nSdPct",
|
||||
"fireSpellDamage": "fSdPct",
|
||||
"waterSpellDamage": "wSdPct",
|
||||
"airSpellDamage": "aSdPct",
|
||||
"thunderSpellDamage": "tSdPct",
|
||||
"earthSpellDamage": "eSdPct",
|
||||
"mainAttackDamage": "mdPct",
|
||||
"elementalMainAttackDamage": "rMdPct",
|
||||
"neutralMainAttackDamage": "nMdPct",
|
||||
"fireMainAttackDamage": "fMdPct",
|
||||
"waterMainAttackDamage": "wMdPct",
|
||||
"airMainAttackDamage": "aMdPct",
|
||||
"thunderMainAttackDamage": "tMdPct",
|
||||
"earthMainAttackDamage": "eMdPct",
|
||||
"lifeSteal": "ls",
|
||||
"manaSteal": "ms",
|
||||
"xpBonus": "xpb",
|
||||
"lootBonus": "lb",
|
||||
"leveledXpBonus": "lxpb",
|
||||
"leveledLootBonus": "llb",
|
||||
"reflection": "ref",
|
||||
"rawStrength": "str",
|
||||
"rawDexterity": "dex",
|
||||
"rawIntelligence": "int",
|
||||
"rawDefence": "def",
|
||||
"rawAgility": "agi",
|
||||
"thorns": "thorns",
|
||||
"poison": "poison",
|
||||
"exploding": "expd",
|
||||
"walkSpeed": "spd",
|
||||
"rawAttackSpeed": "atkTier",
|
||||
"rawHealth": "hpBonus",
|
||||
"soulPointRegen": "spRegen",
|
||||
"stealing": "eSteal",
|
||||
"healthRegenRaw": "hprRaw",
|
||||
"rawSpellDamage": "sdRaw",
|
||||
"rawElementalSpellDamage": "rSdRaw",
|
||||
"rawNeutralSpellDamage": "nSdRaw",
|
||||
"rawFireSpellDamage": "fSdRaw",
|
||||
"rawWaterSpellDamage": "wSdRaw",
|
||||
"rawAirSpellDamage": "aSdRaw",
|
||||
"rawThunderSpellDamage": "tSdRaw",
|
||||
"rawEarthSpellDamage": "eSdRaw",
|
||||
"rawMainAttackDamage": "mdRaw",
|
||||
"rawElementalMainAttackDamage": "rMdRaw",
|
||||
"rawNeutralMainAttackDamage": "nMdRaw",
|
||||
"rawFireMainAttackDamage": "fMdRaw",
|
||||
"rawWaterMainAttackDamage": "wMdRaw",
|
||||
"rawAirMainAttackDamage": "aMdRaw",
|
||||
"rawThunderMainAttackDamage": "tMdRaw",
|
||||
"rawEarthMainAttackDamage": "eMdRaw",
|
||||
"damage": "damPct",
|
||||
"neutralDamage": "nDamPct",
|
||||
"fireDamage": "fDamPct",
|
||||
"waterDamage": "wDamPct",
|
||||
"airDamage": "aDamPct",
|
||||
"thunderDamage": "tDamPct",
|
||||
"earthDamage": "eDamPct",
|
||||
"elementalDamage": "rDamPct",
|
||||
"rawDamage": "damRaw",
|
||||
"rawNeutralDamage": "nDamRaw",
|
||||
"rawFireDamage": "fDamRaw",
|
||||
"rawWaterDamage": "wDamRaw",
|
||||
"rawAirDamage": "aDamRaw",
|
||||
"rawThunderDamage": "tDamRaw",
|
||||
"rawEarthDamage": "eDamRaw",
|
||||
"rawElementalDamage": "rDamRaw",
|
||||
"fireDefence": "fDefPct",
|
||||
"waterDefence": "wDefPct",
|
||||
"airDefence": "aDefPct",
|
||||
"thunderDefence": "tDefPct",
|
||||
"earthDefence": "eDefPct",
|
||||
"elementalDefence": "rDefPct",
|
||||
|
||||
"1stSpellCost": "spPct1",
|
||||
"raw1stSpellCost": "spRaw1",
|
||||
"2ndSpellCost": "spPct2",
|
||||
"raw2ndSpellCost": "spRaw2",
|
||||
"3rdSpellCost": "spPct3",
|
||||
"raw3rdSpellCost": "spRaw3",
|
||||
"4thSpellCost": "spPct4",
|
||||
"raw4thSpellCost": "spRaw4",
|
||||
|
||||
"sprint": "sprint",
|
||||
"sprintRegen": "sprintReg",
|
||||
"jumpHeight": "jh",
|
||||
"lootQuality": "lq",
|
||||
|
||||
"gatherXpBonus": "gXp",
|
||||
"gatherSpeed": "gSpd",
|
||||
|
||||
"healingEfficiency": "healPct",
|
||||
"knockback": "kb",
|
||||
"weakenEnemy": "weakenEnemy",
|
||||
"slowEnemy": "slowEnemy",
|
||||
"elementalDefense": "rDefPct",
|
||||
|
||||
"damageFromMobs": "selfWeakPct"
|
||||
}
|
||||
}
|
236
py_script/v3_process_items.py
Normal file
|
@ -0,0 +1,236 @@
|
|||
"""
|
||||
Used to process the raw item data pulled from the API.
|
||||
|
||||
Usage:
|
||||
- python process_items.py [infile] [outfile]
|
||||
OR
|
||||
- python process_items.py [infile and outfile]
|
||||
|
||||
|
||||
NOTE: id_map.json is due for change. Should be updated manually when Wynn2.0/corresponding WB version drops.
|
||||
"""
|
||||
|
||||
import json
|
||||
import sys
|
||||
import os
|
||||
import base64
|
||||
import argparse
|
||||
from items_common import translate_mappings
|
||||
|
||||
parser = argparse.ArgumentParser(description="Process raw pulled item data.")
|
||||
parser.add_argument('infile', help='input file to read data from', default=None, nargs='?')
|
||||
#parser.add_argument('outfile', help='output file to dump clean data into')
|
||||
args = parser.parse_args()
|
||||
if args.infile is None:
|
||||
print("Grabbing json data from wynn api")
|
||||
from item_wrapper import Items
|
||||
api_data = Items().get_all_items()
|
||||
json.dump(api_data, open('dump.json', 'w'))
|
||||
else:
|
||||
with open(args.infile, "r") as in_file:
|
||||
api_data = json.load(in_file)
|
||||
|
||||
def translate_single_item(key, entry, name, directives, accumulate):
|
||||
ret = entry
|
||||
try:
|
||||
if 'min' in entry and 'max' in entry:
|
||||
if 'raw' in entry:
|
||||
ret = entry['raw']
|
||||
else:
|
||||
ret = [entry['min'], entry['max']]
|
||||
except:
|
||||
pass
|
||||
|
||||
i = 0
|
||||
while i < len(directives):
|
||||
directive = directives[i]
|
||||
if directive == 'DELETE':
|
||||
ret = None
|
||||
elif directive == 'CAPS':
|
||||
ret = ret[0].upper() + ret[1:]
|
||||
elif directive == 'ALLCAPS':
|
||||
ret = ret.upper()
|
||||
elif directive == 'STR_RANGE':
|
||||
if 'min' in entry and 'max' in entry:
|
||||
ret = f"{entry['min']}-{entry['max']}"
|
||||
elif directive == 'UNWRAP':
|
||||
recursive_translate(entry, accumulate, name, translate_single_item)
|
||||
ret = None
|
||||
i += 1
|
||||
return ret
|
||||
|
||||
def translate_single_ing(key, entry, name, directives, accumulate):
|
||||
ret = entry
|
||||
try:
|
||||
if 'min' in entry and 'max' in entry:
|
||||
ret = {
|
||||
'minimum': entry['min'],
|
||||
'maximum': entry['max']
|
||||
}
|
||||
except:
|
||||
pass
|
||||
|
||||
i = 0
|
||||
while i < len(directives):
|
||||
directive = directives[i]
|
||||
if directive == 'DELETE':
|
||||
ret = None
|
||||
elif directive == 'UNWRAP':
|
||||
recursive_translate(entry, accumulate, name, translate_single_ing)
|
||||
ret = None
|
||||
elif directive[:8] == 'RECURSE_':
|
||||
ret = recursive_translate(entry, {}, directive[8:], translate_single_ing)
|
||||
i += 1
|
||||
return ret
|
||||
|
||||
def recursive_translate(entry, result, path, translate_single):
|
||||
mapping = translate_mappings[path]
|
||||
|
||||
for k, v in entry.items():
|
||||
# Translate the item.
|
||||
if k in mapping:
|
||||
tmp = mapping[k].split(';')
|
||||
directives, translated_name = tmp[:-1], tmp[-1]
|
||||
res = translate_single(k, v, translated_name, directives, result)
|
||||
if res is not None:
|
||||
result[translated_name] = res
|
||||
continue
|
||||
|
||||
# pass it through unchanged.
|
||||
result[k] = v
|
||||
return result
|
||||
|
||||
armor_types = ['helmet', 'chestplate', 'leggings', 'boots']
|
||||
|
||||
def translate_entry(entry):
|
||||
"""
|
||||
Convert an api entry into an appropriate parsed item.
|
||||
|
||||
Returns a pair: (converted, type)
|
||||
where `type` is "item", "ingredient", "tome", "material", "charm", or None
|
||||
and converted might be None if the conversion failed.
|
||||
"""
|
||||
# sketchily infer what kind of item we're dealing with, and translate it appropriately.
|
||||
if "type" in entry:
|
||||
# only items have this field.
|
||||
res = recursive_translate(entry, {}, "item", translate_single_item)
|
||||
if res['type'] in armor_types:
|
||||
res['category'] = 'armor'
|
||||
else:
|
||||
res['category'] = 'weapon'
|
||||
for element in 'netwfa':
|
||||
damage_key = element + 'Dam'
|
||||
if damage_key not in res:
|
||||
res[damage_key] = '0-0'
|
||||
return res, 'item'
|
||||
if "accessoryType" in entry:
|
||||
# only accessories have this field.
|
||||
return recursive_translate(entry, {'category': 'accessory'}, "item", translate_single_item), "item"
|
||||
if "itemOnlyIDs" in entry:
|
||||
# only ingredients have this field.
|
||||
res = recursive_translate(entry, {}, "ingredient", translate_single_ing)
|
||||
return res, "ingredient"
|
||||
#return recursive_translate(entry, {}, "ing"), "ingredient"
|
||||
if "tomeType" in entry:
|
||||
# only tomes have this field.
|
||||
return None, "tome"
|
||||
if "craftable" in entry:
|
||||
return None, "material"
|
||||
|
||||
# I think the only things left are charms, we just don't classify them.
|
||||
return None, None
|
||||
|
||||
with open("id_map.json", "r") as id_map_file:
|
||||
id_map = json.load(id_map_file)
|
||||
used_ids = set([v for k, v in id_map.items()])
|
||||
max_id = 0
|
||||
with open("ing_map.json","r") as ing_map_file:
|
||||
ing_map = json.load(ing_map_file)
|
||||
|
||||
items = []
|
||||
ingreds = []
|
||||
for name, entry in api_data.items():
|
||||
entry['name'] = name
|
||||
res, entry_type = translate_entry(entry)
|
||||
print(f"Parsed {name}, type {entry_type}")
|
||||
if res is None:
|
||||
continue
|
||||
# TODO: make this a map or smth less ugly code
|
||||
if entry_type == 'item':
|
||||
items.append(res)
|
||||
elif entry_type == 'ingredient':
|
||||
ingreds.append(res)
|
||||
|
||||
with open("../clean.json", "r") as oldfile:
|
||||
old_data = json.load(oldfile)
|
||||
old_items = old_data['items']
|
||||
with open("../ingreds_clean.json", "r") as ingfile:
|
||||
old_ingreds = json.load(ingfile)
|
||||
|
||||
known_item_names = set()
|
||||
known_ingred_names = set()
|
||||
for item in items:
|
||||
known_item_names.add(item["name"])
|
||||
for ingred in ingreds:
|
||||
known_ingred_names.add(ingred["name"])
|
||||
|
||||
for item in old_items:
|
||||
if item["name"] not in known_item_names:
|
||||
print(f'Unknown old item: {item["name"]}!!!')
|
||||
for ingred in old_ingreds:
|
||||
if ingred["name"] not in known_ingred_names:
|
||||
print(f'Unknown old ingred: {ingred["name"]}!!!')
|
||||
|
||||
# TODO hack pull the major id file
|
||||
major_ids_filename = "../js/builder/major_ids_clean.json"
|
||||
with open(major_ids_filename, 'r') as major_ids_file:
|
||||
major_ids_map = json.load(major_ids_file)
|
||||
major_ids_reverse_map = { v['displayName'] : k for k, v in major_ids_map.items() }
|
||||
|
||||
for item in items:
|
||||
# HACKY ITEM FIXES!
|
||||
if 'majorIds' in item:
|
||||
item['majorIds'] = [ major_ids_reverse_map[item['majorIds']['name']] ]
|
||||
|
||||
if not (item["name"] in id_map):
|
||||
while max_id in used_ids:
|
||||
max_id += 1
|
||||
used_ids.add(max_id)
|
||||
id_map[item["name"]] = max_id
|
||||
print(f'New item: {item["name"]} (id: {max_id})')
|
||||
item["id"] = id_map[item["name"]]
|
||||
|
||||
for ingred in ingreds:
|
||||
# HACKY ING FIXES!
|
||||
ingred['itemIDs']['dura'] = int(ingred['itemIDs']['dura'] / 1000)
|
||||
ingred['skills'] = [x.upper() for x in ingred['skills']]
|
||||
if 'ids' not in ingred:
|
||||
ingred['ids'] = dict()
|
||||
print(f"ing missing 'ids': {ingred['name']}")
|
||||
if 'consumableIDs' not in ingred:
|
||||
ingred['consumableIDs'] = {'dura': 0, 'charges': 0}
|
||||
print(f"ing missing 'consumableIDs': {ingred['name']}")
|
||||
|
||||
if not (ingred["name"] in ing_map):
|
||||
new_id = len(ing_map)
|
||||
ing_map[ingred["name"]] = new_id
|
||||
print(f'New item: {item["name"]} (id: {new_id})')
|
||||
ingred["id"] = ing_map[ingred["name"]]
|
||||
|
||||
#write items back into data
|
||||
old_data["items"] = items
|
||||
|
||||
#save id map
|
||||
with open("id_map.json","w") as id_map_file:
|
||||
json.dump(id_map, id_map_file, indent=2)
|
||||
with open("ing_map.json","w") as ing_map_file:
|
||||
json.dump(ing_map, ing_map_file, indent=2)
|
||||
|
||||
|
||||
#write the data back to the outfile
|
||||
with open('item_out.json', "w+") as out_file:
|
||||
json.dump(old_data, out_file, ensure_ascii=False, separators=(',', ':'))
|
||||
|
||||
with open('ing_out.json', "w+") as out_file:
|
||||
json.dump(ingreds, out_file, ensure_ascii=False, separators=(',', ':'))
|
||||
|
27
thirdparty/katex.js
vendored
Normal file
|
@ -0,0 +1,27 @@
|
|||
function add_katex() {
|
||||
head_elem = document.getElementsByTagName("head")[0];
|
||||
|
||||
link = document.createElement('link')
|
||||
link.setAttribute('rel', 'stylesheet')
|
||||
link.setAttribute('href', "https://cdn.jsdelivr.net/npm/katex@0.16.10/dist/katex.min.css")
|
||||
link.setAttribute('integrity', "sha384-wcIxkf4k558AjM3Yz3BBFQUbk/zgIYC2R0QpeeYb+TwlBVMrlgLqwRjRtGZiK7ww")
|
||||
link.setAttribute('crossorigin', "anonymous")
|
||||
scr_1 = document.createElement('script')
|
||||
scr_1.setAttribute('src', "https://cdn.jsdelivr.net/npm/katex@0.16.10/dist/katex.min.js")
|
||||
scr_1.setAttribute('integrity', "sha384-hIoBPJpTUs74ddyc4bFZSM1TVlQDA60VBbJS0oA934VSz82sBx1X7kSx2ATBDIyd")
|
||||
scr_1.setAttribute('crossorigin', "anonymous")
|
||||
scr_1.setAttribute('defer', '')
|
||||
scr_2 = document.createElement('script')
|
||||
scr_2.setAttribute('src',"https://cdn.jsdelivr.net/npm/katex@0.16.10/dist/contrib/auto-render.min.js")
|
||||
scr_2.setAttribute('integrity', "sha384-43gviWU0YVjaDtb/GhzOouOXtZMP/7XUzwPTstBeZFe/+rCMvRwr4yROQP43s0Xk")
|
||||
scr_2.setAttribute('crossorigin', "anonymous")
|
||||
scr_2.setAttribute('defer', '')
|
||||
scr_2.setAttribute('onload', "renderMathInElement(document.body, {delimiters: [{left: '$$', right: '$$', display: true},{left: '$', right: '$', display: false}]});")
|
||||
|
||||
head_elem.append(link, scr_1, scr_2);
|
||||
}
|
||||
|
||||
|
||||
add_katex();
|
||||
|
||||
|
53
wynnfo/damage_calc/index.html
Normal file
|
@ -0,0 +1,53 @@
|
|||
<!DOCTYPE html>
|
||||
<html scroll-behavior="smooth">
|
||||
<head>
|
||||
<title>WynnAtlas Help</title>
|
||||
<link rel="icon" href="/media/icons/new/searcher.png">
|
||||
<link rel="manifest" href="manifest.json">
|
||||
|
||||
<meta name="viewport" content="width=device-width, initial-scale=.45, user-scalable=no">
|
||||
|
||||
<!-- nunito font, copying wynnbuilder, which is copying wynndata -->
|
||||
<link rel="preconnect" href="https://fonts.googleapis.com">
|
||||
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
|
||||
<link href="https://fonts.googleapis.com/css2?family=Nunito&display=swap" rel="stylesheet">
|
||||
|
||||
<link href="https://fonts.googleapis.com/css2?family=Nunito&display=swap" rel="stylesheet">
|
||||
<link href="/thirdparty/bootstrap.min.css" rel="stylesheet" integrity="sha384-1BmE4kWBq78iYhFldvKuhfTAU6auU8tT94WrHftjDbrCEXSU1oBoqyl2QvZ6jIW3" crossorigin="anonymous">
|
||||
|
||||
<link rel="stylesheet" href="/thirdparty/autoComplete.min.css">
|
||||
|
||||
|
||||
<link rel="stylesheet" href="/css/article.css"> <!-- This one is the important one for docs -->
|
||||
<link rel="stylesheet" href="/css/docs_home.css">
|
||||
<link rel="stylesheet" href="/css/styles.css">
|
||||
<link rel="stylesheet" href="/css/sidebar.css">
|
||||
<link rel="stylesheet" href="/css/wynnstyles.css">
|
||||
|
||||
<script type="text/javascript" src="/thirdparty/katex.js"></script>
|
||||
|
||||
</head>
|
||||
<body class="all" style="overflow-y: scroll">
|
||||
<div id="main-sidebar" class="sidebar dark-7 dark-shadow">
|
||||
<a href = "/builder/"><img src="/media/icons/new/builder.png" alt = "WynnBuilder" title = "WynnBuilder"><b>WynnBuilder</b></a>
|
||||
<a href = "/crafter/"><img src = "/media/icons/new/crafter.png" alt = "WynnCrafter" title = "WynnCrafter"><b>WynnCrafter</b></a>
|
||||
<a href = "/items/"><img src = "/media/icons/new/searcher.png" alt = "WynnAtlas" title = "WynnAtlas"><b>WynnAtlas</b></a>
|
||||
<a href = "/custom/"><img src = "/media/icons/new/custom.png" alt = "WynnCustom" title = "WynnCustom"><b>WynnCustom</b></a>
|
||||
<a href = "/map/"><img src = "/media/icons/new/compass.png" alt = "WynnGPS" title = "WynnGPS"><b>WynnGPS</b></a>
|
||||
<a href = "/wynnfo/"><img src = "/media/icons/new/book.png" alt = "Wynnfo" title = "Wynnfo"><b>Wynnfo</b></a>
|
||||
<a onclick = "toggleIcons()"><img src = "/media/icons/new/reload.png" alt = "" title = "Swap items on page"><b>Swap Icon Style</b></a>
|
||||
<hr/>
|
||||
<a href = "https://discord.gg/CGavnAnerv" target = "_blank"><img src = "/media/icons/discord.png" alt = "WB Discord" title = "WB Discord"><b>WB Discord</b></a>
|
||||
</div>
|
||||
<main>
|
||||
<div class="full-width text-center">
|
||||
<!-- <img src="./help_photo.png"/> -->
|
||||
</div>
|
||||
<div class="section">
|
||||
<h2>Lorem Ipsum</h2>
|
||||
<p>Hopefully this gets replced by a guide to Wynn 2.1 damage calculation</p>
|
||||
</div>
|
||||
</main>
|
||||
<script type="text/javascript" src="/js/icons.js"></script>
|
||||
</body>
|
||||
</html>
|
|
@ -1,85 +1,58 @@
|
|||
<!DOCTYPE html>
|
||||
<html scroll-behavior="smooth">
|
||||
<head>
|
||||
<title>WynnAtlas</title>
|
||||
<link rel="icon" href="../media/icons/new/searcher.png" type="image/icon type">
|
||||
|
||||
<title>WynnDocs</title>
|
||||
<link rel="icon" href="/media/icons/new/searcher.png">
|
||||
<link rel="manifest" href="manifest.json">
|
||||
|
||||
<meta name="viewport" content="width=device-width, initial-scale=.45, user-scalable=no">
|
||||
|
||||
<!-- nunito font, copying wynnbuilder, which is copying wynndata -->
|
||||
<link rel="preconnect" href="https://fonts.googleapis.com">
|
||||
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
|
||||
<link href="https://fonts.googleapis.com/css2?family=Nunito&display=swap" rel="stylesheet">
|
||||
|
||||
<link href="https://fonts.googleapis.com/css2?family=Nunito&display=swap" rel="stylesheet">
|
||||
<link href="/thirdparty/bootstrap.min.css" rel="stylesheet" integrity="sha384-1BmE4kWBq78iYhFldvKuhfTAU6auU8tT94WrHftjDbrCEXSU1oBoqyl2QvZ6jIW3" crossorigin="anonymous">
|
||||
|
||||
<link rel="stylesheet" href="/thirdparty/autoComplete.min.css">
|
||||
|
||||
|
||||
<link rel="stylesheet" href="../css/sq2bs.css">
|
||||
<link rel="stylesheet" href="../css/sidebar.css">
|
||||
<link rel="stylesheet" href="../css/wynnstyles.css">
|
||||
<link rel="stylesheet" href="/css/article.css"> <!-- This one is the important one for docs -->
|
||||
<link rel="stylesheet" href="/css/docs_home.css">
|
||||
<link rel="stylesheet" href="/css/styles.css">
|
||||
<link rel="stylesheet" href="/css/sidebar.css">
|
||||
<link rel="stylesheet" href="/css/wynnstyles.css">
|
||||
|
||||
<script text = "text/javascript" src = "/js/docs.js"></script>
|
||||
<script text = "text/javascript">document.addEventListener("DOMContentLoaded", (event) => {populate_post_previews();})</script>
|
||||
</head>
|
||||
<body class = "text-light d-flex justify-content-center" id = "body">
|
||||
<div id="main-sidebar" class="sidebar dark-7 dark-shadow">
|
||||
<a href = "../builder/"><img src="../media/icons/new/builder.png" alt = "WynnBuilder" title = "WynnBuilder"><b>WynnBuilder</b></a>
|
||||
<a href = "../crafter/"><img src = "../media/icons/new/crafter.png" alt = "WynnCrafter" title = "WynnCrafter"><b>WynnCrafter</b></a>
|
||||
<a href = "../items/"><img src = "../media/icons/new/searcher.png" alt = "WynnAtlas" title = "WynnAtlas"><b>WynnAtlas</b></a>
|
||||
<a href = "../custom/"><img src = "../media/icons/new/custom.png" alt = "WynnCustom" title = "WynnCustom"><b>WynnCustom</b></a>
|
||||
<a href = "../map/"><img src = "../media/icons/new/compass.png" alt = "WynnGPS" title = "WynnGPS"><b>WynnGPS</b></a>
|
||||
<a href = ""><img src = "../media/icons/new/book.png" alt = "Wynnfo" title = "Wynnfo"><b>Wynnfo</b></a>
|
||||
<a onclick = "toggleIcons()"><img src = "../media/icons/new/reload.png" alt = "" title = "Swap items on page"><b>Swap Icon Style</b></a>
|
||||
<hr/>
|
||||
<a href = "https://discord.gg/CGavnAnerv" target = "_blank"><img src = "../media/icons/discord.png" alt = "WB Discord" title = "WB Discord"><b>WB Discord</b></a>
|
||||
<body class="all" style="overflow-y: scroll">
|
||||
<div id="main-sidebar" class="sidebar dark-7 dark-shadow">
|
||||
<a href = "/builder/"><img src="/media/icons/new/builder.png" alt = "WynnBuilder" title = "WynnBuilder"><b>WynnBuilder</b></a>
|
||||
<a href = "/crafter/"><img src = "/media/icons/new/crafter.png" alt = "WynnCrafter" title = "WynnCrafter"><b>WynnCrafter</b></a>
|
||||
<a href = "/items/"><img src = "/media/icons/new/searcher.png" alt = "WynnAtlas" title = "WynnAtlas"><b>WynnAtlas</b></a>
|
||||
<a href = "/custom/"><img src = "/media/icons/new/custom.png" alt = "WynnCustom" title = "WynnCustom"><b>WynnCustom</b></a>
|
||||
<a href = "/map/"><img src = "/media/icons/new/compass.png" alt = "WynnGPS" title = "WynnGPS"><b>WynnGPS</b></a>
|
||||
<a href = "."><img src = "/media/icons/new/book.png" alt = "Wynnfo" title = "Wynnfo"><b>Wynnfo</b></a>
|
||||
<a onclick = "toggleIcons()"><img src = "/media/icons/new/reload.png" alt = "" title = "Swap items on page"><b>Swap Icon Style</b></a>
|
||||
<hr/>
|
||||
<a href = "https://discord.gg/CGavnAnerv" target = "_blank"><img src = "/media/icons/discord.png" alt = "WB Discord" title = "WB Discord"><b>WB Discord</b></a>
|
||||
</div>
|
||||
<main>
|
||||
<div class="full-width text-center">
|
||||
<img src="/media/items/new.png"/>
|
||||
</div>
|
||||
<div id="mobile-navbar" class="navbar dark-5 dark-shadow fixed-top d-lg-none pb-0">
|
||||
<div class="container-fluid scaled-font justify-content-center" style="height: 5vh;">
|
||||
<div class="navbar-brand mx-auto scaled-font" style="height: 100%;">
|
||||
<img src="../media/icons/new/book.png" alt="" style="height: 100%;">
|
||||
<span>WynnFo</span>
|
||||
</div>
|
||||
<button class="btn dropdown-toggle dark-2 px-4 text-white scaled-font border-dark border-3" onclick="toggle_tab('mobile-navbar-dropdown');"></button>
|
||||
</div>
|
||||
<div class="container-fluid scaled-font dark-3 px-3 py-3" id="mobile-navbar-dropdown" style="display: none;">
|
||||
<a href="../builder/" class="w-100 mb-3 text-white" style="height: 5vh; text-decoration: none;">
|
||||
<img src="../media/icons/new/builder.png" alt="" style="height: 100%;">
|
||||
<span>WynnBuilder</span>
|
||||
</a>
|
||||
<a href="../crafter/" class="w-100 mb-3 text-white" style="height: 5vh; text-decoration: none;">
|
||||
<img src="../media/icons/new/crafter.png" alt="" style="height: 100%;">
|
||||
<span>WynnCrafter</span>
|
||||
</a>
|
||||
<a href="../items/" class="w-100 mb-3 text-white" style="height: 5vh; text-decoration: none;">
|
||||
<img src="../media/icons/new/searcher.png" alt="" style="height: 100%;">
|
||||
<span>WynnAtlas</span>
|
||||
</a>
|
||||
<a href="../custom/" class="w-100 mb-3 text-white" style="height: 5vh; text-decoration: none;">
|
||||
<img src="../media/icons/new/custom.png" alt="" style="height: 100%;">
|
||||
<span>WynnCustom</span>
|
||||
</a>
|
||||
<a href="../map/" class="w-100 mb-3 text-white" style="height: 5vh; text-decoration: none;">
|
||||
<img src="../media/icons/new/compass.png" alt="" style="height: 100%;">
|
||||
<span>WynnGPS</span>
|
||||
</a>
|
||||
<a href="../wynnfo/" class="w-100 mb-3 text-white" style="height: 5vh; text-decoration: none;">
|
||||
<img src="../media/icons/new/book.png" alt="" style="height: 100%;">
|
||||
<span>WynnFo</span>
|
||||
</a>
|
||||
<a onclick = "toggleIcons()" class="w-100 mb-3 text-white" style="height: 5vh; text-decoration: none;">
|
||||
<img src="../media/icons/new/reload.png" alt="" style="height: 100%;">
|
||||
<span>Swap Icon Style</span>
|
||||
</a>
|
||||
<a href="https://discord.gg/CGavnAnerv" class="w-100 mb-3 text-white" style="height: 5vh; text-decoration: none;">
|
||||
<img src="../media/icons/discord.png" alt="" style="height: 100%;">
|
||||
<span>Discord</span>
|
||||
</a>
|
||||
</div>
|
||||
<div class="section">
|
||||
<h2>Welcome to the WynnBuilder Docs</h2>
|
||||
<p>Documentation Homepage - sections coming soon!</p>
|
||||
</div>
|
||||
<div class = "container py-5 vh-100 mx-0 mx-lg-auto scaled-font mt-lg-2" id = "main" style="margin-top: 6vh;">
|
||||
<div class = "row item-title">Welcome!</div>
|
||||
<p class = "row">This page is the main page for Wynnfo. Wynnfo is Wynnbuilder's page for all sorts of Wynncraft-related literature, including code documenation, game mechanic novels, and other literature! Browse at your leisure below.</p>
|
||||
|
||||
<!-- Gets populated by populate_post_previews() -->
|
||||
<div class ="section" id = "post-list">
|
||||
|
||||
</div>
|
||||
<script type="text/javascript" src = "scripts/main.js"></script>
|
||||
<script type="text/javascript" src = "../js/utils.js"></script>
|
||||
<script type="text/javascript" src = "../js/icons.js"></script>
|
||||
</body>
|
||||
</main>
|
||||
<script type="text/javascript" src="/js/icons.js"></script>
|
||||
</body>
|
||||
</html>
|
||||
|
|
Before Width: | Height: | Size: 65 KiB After Width: | Height: | Size: 65 KiB |
|
@ -2,7 +2,7 @@
|
|||
<html scroll-behavior="smooth">
|
||||
<head>
|
||||
<title>WynnAtlas Help</title>
|
||||
<link rel="icon" href="../media/icons/new/searcher.png">
|
||||
<link rel="icon" href="/media/icons/new/searcher.png">
|
||||
<link rel="manifest" href="manifest.json">
|
||||
|
||||
<meta name="viewport" content="width=device-width, initial-scale=.45, user-scalable=no">
|
||||
|
@ -18,28 +18,31 @@
|
|||
<link rel="stylesheet" href="/thirdparty/autoComplete.min.css">
|
||||
|
||||
|
||||
<link rel="stylesheet" href="../css/article.css">
|
||||
<link rel="stylesheet" href="../css/styles.css">
|
||||
<link rel="stylesheet" href="../css/sidebar.css">
|
||||
<link rel="stylesheet" href="../css/wynnstyles.css">
|
||||
<link rel="stylesheet" href="/css/article.css"> <!-- This one is the important one for docs -->
|
||||
<link rel="stylesheet" href="/css/styles.css">
|
||||
<link rel="stylesheet" href="/css/sidebar.css">
|
||||
<link rel="stylesheet" href="/css/wynnstyles.css">
|
||||
|
||||
</head>
|
||||
<body class="all" style="overflow-y: scroll">
|
||||
<div id="main-sidebar" class="sidebar dark-7 dark-shadow">
|
||||
<a href = "../builder/"><img src="../media/icons/new/builder.png" alt = "WynnBuilder" title = "WynnBuilder"><b>WynnBuilder</b></a>
|
||||
<a href = "../crafter/"><img src = "../media/icons/new/crafter.png" alt = "WynnCrafter" title = "WynnCrafter"><b>WynnCrafter</b></a>
|
||||
<a href = "../items/"><img src = "../media/icons/new/searcher.png" alt = "WynnAtlas" title = "WynnAtlas"><b>WynnAtlas</b></a>
|
||||
<a href = "../custom/"><img src = "../media/icons/new/custom.png" alt = "WynnCustom" title = "WynnCustom"><b>WynnCustom</b></a>
|
||||
<a href = "../map/"><img src = "../media/icons/new/compass.png" alt = "WynnGPS" title = "WynnGPS"><b>WynnGPS</b></a>
|
||||
<a href = "../wynnfo/"><img src = "../media/icons/new/book.png" alt = "Wynnfo" title = "WynnCrafter"><b>WynnCrafter</b></a>
|
||||
<a onclick = "toggleIcons()"><img src = "../media/icons/new/reload.png" alt = "" title = "Swap items on page"><b>Swap Icon Style</b></a>
|
||||
<a href = "/builder/"><img src="/media/icons/new/builder.png" alt = "WynnBuilder" title = "WynnBuilder"><b>WynnBuilder</b></a>
|
||||
<a href = "/crafter/"><img src = "/media/icons/new/crafter.png" alt = "WynnCrafter" title = "WynnCrafter"><b>WynnCrafter</b></a>
|
||||
<a href = "/items/"><img src = "/media/icons/new/searcher.png" alt = "WynnAtlas" title = "WynnAtlas"><b>WynnAtlas</b></a>
|
||||
<a href = "/custom/"><img src = "/media/icons/new/custom.png" alt = "WynnCustom" title = "WynnCustom"><b>WynnCustom</b></a>
|
||||
<a href = "/map/"><img src = "/media/icons/new/compass.png" alt = "WynnGPS" title = "WynnGPS"><b>WynnGPS</b></a>
|
||||
<a href = "/wynnfo/"><img src = "/media/icons/new/book.png" alt = "Wynnfo" title = "Wynnfo"><b>Wynnfo</b></a>
|
||||
<a onclick = "toggleIcons()"><img src = "/media/icons/new/reload.png" alt = "" title = "Swap items on page"><b>Swap Icon Style</b></a>
|
||||
<hr/>
|
||||
<a href = "https://discord.gg/CGavnAnerv" target = "_blank"><img src = "../media/icons/discord.png" alt = "WB Discord" title = "WB Discord"><b>WB Discord</b></a>
|
||||
<a href = "https://discord.gg/CGavnAnerv" target = "_blank"><img src = "/media/icons/discord.png" alt = "WB Discord" title = "WB Discord"><b>WB Discord</b></a>
|
||||
</div>
|
||||
<main>
|
||||
<div class="full-width text-center">
|
||||
<img src="./help_photo.png"/>
|
||||
</div>
|
||||
|
||||
<div class="section">
|
||||
<h1>Advanced Item Search Guide</h1>
|
||||
</div>
|
||||
<div class="section">
|
||||
<h2>What the heck is “Advanced Item Search”?</h2>
|
||||
<p>The WynnBuilder team has been hard at work giving you the latest and greatest tools for optimizing your most complex Wynncraft builds. Now, we're introducing <strong class="rb-text">WynnAtlas</strong>, the new, bigger, better, smarter, powerful-er item guide! Featuring an extremely flexible expression language for filtering and sorting items, WynnAtlas' advanced item search system gives build engineers the power to select items with a high degree of granularity. Picking components for your brand-new Divzer WFA build has never been easier!</p>
|
||||
|
@ -221,6 +224,6 @@
|
|||
docsFns.append(genDocEntry(entry[0], entry[1], null, entry[2]));
|
||||
}
|
||||
</script>
|
||||
<script type="text/javascript" src="../js/icons.js"></script>
|
||||
<script type="text/javascript" src="/js/icons.js"></script>
|
||||
</body>
|
||||
</html>
|
267
wynnfo/powders/index.html
Normal file
|
@ -0,0 +1,267 @@
|
|||
<!DOCTYPE html>
|
||||
<html scroll-behavior="smooth">
|
||||
<head>
|
||||
<title>Powder Mechanics Guide</title>
|
||||
<link rel="icon" href="/media/icons/new/searcher.png">
|
||||
<link rel="manifest" href="manifest.json">
|
||||
|
||||
<meta name="viewport" content="width=device-width, initial-scale=.45, user-scalable=no">
|
||||
|
||||
<!-- nunito font, copying wynnbuilder, which is copying wynndata -->
|
||||
<link rel="preconnect" href="https://fonts.googleapis.com">
|
||||
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
|
||||
<link href="https://fonts.googleapis.com/css2?family=Nunito&display=swap" rel="stylesheet">
|
||||
|
||||
<link href="https://fonts.googleapis.com/css2?family=Nunito&display=swap" rel="stylesheet">
|
||||
<link href="/thirdparty/bootstrap.min.css" rel="stylesheet" integrity="sha384-1BmE4kWBq78iYhFldvKuhfTAU6auU8tT94WrHftjDbrCEXSU1oBoqyl2QvZ6jIW3" crossorigin="anonymous">
|
||||
|
||||
<link rel="stylesheet" href="/thirdparty/autoComplete.min.css">
|
||||
|
||||
|
||||
<link rel="stylesheet" href="/css/article.css"> <!-- This one is the important one for docs -->
|
||||
<link rel="stylesheet" href="/css/docs_home.css">
|
||||
<link rel="stylesheet" href="/css/styles.css">
|
||||
<link rel="stylesheet" href="/css/sidebar.css">
|
||||
<link rel="stylesheet" href="/css/wynnstyles.css">
|
||||
|
||||
<script type="text/javascript" src="/js/docs.js"></script>
|
||||
<script text = "text/javascript">document.addEventListener("DOMContentLoaded", (event) => {initDropdownSections();})</script>
|
||||
</head>
|
||||
<body class="all" style="overflow-y: scroll">
|
||||
<div id="main-sidebar" class="sidebar dark-7 dark-shadow">
|
||||
<a href = "/builder/"><img src="/media/icons/new/builder.png" alt = "WynnBuilder" title = "WynnBuilder"><b>WynnBuilder</b></a>
|
||||
<a href = "/crafter/"><img src = "/media/icons/new/crafter.png" alt = "WynnCrafter" title = "WynnCrafter"><b>WynnCrafter</b></a>
|
||||
<a href = "/items/"><img src = "/media/icons/new/searcher.png" alt = "WynnAtlas" title = "WynnAtlas"><b>WynnAtlas</b></a>
|
||||
<a href = "/custom/"><img src = "/media/icons/new/custom.png" alt = "WynnCustom" title = "WynnCustom"><b>WynnCustom</b></a>
|
||||
<a href = "/map/"><img src = "/media/icons/new/compass.png" alt = "WynnGPS" title = "WynnGPS"><b>WynnGPS</b></a>
|
||||
<a href = "/wynnfo/"><img src = "/media/icons/new/book.png" alt = "Wynnfo" title = "Wynnfo"><b>Wynnfo</b></a>
|
||||
<a onclick = "toggleIcons()"><img src = "/media/icons/new/reload.png" alt = "" title = "Swap items on page"><b>Swap Icon Style</b></a>
|
||||
<hr/>
|
||||
<a href = "https://discord.gg/CGavnAnerv" target = "_blank"><img src = "/media/icons/discord.png" alt = "WB Discord" title = "WB Discord"><b>WB Discord</b></a>
|
||||
</div>
|
||||
<main>
|
||||
<div class="full-width text-center">
|
||||
<!-- <img src="./help_photo.png"/> -->
|
||||
</div>
|
||||
<div class="section">
|
||||
<h1>Powder Application Guide</h1>
|
||||
<p>June 5, 2024 (Wynn 2.0)</p>
|
||||
<p>Authors: ferricles, hppeng</p>
|
||||
</div>
|
||||
|
||||
<div class="section">
|
||||
<h2>Basics</h2>
|
||||
<p>I assume you know what powders do - you apply them on armor to get elemental defense or on weapons to get extra damage. If you apply multiple high-tier powders of the same type, you get an extra ability on your weapon (powder special). In this post, we'll go over the calculations that get run when powders are applied on weapons.</p>
|
||||
<p>
|
||||
Here's some terminology that we'll use later:
|
||||
<li>Base damage range: the low and high damage ranges which are shown in the item display. </li>
|
||||
<li>Damage type: There are 6 types of damage. There is neutral damage (<buf class = 'Neutral'>N</buf>) and 5 elemental types: earth (<buf class = 'Earth'>E</buf>), thunder (<buf class = 'Thunder'>T</buf>), water (<buf class = 'Water'>W</buf>), fire (<buf class = 'Fire'>F</buf>), and air (<buf class = 'Air'>A</buf>). </li>
|
||||
<li>Conversion (<code>powder.conversion</code>): The percentage conversion rate of a powder from neutral to elemental damage.</li>
|
||||
<li>Powder raw (<code>powder.raw</code>): The raw boost to the base damage range of an element given by a powder.</li>
|
||||
</p>
|
||||
<p>Before we get into calculations, one last thing - there are two types of weapons we can powder: non-crafted (regular) and crafted. There are also two corresponding types of powder application which have their own mechanics: applied powders, when a powder master puts powders on your items, and ingredient powders, when you use a powder in the recipe to make a crafted item. We will start with the more common weapon type: regular weapons.</p>
|
||||
</div>
|
||||
|
||||
<div class="section">
|
||||
<h2>Powder Application on Regular Weapons</h2>
|
||||
<p>On regular weapons, only the applied powder mechanic is relevant. The algorithm for this mechanic can be broken down into two steps: the aggregation step and the application step.</p>
|
||||
<p>
|
||||
Loop one (aggregation step):
|
||||
<li>Record the order of powders in order of <b>first powder for each type</b>.</li>
|
||||
<li>Aggregate conversion stats for each element additively.</li>
|
||||
</p>
|
||||
<p>
|
||||
Loop two (application step):
|
||||
<li>In the order of elemental types determined in loop one, calculate powder conversion of <b>remaining neutral damage</b>.</li>
|
||||
<li>Neutral damage range is decreased by the total conversion range</li>
|
||||
<li>Elemental damage range is increased by the total conversion range</li>
|
||||
<li>Elemental damage range is also increased by the powder range</li>
|
||||
<li>At the end of all applications, the damage ranges are floored for display on the weapon. (Note: these values are not floored when performing damage calculations later)</li>
|
||||
</p>
|
||||
<p>In pseudocode, this process looks like:</p>
|
||||
<pre>
|
||||
powders = [] //populated with powders which have a type, a conversion rate, and a range
|
||||
order = []
|
||||
conversions = {type: {raw: [low, high], conversion: float }}
|
||||
|
||||
for powder in powders:
|
||||
If powder.type not in order:
|
||||
order += powder.type
|
||||
conversions[powder.type][raw] += powder.raw
|
||||
conversions[powder.type][conversion] += powder.conversion
|
||||
|
||||
for powder_type in order:
|
||||
powder_conversion = conversions[powder_type]
|
||||
neu_conversion = (powder_conversion.conversion * weapon_neu_range)
|
||||
weapon_neu_range -= neu_conversion
|
||||
weapon_elem_range += neu_conversion + powder_conversion.range //the appropriate elemental type</pre>
|
||||
<p>We verified this algorithm by testing in-game. If you're interested, click on this dropdown for a worked example!</p>
|
||||
<span class="dropdown" style="font-weight:bold;"title="Regular Applied Powder Example">
|
||||
<div>
|
||||
<p>We used a <a class = "link" href = "/item/#Crystal Senbon">Crystal Senbon</a> to test. Crystal Senbon has 5 powder slots and a base damage range of <tmp class = 'Neutral'>[77, 77]</tmp>.</p>
|
||||
<p>The powders we applied, in order: [<Earth>III</Earth>, <Thunder>III</Thunder>, <Water>III</Water>, <Earth>III</Earth>, <Earth>III</Earth>]</p>
|
||||
<p>And their stats:</p>
|
||||
<li><Earth>III</Earth>: [8, 14] raw, 25% conversion </li>
|
||||
<li><Thunder>III</Thunder>: [2, 18] raw, 13% conversion </li>
|
||||
<li><Water>III</Water>: [6, 10] raw, 17% conversion </li>
|
||||
<p>We can start running the applied powder algorithm. After the aggregation step, we'd have:</p>
|
||||
<pre>
|
||||
order = [E, T, W]
|
||||
conversions: {
|
||||
E: {raw: [24, 42], conversion: 0.75},
|
||||
T: {raw: [2, 18], conversion: 0.13},
|
||||
W: {raw: [6, 10], conversion: 0.17}
|
||||
}</pre>
|
||||
<p>Then we can run through the application step.</p>
|
||||
<pre>
|
||||
Starting neutral range = <Neutral>[77, 77]</Neutral>
|
||||
|
||||
Earth conversion: [77, 77] * .75 = 57.75
|
||||
<Neutral></Neutral>= [77, 77] - [57.75, 57.75] = <Neutral>[19.25, 19.25]</Neutral>
|
||||
<Earth></Earth>= [57.75, 57.75] + [24, 42] = <Earth>[81.75, 99.75]</Earth>
|
||||
|
||||
Thunder conversion: [19.25, 19.25] * .13 = 2.5025
|
||||
<Neutral></Neutral>= [19.25, 19.25] - [2.5025, 2.5025] = <Neutral>[16.7475, 16.7475]</Neutral>
|
||||
<Thunder></Thunder>= [2.5025, 2.5025] + [2, 18] = <Thunder>[4.5025, 20.5025]</Thunder>
|
||||
|
||||
Water conversion: [16.7475, 16.7475] * 0.17 = 2.847075
|
||||
<Neutral></Neutral>= [16.7475, 16.7475] - [2.847075, 2.847075] = <Neutral>[13.900425, 13.900425]</Neutral>
|
||||
<Water></Water>= [2.847075, 2.847075] + [6, 10] = <Water>[8.847, 12.847]</Water>
|
||||
|
||||
Final (displayed) ranges:
|
||||
floor(<Neutral>[13.900425, 13.900425]</Neutral>) = <Neutral>[13, 13]</Neutral>
|
||||
floor(<Earth>[81.75, 99.75]</Earth>) = <Earth>[81, 99]</Earth>
|
||||
floor(<Thunder>[4.5025, 20.5025]</Thunder>) = <Thunder>[4, 20]</Thunder>
|
||||
floor(<Water>[8.847, 12.847]</Water>) = <Water>[8, 12]</Water></pre>
|
||||
<p>After flooring all damage values, the Crystal Senbon should display damage ranges of <Neutral>[13, 13]</Neutral> <Earth>[43, 19]</Earth> <Thunder>[4, 20]</Thunder> <Water>[8, 12]</Water>. However, our weapon display suggests otherwise! This is because it is lying.</p>
|
||||
<div class="text-center fig">
|
||||
<img src="./media/crystal_senbon_powdered.png" width = "300"/>
|
||||
</div>
|
||||
<p>We collected some data samples by melee-ing some combat dummies many times (on the order of hundreds). Showing photo proof for many hits in this post is excessive (we show one for good measure). We tested this on a character with 0 abilities, 0 external buffs, and only the skill points necessary for holding Crystal Senbon (10 in each).</p>
|
||||
<p>This is somewhat handwaving damage calculation, but here's the expected ranges of an assassin melee attack using the weapon damages we calculated.</p>
|
||||
<p>Stat bonuses:
|
||||
<li>3% earth damage boost (crystal senbon id)</li>
|
||||
<li>7% thunder damage boost (crystal senbon id)</li>
|
||||
<li>4% water damage boost (crystal senbon id)</li>
|
||||
<li>11.3% earth dmg boost (12 str)</li>
|
||||
<li>11.3% thunder dmg boost (12 dex)</li>
|
||||
<li>7.0% water dmg boost (12 int)</li>
|
||||
<li>11.3% total damage boost (12 strength)</li>
|
||||
</p>
|
||||
<p>The damage ranges we would expect to see from using a melee attack using our calculated base damage ranges:</p>
|
||||
<p><code><Neutral>[13.900425, 13.900425]</Neutral> * (1 + .113) ~= <Neutral>[15.4707, 15.4707]</Neutral></code> </p>
|
||||
<p><code><Earth>[81.75, 99.75]</Earth> * (1 + 0.03 + 0.113) * (1 + 0.113) ~= <Earth>[103.999, 126.898]</Earth></code></p>
|
||||
<p><code><Thunder>[4.5025, 20.5025]</Thunder> * (1 + 0.07 + 0.113) * (1 + 0.113) ~= <Thunder>[5.928, 26.995]</Thunder></code></p>
|
||||
<p><code><Water>[8.847, 12.847]</Water> * (1 + 0.04 + 0.07) * (1 + 0.113) ~= <Water>[10.930, 15.872]</Water></code></p>
|
||||
<div class="text-center fig">
|
||||
<img src="./media/crystal_senbon_attack.png" width = "500"/>
|
||||
<div class = "caption">Note: the double damage hit is due to a dexterity crit.</div>
|
||||
</div>
|
||||
<p>Evidently, the observed damages match up much more closely the powder/damage calculations we've performed compared to the advertised damages on the weapon. Consider the fact that the weapon display doesn't even show neutral damage...</p>
|
||||
</div>
|
||||
</span>
|
||||
</div>
|
||||
|
||||
<div class="section">
|
||||
<h2>Powder Application on Crafted Weapons</h2>
|
||||
<p>There are 2 algorithms relevant to powder mechanics on crafted weapons. First, we'll cover the ingredient powder mechanic.</p>
|
||||
<p>The ingredient powder mechanic:</p>
|
||||
<pre>
|
||||
powders = [crafting menu powders in order of reading english]
|
||||
for powder in powders:
|
||||
conversion = floor(neutral_remaining * powder.conversion)
|
||||
Neutral_base_dmg -= conversion
|
||||
Elem_base_dmg += conversion + floor((powder.raw.low + powder.raw.high) / 2)</pre>
|
||||
<p>For those unfamiliar with crafted weapon base damage: crafted weapons have a singular base damage value that is randomly chosen from a range when the item is crafted. The resulting base damage range is calculated using this value: if <code>base</code> is the base damage value, then the corresponding range is <code>[floor(0.9 * base), floor(1.1 * base)]</code>. The ingredient powder mechanic modifies the base damage values of a crafted weapon before they get converted to base damage ranges.</p>
|
||||
<p>If you use a powder as an ingredient in a crafting recipe for a crafted weapon, the above ingredient powder mechanic is applied. However, there's a more complex interaction when using both ingredient and applied powders. Using the ingredient powder mechanic and the applied powder mechanic as subroutines, we can define the algorithm for applying powders on crafted weapons as below:</p>
|
||||
<ul>1) Apply all applied powders with the ingredient powder mechanic.</ul>
|
||||
<ul>2) Apply all ingredient powders with the ingredient powder mechanic.</ul>
|
||||
<ul>3) Use the base damage values of the crafted weapon to get a full damage range.</ul>
|
||||
<ul>4) Apply all applied powders with the applied powder mechanic.</ul>
|
||||
<p>Both the ingredient powder mechanic and the full algorithm for crafted weapon powders were tested and verified in-game. For another worked-out example, expand the following dropdown.</p>
|
||||
<span class="dropdown" title="Crafted Weapon Powder Example">
|
||||
<div>
|
||||
<p>We crafted a wand using a <Air>III</Air> powder as an ingredient. Here's a <a href = "/crafter/#1+x+W+W+W+W+W9q10" class = "link">link to the recipe</a>. We then applied these powders, in order: [<Water>I</Water>, <Fire>I</Fire>, <Water>I</Water>]. Powder stats below:</p>
|
||||
<li><Air>III</Air>: [4, 11] raw, 17% conversion</li>
|
||||
<li><Water>I</Water>: [3, 4] raw, 13% conversion</li>
|
||||
<li><Fire>I</Fire>: [2, 5] raw, 14% conversion</li>
|
||||
<div class="text-center fig">
|
||||
<img src="./media/CR_prepowder.png" width = "500"/>
|
||||
<div class = "caption">The crafted weapon pre-applied powders.</div>
|
||||
</div>
|
||||
<p>The crafted weapon starts with 181 base (before applying any powders through any mechanic). We will run through the entire crafted weapon powder application process below:</p>
|
||||
<pre>
|
||||
Starting Neutral Base: <Neutral>181</Neutral>
|
||||
|
||||
1) Apply applied powders with ingredient powder mechanic
|
||||
<Neutral></Neutral>-= floor(.13 * 181) = 181 - 23 = <Neutral>158</Neutral>
|
||||
<Water></Water>+= 23 + floor((3+4)/2) = 23 + 3 = <Water>26</Water>
|
||||
|
||||
<Neutral></Neutral>-= floor(.14 * 158) = 158 - 22 = <Neutral>136</Neutral>
|
||||
<Fire></Fire>+= 22 + floor((2 + 5)/2) = 22 + 3 = <Fire>25</Fire>
|
||||
|
||||
<Neutral></Neutral>-= floor(.13 * 136) = 136 - 17 = <Neutral>119</Neutral>
|
||||
<Water></Water>+= 17 + floor((3 + 4) / 2) = 26 + 17 + 3 = <Water>46</Water>
|
||||
|
||||
2) Apply ingredient powders with ingredient powder mechanic
|
||||
|
||||
<Neutral></Neutral>-= floor(.17 * 119) = 119 - 20 = <Neutral>99</Neutral>
|
||||
<Air></Air>+= 20 + floor((4 + 11) / 2) = 20 + 7 = <Air>27</Air>
|
||||
|
||||
3) Convert base damage to ranges
|
||||
floor(<Neutral>99</Neutral> * [0.9, 1.1]) = <Neutral>[89, 108]</Neutral>
|
||||
floor(<Water>46</Water> * [0.9, 1.1]) = <Water>[41, 50]</Water>
|
||||
floor(<Fire>25</Fire> * [0.9, 1.1]) = <Fire>[22, 27]</Fire>
|
||||
floor(<Air>27</Air> * [0.9, 1.1]) = <Air>[24, 29]</Air>
|
||||
|
||||
4) Applied applied powders with applied powder mechanic
|
||||
|
||||
Starting base ranges:
|
||||
<Neutral>[89, 108]</Neutral>
|
||||
<Water>[41, 50]</Water>
|
||||
<Fire>[22, 27]</Fire>
|
||||
<Air>[24, 29]</Air>
|
||||
|
||||
Powders applied: [<Water>I</Water>, <Fire>I</Fire>, <Water>I</Water>]
|
||||
|
||||
Aggregation step:
|
||||
<Water></Water>[3, 4] *2, 13% * 2 = {raw: [6, 8], conversion: .26}
|
||||
<Fire></Fire>[2, 5], 14% * 1 = {raw: [2, 5], conversion: .14}
|
||||
|
||||
Application step:
|
||||
|
||||
W conversion: [89, 108] * .26 = [23.14, 28.08]
|
||||
<Water></Water>= [41, 50] + [23.14, 28.08] + [6, 8] = <Water>[70.16, 86.08]</Water>
|
||||
<Neutral></Neutral> = [89, 108] - [23.14, 28.08] = <Neutral>[65.86, 79.92]</Neutral>
|
||||
|
||||
F conversion: [65.86, 79.92] * .14 = [9.2204, 11.1888]
|
||||
<Fire></Fire> = [22, 27] + [9.2204, 11.1888] + [2, 5] = <Fire>[33.2204, 43.1888]</Fire>
|
||||
<Neutral></Neutral> = [65.86, 79.92] - [9.2204, 11.1888] = <Neutral>[56.6396, 68.7312]</Neutral>
|
||||
|
||||
Final (displayed) ranges
|
||||
floor(<Neutral>[56.6396, 68.7312]</Neutral>) = <Neutral>[56, 68]</Neutral>
|
||||
floor(<Water>[70.16, 86.08]</Water>) = <Water>[70, 86]</Water>
|
||||
floor(<Fire>[33.2204, 43.1888]</Fire>)= <Fire>[33, 43]</Fire>
|
||||
floor(<Air>[24, 29]</Air>) = <Air>[24, 29]</Air></pre>
|
||||
<p>And, to compare, here's the crafted weapon after applying powders. Again, the numbers are slightly off for the same reasons as they are with the regular weapon example.</p>
|
||||
<div class="text-center fig">
|
||||
<img src="./media/CR_postpowder.png" width = "500"/>
|
||||
<div class = "caption">The crafted weapon after applied powders.</div>
|
||||
</div>
|
||||
<p>We did the same melee attack testing on combat dummies. We leave damage calculation out of this example, but the damages observed more closely match the calculated numbers than the displayed numbers. Here's a screenshot:</p>
|
||||
<div class="text-center fig">
|
||||
<img src="./media/CR_attack.png" width = "500"/>
|
||||
</div>
|
||||
</div>
|
||||
</span>
|
||||
</div>
|
||||
|
||||
|
||||
<div class="section">
|
||||
|
||||
</div>
|
||||
</main>
|
||||
<script type="text/javascript" src="/thirdparty/katex.js"></script>
|
||||
<script type="text/javascript" src="/js/icons.js"></script>
|
||||
</body>
|
||||
</html>
|
BIN
wynnfo/powders/media/CR_attack.png
Normal file
After Width: | Height: | Size: 722 KiB |
BIN
wynnfo/powders/media/CR_postpowder.png
Normal file
After Width: | Height: | Size: 26 KiB |
BIN
wynnfo/powders/media/CR_prepowder.png
Normal file
After Width: | Height: | Size: 21 KiB |
BIN
wynnfo/powders/media/crystal_senbon_attack.png
Normal file
After Width: | Height: | Size: 298 KiB |
BIN
wynnfo/powders/media/crystal_senbon_powdered.png
Normal file
After Width: | Height: | Size: 341 KiB |
|
@ -1,172 +0,0 @@
|
|||
// ['Title', ["type of paper","file name"]]
|
||||
const pdfs = new Map([
|
||||
["Wynncraft Damage Calculation",
|
||||
["Mechanics", "Damage_calculation", "hppeng, ferricles, et al.", "A complete guide to Wynncraft's damage calculations. Includes formulas, tested game values, and worked examples."
|
||||
]],
|
||||
["Crafted Weapon Powder Mechanics",
|
||||
["Mechanics", "Crafted_Weapon_Powder_Mechanics", "ferricles", "A short guide to the mechanics of powder application on crafted weapons. Includes formulas and a worked example."
|
||||
]],
|
||||
["Spell Costs",
|
||||
["Mechanics", "Spell_Costs", "Bart MC, ferricles", "A documentation of spell costs and the mechanics of spell cost reduction."
|
||||
]],
|
||||
//[title ,[genre, filename, author(s), abstract/desc]]
|
||||
]);
|
||||
|
||||
|
||||
const changelog = new Map([
|
||||
["Build Version 6 (20 May 2022)",
|
||||
[
|
||||
" + Added Tomes",
|
||||
" + Changed Build encode and decode schemes to account for tomes",
|
||||
]
|
||||
],
|
||||
["WynnBuilder^2 (12 May 2022)",
|
||||
[
|
||||
" + Switched most of Wynnbuilder over to Bootstrap",
|
||||
" - Old UI",
|
||||
]
|
||||
],
|
||||
//[title ,[genre, filename, author(s), abstract/desc]]
|
||||
]);
|
||||
|
||||
|
||||
const sections = ["Changelog", "Mechanics", "History" ]
|
||||
|
||||
function init() {
|
||||
initSections();
|
||||
|
||||
for ([title, pdf] of pdfs) {
|
||||
let sec = document.getElementById(pdf[0]+"-section");
|
||||
if (sec) {
|
||||
let pre = document.createElement("pre");
|
||||
let firstline = document.createElement("div");
|
||||
firstline.style.display = "flex";
|
||||
firstline.style.justifyContent = "space-between";
|
||||
|
||||
let titleElem = document.createElement("p");
|
||||
titleElem.textContent = title;
|
||||
|
||||
let a = document.createElement("a");
|
||||
a.href = "./pdfs/" + pdf[1] + ".pdf";
|
||||
a.target = "_blank";
|
||||
a.textContent = pdf[1] + ".pdf";
|
||||
a.classList.add("link");
|
||||
a.style.display = "flex-end";
|
||||
|
||||
let secondline = document.createElement("div");
|
||||
secondline.style.display = "flex";
|
||||
let ul = document.createElement("ul");
|
||||
ul.style.wordBreak = "break-word";
|
||||
let li = document.createElement("li");
|
||||
let div = document.createElement("div");
|
||||
if (pdf[2]) {
|
||||
li.textContent = "Author(s): " + pdf[2];
|
||||
} else {
|
||||
li.textContent = "Author(s): Unknown";
|
||||
}
|
||||
ul.appendChild(li);
|
||||
li = document.createElement("li");
|
||||
div = document.createElement("div");
|
||||
if (pdf[3]) {
|
||||
div.textContent = "Description: " + pdf[3];
|
||||
} else {
|
||||
div.textContent = "Description: None";
|
||||
}
|
||||
ul.appendChild(li);
|
||||
li.appendChild(div);
|
||||
pre.appendChild(firstline);
|
||||
firstline.appendChild(titleElem);
|
||||
firstline.appendChild(a);
|
||||
pre.appendChild(secondline);
|
||||
secondline.appendChild(ul);
|
||||
|
||||
sec.appendChild(document.createElement("br"));
|
||||
sec.appendChild(pre);
|
||||
} else {
|
||||
console.log("Invalid paper type for " + title + ": " + pdf[0]);
|
||||
}
|
||||
}
|
||||
|
||||
let sec = document.getElementById("Changelog-section");
|
||||
for ([version, changes] of changelog) {
|
||||
let pre = document.createElement("pre");
|
||||
let firstline = document.createElement("div");
|
||||
firstline.style.display = "flex";
|
||||
firstline.style.justifyContent = "space-between";
|
||||
|
||||
let titleElem = document.createElement("p");
|
||||
titleElem.textContent = "Version " + version;
|
||||
|
||||
pre.appendChild(firstline);
|
||||
firstline.appendChild(titleElem);
|
||||
sec.appendChild(document.createElement("br"));
|
||||
sec.appendChild(pre);
|
||||
|
||||
let ul = document.createElement("ul");
|
||||
ul.style.listStyle = "none";
|
||||
for (change of changes) {
|
||||
let li = document.createElement("li");
|
||||
li.textContent = change;
|
||||
if (change.substring(0,3) === " + ") {
|
||||
li.classList.add("positive");
|
||||
} else if (change.substring(0,3) === " - ") {
|
||||
li.classList.add("negative");
|
||||
} else {
|
||||
}
|
||||
ul.appendChild(li);
|
||||
}
|
||||
|
||||
pre.appendChild(ul);
|
||||
}
|
||||
}
|
||||
|
||||
function initSections() {
|
||||
let main = document.getElementById("main");
|
||||
for (const sec of sections) {
|
||||
let div = document.createElement("div");
|
||||
div.classList.add("row", "my-2");
|
||||
div.id = sec;
|
||||
|
||||
let secspan = document.createElement("span");
|
||||
secspan.classList.add("row", "up", "clickable");
|
||||
div.appendChild(secspan);
|
||||
let title = document.createElement("div");
|
||||
title.classList.add("col-10", "item-title", "text-start")
|
||||
title.style.margin = "0 0 0";
|
||||
title.textContent = "Section: " + sec;
|
||||
let indicator = document.createElement("div");
|
||||
indicator.classList.add("col-auto", "fw-bold", "box-title");
|
||||
indicator.textContent = "V";
|
||||
secspan.appendChild(title);
|
||||
secspan.appendChild(indicator);
|
||||
|
||||
|
||||
let section = document.createElement("section");
|
||||
section.classList.add("toggle-section");
|
||||
section.id = sec + "-section";
|
||||
section.style.display = "none";
|
||||
div.appendChild(section);
|
||||
main.appendChild(div);
|
||||
|
||||
secspan.addEventListener("click", function(){
|
||||
if (secspan.classList.contains("up")) {
|
||||
secspan.classList.remove("up");
|
||||
secspan.classList.add("down");
|
||||
indicator.style.transform = 'rotate(180deg)';
|
||||
|
||||
section.style.display = "";
|
||||
} else {
|
||||
secspan.classList.remove("down");
|
||||
secspan.classList.add("up");
|
||||
indicator.style.transform = 'rotate(0deg)';
|
||||
section.style.display = "none";
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
init();
|
|
@ -1,354 +0,0 @@
|
|||
.header {
|
||||
text-align: center;
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
justify-content: center;
|
||||
}
|
||||
.title{
|
||||
text-align: center;
|
||||
font-size: 150%;
|
||||
}
|
||||
.smalltitle{
|
||||
text-align: center;
|
||||
font-size: 125%;
|
||||
margin-top: 10px;
|
||||
margin-bottom: 4px;
|
||||
}
|
||||
.headericon {
|
||||
/* JANK FIX IF CAN */
|
||||
max-height: 48px;
|
||||
max-width: 48px;
|
||||
}
|
||||
.headerleft {
|
||||
display: inline-block;
|
||||
width: 35%;
|
||||
text-align: left;
|
||||
}
|
||||
.headercenter {
|
||||
display: inline-block;
|
||||
width: 30%;
|
||||
text-align: center;
|
||||
}
|
||||
.headerright{
|
||||
display: inline-block;
|
||||
width: 35%;
|
||||
text-align: right;
|
||||
}
|
||||
.iconlink {
|
||||
position: relative;
|
||||
left: 0%;
|
||||
right: 0%;
|
||||
height: 100%;
|
||||
width: 100%;
|
||||
}
|
||||
.all {
|
||||
font-family: 'Nunito',sans-serif;
|
||||
font-weight: 700;
|
||||
}
|
||||
.left{
|
||||
margin: 2px 2%;
|
||||
text-align: left;
|
||||
}
|
||||
.center {
|
||||
text-align: center;
|
||||
position: relative;
|
||||
}
|
||||
.itemp, .damagep {
|
||||
margin: 2px 2%;
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
/*Scrollbar*/
|
||||
/* width */
|
||||
::-webkit-scrollbar {
|
||||
width: 10px;
|
||||
}
|
||||
|
||||
/* Track */
|
||||
::-webkit-scrollbar-track {
|
||||
box-shadow: inset 0 0 5px #BCBCBC;
|
||||
border: #BCBCBC;
|
||||
border-radius: 5px;
|
||||
}
|
||||
|
||||
/* Handle */
|
||||
::-webkit-scrollbar-thumb {
|
||||
background: #aaa;
|
||||
border-radius: 10px;
|
||||
}
|
||||
|
||||
/* Ugly Corner */
|
||||
::-webkit-scrollbar-corner{
|
||||
background: #110110;
|
||||
}
|
||||
|
||||
.tooltip {
|
||||
position: relative;
|
||||
}
|
||||
.tooltip .tooltiptext {
|
||||
visibility: hidden;
|
||||
color: #ddd;
|
||||
background: #110110;
|
||||
/*width: min(200%, 75vw);*/
|
||||
display: inline-block;
|
||||
padding: 0 min(2%,10px) 0 min(2%,10px);
|
||||
text-align: center;
|
||||
border: 1px solid #BCBCBC;
|
||||
border-radius: 2px;
|
||||
position: absolute;
|
||||
z-index: 1;
|
||||
}
|
||||
.tooltip:hover .tooltiptext {
|
||||
visibility: visible;
|
||||
}
|
||||
.header-tooltip {
|
||||
top: 100%;
|
||||
left: -20%;
|
||||
}
|
||||
|
||||
.button-narrow {
|
||||
background-color: #666;
|
||||
border: 2px solid #444;
|
||||
border-radius: 5px;
|
||||
color: #ddd;
|
||||
text-align: center;
|
||||
text-decoration: none;
|
||||
font-family: 'Nunito',sans-serif;
|
||||
font-weight: 700;
|
||||
font-size: 90%;
|
||||
display: inline-block;
|
||||
}
|
||||
button {
|
||||
background-color: #666;
|
||||
border: 2px solid #444;
|
||||
border-radius: 5px;
|
||||
color: #ddd;
|
||||
text-align: center;
|
||||
text-decoration: none;
|
||||
font-family: 'Nunito',sans-serif;
|
||||
font-weight: 700;
|
||||
font-size: 120%;
|
||||
display: inline-block;
|
||||
}
|
||||
button:hover {
|
||||
background-color: #556;
|
||||
}
|
||||
|
||||
button:active {
|
||||
background-color: #558;
|
||||
box-shadow: 0 3px #666;
|
||||
transform: translateY(1px);
|
||||
}
|
||||
|
||||
/*==============================================================*/
|
||||
.all{
|
||||
background: #121516;
|
||||
color: #aaa;
|
||||
}
|
||||
|
||||
a.link{
|
||||
color: #A5FDFF;
|
||||
}
|
||||
|
||||
main {
|
||||
margin: 24px 0 48px;
|
||||
}
|
||||
|
||||
main h2 {
|
||||
margin: 0 0 8px;
|
||||
color: #bbb;
|
||||
font-size: 24pt;
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
main p {
|
||||
margin: 0 0 8px;
|
||||
line-height: 1.35em;
|
||||
text-indent: 2.5em;
|
||||
text-align: justify;
|
||||
font-size: 13pt;
|
||||
font-weight: 700;
|
||||
}
|
||||
|
||||
main .footer {
|
||||
font-size: 10pt;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
main code {
|
||||
padding: 0 3px;
|
||||
background-color: #1d1f21;
|
||||
color: #de935f;
|
||||
font-family: 'Source Code Pro', 'Ubuntu Mono', 'Courier New', monospace;
|
||||
}
|
||||
|
||||
main pre { /* tomorrow night: https://github.com/chriskempson/tomorrow-theme */
|
||||
margin: 14px 2px;
|
||||
padding: 10px 16px;
|
||||
border-left: 4px solid #7f7f7f;
|
||||
background-color: #1d1f21;
|
||||
color: #ddd;
|
||||
font-size: 12pt;
|
||||
font-weight: normal;
|
||||
}
|
||||
|
||||
main pre > .prop {
|
||||
color: #cc6666;
|
||||
}
|
||||
|
||||
main pre > .fn {
|
||||
color: #f0c674;
|
||||
}
|
||||
|
||||
main pre > .bool {
|
||||
color: #b294bb;
|
||||
}
|
||||
|
||||
main pre > .str {
|
||||
color: #b5bd68;
|
||||
}
|
||||
|
||||
main pre > .num {
|
||||
color: #81a2be;
|
||||
}
|
||||
|
||||
main pre > .op {
|
||||
color: #ccc;
|
||||
}
|
||||
|
||||
main strong {
|
||||
color: #ccc;
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
main .rb-text {
|
||||
background-image: linear-gradient(to left, #f5f, #a0a, #5ff, #5f5, #ff5, #fa0, #a00, #f5f);
|
||||
background-size: 300% 100%;
|
||||
-webkit-background-clip: text;
|
||||
color: transparent;
|
||||
animation: scroll-bg 4s linear infinite;
|
||||
}
|
||||
|
||||
main .math {
|
||||
font-family: 'CMU Serif', 'Cambria Math', 'Times New Roman', serif;
|
||||
}
|
||||
|
||||
main .heart {
|
||||
color: #e44078;
|
||||
}
|
||||
|
||||
@keyframes scroll-bg {
|
||||
0% {
|
||||
background-position-x: 0;
|
||||
}
|
||||
100% {
|
||||
background-position-x: 300%;
|
||||
}
|
||||
}
|
||||
|
||||
.full-width {
|
||||
width: 100%;
|
||||
margin: 4px 0 32px;
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
.full-width > img {
|
||||
width: 100%;
|
||||
background-color: #000;
|
||||
filter: brightness(0.7) contrast(1.2) grayscale(0.5);
|
||||
}
|
||||
|
||||
.section {
|
||||
margin: 0 10vw 28px;
|
||||
}
|
||||
|
||||
.docs {
|
||||
margin: 14px 0;
|
||||
}
|
||||
|
||||
.docs h3 {
|
||||
margin: 0 0 8px;
|
||||
color: #aaa;
|
||||
font-size: 20pt;
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
.docs-entry {
|
||||
margin: 4px 0 16px;
|
||||
}
|
||||
|
||||
.docs-entry-key {
|
||||
margin-bottom: 6px;
|
||||
padding: 4px 6px;
|
||||
display: flex;
|
||||
flex-flow: row;
|
||||
align-items: baseline;
|
||||
background-color: #1d1f21;
|
||||
font-weight: normal;
|
||||
}
|
||||
|
||||
.docs-entry-key-id {
|
||||
color: #cc6666;
|
||||
font-size: 16pt;
|
||||
font-family: 'Source Code Pro', 'Ubuntu Mono', 'Courier New', monospace;
|
||||
}
|
||||
|
||||
.docs-entry-key-type {
|
||||
flex: 1;
|
||||
margin-left: 8px;
|
||||
color: #de935f;
|
||||
font-size: 11pt;
|
||||
font-family: 'Source Code Pro', 'Ubuntu Mono', 'Courier New', monospace;
|
||||
}
|
||||
|
||||
.docs-entry-key-alias {
|
||||
float: right;
|
||||
color: #515356;
|
||||
font-size: 11pt;
|
||||
}
|
||||
|
||||
.docs-entry-key-alias > .alias {
|
||||
float: none;
|
||||
color: #969896;
|
||||
font-family: 'Source Code Pro', 'Ubuntu Mono', 'Courier New', monospace;
|
||||
}
|
||||
|
||||
.docs-entry > p {
|
||||
margin-left: 1.5em;
|
||||
text-indent: 0;
|
||||
}
|
||||
|
||||
.indicator-img {
|
||||
max-height: 24px;
|
||||
top: 0;
|
||||
bottom: 0;
|
||||
display: flex-end;
|
||||
margin: auto 0 auto;
|
||||
}
|
||||
.span-flex > * {
|
||||
display: inline-block;
|
||||
}
|
||||
.span-flex {
|
||||
width: 100%;
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
}
|
||||
.span-flex:hover {
|
||||
text-decoration: underline;
|
||||
}
|
||||
|
||||
ul{
|
||||
word-wrap: break-word;
|
||||
word-break: break-word;
|
||||
white-space: pre-wrap;
|
||||
}
|
||||
|
||||
.positive {
|
||||
color: #5f5;
|
||||
/*text-shadow: 2px 2px 0 #153f15;*/
|
||||
}
|
||||
|
||||
.negative {
|
||||
color: #f55;
|
||||
/*text-shadow: 2px 2px 0 #1f1515;*/
|
||||
}
|