Compare commits
27 commits
sock_encod
...
dev
Author | SHA1 | Date | |
---|---|---|---|
5faee76143 | |||
|
a1ddce803f | ||
|
1d6b302f38 | ||
|
3e725eded8 | ||
|
479af33a81 | ||
|
1a5ad19ef5 | ||
|
590aa2269d | ||
|
d9e5d6da95 | ||
|
4b9460ebc2 | ||
|
645f3145f0 | ||
|
39c8357c5d | ||
|
4cf270f24f | ||
|
8058bb5374 | ||
|
24de93168f | ||
|
53c4ea67cc | ||
|
fb8e62ce9c | ||
|
e3b2ea4cdf | ||
|
dc878caf1c | ||
|
2bdebda89f | ||
|
bf29018a60 | ||
|
88fe5217d2 | ||
|
e37226fae7 | ||
|
cded54bcc0 | ||
|
0a054b8d94 | ||
|
f90794070a | ||
|
cc7e5b6818 | ||
|
0e66c63cda |
147 changed files with 340829 additions and 120522 deletions
|
@ -10,9 +10,9 @@
|
|||
<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://cdn.jsdelivr.net/npm/bootstrap@5.1.3/dist/css/bootstrap.min.css" rel="stylesheet" integrity="sha384-1BmE4kWBq78iYhFldvKuhfTAU6auU8tT94WrHftjDbrCEXSU1oBoqyl2QvZ6jIW3" crossorigin="anonymous">
|
||||
<link href="/thirdparty/bootstrap.min.css" rel="stylesheet" integrity="sha384-1BmE4kWBq78iYhFldvKuhfTAU6auU8tT94WrHftjDbrCEXSU1oBoqyl2QvZ6jIW3" crossorigin="anonymous">
|
||||
|
||||
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/@tarekraafat/autocomplete.js@10.2.6/dist/css/autoComplete.min.css">
|
||||
<link rel="stylesheet" href="/thirdparty/autoComplete.min.css">
|
||||
|
||||
<link rel="stylesheet" href="../css/sidebar.css">
|
||||
<link rel="stylesheet" href="../css/sq2bs.css">
|
||||
|
@ -27,6 +27,8 @@
|
|||
<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>
|
||||
<hr/>
|
||||
<a href = "https://nori.fish/wynn/build/" target = "_blank"><img src = "../media/icons/new/nori_build.png" alt = "Build Search" title = "Build Search by Nori-Wynn"><b>Build Search</b></a>
|
||||
<a href = "https://nori.fish/wynn/recipe/" target = "_blank"><img src = "../media/icons/new/nori_recipe.png" alt = "Recipe Search" title = "Recipe Search by Nori-Wynn"><b>Recipe Search</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>
|
||||
<div class="container-fluid py-1 vh-100">
|
||||
|
@ -60,8 +62,8 @@
|
|||
|
||||
|
||||
<script src="https://cdn.jsdelivr.net/npm/bootstrap@5.1.3/dist/js/bootstrap.bundle.min.js" integrity="sha384-ka7Sk0Gln4gmtz2MlQnikT1wXgYsOg+OMhuP+IlRH9sENBO0LRn5q+8nbTov4+1p" crossorigin="anonymous"></script>
|
||||
<script src="https://cdn.jsdelivr.net/npm/@tarekraafat/autocomplete.js@10.2.6/dist/autoComplete.min.js"></script>
|
||||
<script src="https://cdn.jsdelivr.net/npm/macy@2"></script>
|
||||
<script src="/thirdparty/autoComplete.min.js"></script>
|
||||
<script src="/thirdparty/macy@2"></script>
|
||||
|
||||
|
||||
<script type="text/javascript" src="../js/utils.js"></script>
|
||||
|
|
|
@ -15,9 +15,9 @@
|
|||
<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://cdn.jsdelivr.net/npm/bootstrap@5.1.3/dist/css/bootstrap.min.css" rel="stylesheet" integrity="sha384-1BmE4kWBq78iYhFldvKuhfTAU6auU8tT94WrHftjDbrCEXSU1oBoqyl2QvZ6jIW3" crossorigin="anonymous">
|
||||
<link href="/thirdparty/bootstrap.min.css" rel="stylesheet" integrity="sha384-1BmE4kWBq78iYhFldvKuhfTAU6auU8tT94WrHftjDbrCEXSU1oBoqyl2QvZ6jIW3" crossorigin="anonymous">
|
||||
|
||||
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/@tarekraafat/autocomplete.js@10.2.6/dist/css/autoComplete.min.css">
|
||||
<link rel="stylesheet" href="/thirdparty/autoComplete.min.css">
|
||||
|
||||
<link rel="stylesheet" href="../css/sq2bs.css">
|
||||
<link rel="stylesheet" href="../css/sidebar.css">
|
||||
|
@ -34,6 +34,8 @@
|
|||
<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://nori.fish/wynn/build/" target = "_blank"><img src = "../media/icons/new/nori_build.png" alt = "Build Search" title = "Build Search by Nori-Wynn"><b>Build Search</b></a>
|
||||
<a href = "https://nori.fish/wynn/recipe/" target = "_blank"><img src = "../media/icons/new/nori_recipe.png" alt = "Recipe Search" title = "Recipe Search by Nori-Wynn"><b>Recipe Search</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>
|
||||
<div id="mobile-navbar" class="navbar dark-5 dark-shadow fixed-top d-lg-none pb-0">
|
||||
|
@ -73,6 +75,14 @@
|
|||
<img src="../media/icons/new/reload.png" alt="" style="height: 100%;">
|
||||
<span>Swap Icon Style</span>
|
||||
</a>
|
||||
<a href="https://nori.fish/wynn/build/" class="w-100 mb-3 text-white" style="height: 5vh; text-decoration: none;">
|
||||
<img src="../media/icons/new/nori_build.png" alt="" style="height: 100%;">
|
||||
<span>Build Search</span>
|
||||
</a>
|
||||
<a href="https://nori.fish/wynn/recipe/" class="w-100 mb-3 text-white" style="height: 5vh; text-decoration: none;">
|
||||
<img src="../media/icons/new/nori_recipe.png" alt="" style="height: 100%;">
|
||||
<span>Recipe Search</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>
|
||||
|
@ -464,7 +474,7 @@
|
|||
War Scream
|
||||
</button>
|
||||
<button class="button-boost m-1 border-0 text-white dark-8u dark-shadow-sm" id="ragnarokkr-boost" onclick="update_boosts('ragnarokkr-boost')">
|
||||
Ragnarokkr (+30%)
|
||||
Ragnarokkr (+20%)
|
||||
</button>
|
||||
<button class="button-boost m-1 border-0 text-white dark-8u dark-shadow-sm" id="totem-boost" onclick="update_boosts('totem-boost')">
|
||||
Vengeful Spirit (+20%)
|
||||
|
@ -506,19 +516,19 @@
|
|||
</div>
|
||||
<div class="col skp-tooltip dark-6 rounded-bottom my-3 my-xl-1" >
|
||||
<button class = "button-boost m-1 border-0 text-white dark-8u dark-shadow-sm" id = "Quake-1" onclick = "updatePowderSpecials('Quake-1')">
|
||||
Lv.4 [e4e4]
|
||||
Lv.1
|
||||
</button>
|
||||
<button class = "button-boost m-1 border-0 text-white dark-8u dark-shadow-sm" id = "Quake-2" onclick = "updatePowderSpecials('Quake-2')">
|
||||
Lv.4.5 [e5e4]
|
||||
Lv.2
|
||||
</button>
|
||||
<button class = "button-boost m-1 border-0 text-white dark-8u dark-shadow-sm" id = "Quake-3" onclick = "updatePowderSpecials('Quake-3')">
|
||||
Lv.5 [e5e5]
|
||||
Lv.3
|
||||
</button>
|
||||
<button class = "button-boost m-1 border-0 text-white dark-8u dark-shadow-sm" id = "Quake-4" onclick = "updatePowderSpecials('Quake-4')">
|
||||
Lv.5.5 [e6e5]
|
||||
Lv.4
|
||||
</button>
|
||||
<button class = "button-boost m-1 border-0 text-white dark-8u dark-shadow-sm" id = "Quake-5" onclick = "updatePowderSpecials('Quake-5')">
|
||||
Lv.6 [e6e6]
|
||||
Lv.5
|
||||
</button>
|
||||
</div>
|
||||
<div class="col eDam">
|
||||
|
@ -531,19 +541,19 @@
|
|||
</div>
|
||||
<div class="col skp-tooltip dark-6 rounded-bottom my-3 my-xl-1">
|
||||
<button class = "button-boost m-1 border-0 text-white dark-8u dark-shadow-sm" id = "Chain_Lightning-1" onclick = "updatePowderSpecials('Chain_Lightning-1')">
|
||||
Lv.4 [t4t4]
|
||||
Lv.1
|
||||
</button>
|
||||
<button class = "button-boost m-1 border-0 text-white dark-8u dark-shadow-sm" id = "Chain_Lightning-2" onclick = "updatePowderSpecials('Chain_Lightning-2')">
|
||||
Lv.4.5 [t5t4]
|
||||
Lv.2
|
||||
</button>
|
||||
<button class = "button-boost m-1 border-0 text-white dark-8u dark-shadow-sm" id = "Chain_Lightning-3" onclick = "updatePowderSpecials('Chain_Lightning-3')">
|
||||
Lv.5 [t5t5]
|
||||
Lv.3
|
||||
</button>
|
||||
<button class = "button-boost m-1 border-0 text-white dark-8u dark-shadow-sm" id = "Chain_Lightning-4" onclick = "updatePowderSpecials('Chain_Lightning-4')">
|
||||
Lv.5.5 [t6t5]
|
||||
Lv.4
|
||||
</button>
|
||||
<button class = "button-boost m-1 border-0 text-white dark-8u dark-shadow-sm" id = "Chain_Lightning-5" onclick = "updatePowderSpecials('Chain_Lightning-5')">
|
||||
Lv.6 [t6t6]
|
||||
Lv.5
|
||||
</button>
|
||||
</div>
|
||||
<div class="col tDam">
|
||||
|
@ -556,19 +566,19 @@
|
|||
</div>
|
||||
<div class="col skp-tooltip dark-6 rounded-bottom my-3 my-xl-1">
|
||||
<button class = "button-boost m-1 border-0 text-white dark-8u dark-shadow-sm" id = "Curse-1" onclick = "updatePowderSpecials('Curse-1')">
|
||||
Lv.4 [w4w4]
|
||||
Lv.1
|
||||
</button>
|
||||
<button class = "button-boost m-1 border-0 text-white dark-8u dark-shadow-sm" id = "Curse-2" onclick = "updatePowderSpecials('Curse-2')">
|
||||
Lv.4.5 [w5w4]
|
||||
Lv.2
|
||||
</button>
|
||||
<button class = "button-boost m-1 border-0 text-white dark-8u dark-shadow-sm" id = "Curse-3" onclick = "updatePowderSpecials('Curse-3')">
|
||||
Lv.5 [w5w5]
|
||||
Lv.3
|
||||
</button>
|
||||
<button class = "button-boost m-1 border-0 text-white dark-8u dark-shadow-sm" id = "Curse-4" onclick = "updatePowderSpecials('Curse-4')">
|
||||
Lv.5.5 [w6w5]
|
||||
Lv.4
|
||||
</button>
|
||||
<button class = "button-boost m-1 border-0 text-white dark-8u dark-shadow-sm" id = "Curse-5" onclick = "updatePowderSpecials('Curse-5')">
|
||||
Lv.6 [w6w6]
|
||||
Lv.5
|
||||
</button>
|
||||
</div>
|
||||
<div class="col wDam">
|
||||
|
@ -581,19 +591,19 @@
|
|||
</div>
|
||||
<div class="col skp-tooltip dark-6 rounded-bottom my-3 my-xl-1">
|
||||
<button class = "button-boost m-1 border-0 text-white dark-8u dark-shadow-sm" id = "Courage-1" onclick = "updatePowderSpecials('Courage-1')">
|
||||
Lv.4 [f4f4]
|
||||
Lv.1
|
||||
</button>
|
||||
<button class = "button-boost m-1 border-0 text-white dark-8u dark-shadow-sm" id = "Courage-2" onclick = "updatePowderSpecials('Courage-2')">
|
||||
Lv.4.5 [f5f4]
|
||||
Lv.2
|
||||
</button>
|
||||
<button class = "button-boost m-1 border-0 text-white dark-8u dark-shadow-sm" id = "Courage-3" onclick = "updatePowderSpecials('Courage-3')">
|
||||
Lv.5 [f5f5]
|
||||
Lv.3
|
||||
</button>
|
||||
<button class = "button-boost m-1 border-0 text-white dark-8u dark-shadow-sm" id = "Courage-4" onclick = "updatePowderSpecials('Courage-4')">
|
||||
Lv.5.5 [f6f5]
|
||||
Lv.4
|
||||
</button>
|
||||
<button class = "button-boost m-1 border-0 text-white dark-8u dark-shadow-sm" id = "Courage-5" onclick = "updatePowderSpecials('Courage-5')">
|
||||
Lv.6 [f6f6]
|
||||
Lv.5
|
||||
</button>
|
||||
</div>
|
||||
<div class="col fDam">
|
||||
|
@ -606,19 +616,19 @@
|
|||
</div>
|
||||
<div class="col skp-tooltip dark-6 rounded-bottom my-3 my-xl-1">
|
||||
<button class = "button-boost m-1 border-0 text-white dark-8u dark-shadow-sm" id = "Wind_Prison-1" onclick = "updatePowderSpecials('Wind_Prison-1')">
|
||||
Lv.4 [a4a4]
|
||||
Lv.1
|
||||
</button>
|
||||
<button class = "button-boost m-1 border-0 text-white dark-8u dark-shadow-sm" id = "Wind_Prison-2" onclick = "updatePowderSpecials('Wind_Prison-2')">
|
||||
Lv.4.5 [a5a4]
|
||||
Lv.2
|
||||
</button>
|
||||
<button class = "button-boost m-1 border-0 text-white dark-8u dark-shadow-sm" id = "Wind_Prison-3" onclick = "updatePowderSpecials('Wind_Prison-3')">
|
||||
Lv.5 [a5a5]
|
||||
Lv.3
|
||||
</button>
|
||||
<button class = "button-boost m-1 border-0 text-white dark-8u dark-shadow-sm" id = "Wind_Prison-4" onclick = "updatePowderSpecials('Wind_Prison-4')">
|
||||
Lv.5.5 [a6a5]
|
||||
Lv.4
|
||||
</button>
|
||||
<button class = "button-boost m-1 border-0 text-white dark-8u dark-shadow-sm" id = "Wind_Prison-5" onclick = "updatePowderSpecials('Wind_Prison-5')">
|
||||
Lv.6 [a6a6]
|
||||
Lv.5
|
||||
</button>
|
||||
</div>
|
||||
<div class="col aDam">
|
||||
|
@ -975,7 +985,15 @@
|
|||
</div>
|
||||
</div>
|
||||
<div class = "col-lg-3 col-sm-6">
|
||||
|
||||
<div class = "row">
|
||||
Life Steal:
|
||||
</div>
|
||||
<div class = "row">
|
||||
<input type = "number" placeholder = "0" id="ls" name="ls" value="0" class="border-dark text-light dark-10 rounded scaled-font form-control form-control-sm"/>
|
||||
</div>
|
||||
<div class = "row" id = "ls-base">
|
||||
Original Value: 0
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class = "row big-title justify-content-center">
|
||||
|
@ -1235,7 +1253,7 @@
|
|||
<div class="col-12 dark-5 scaled-font">
|
||||
<footer class="text-center">
|
||||
<div id="header2">
|
||||
<p>Made by <b class = "hppeng">hppeng</b>, <b class = "ferricles">ferricles</b>, and <b>reschan</b> with <a href = "../atlas" target = "_blank" class = "atlas link">Atlas Inc</a> (JavaScript required to function, nothing works without js)</p>
|
||||
<p>Made by <b class = "hppeng">hppeng</b>, <b class = "ferricles">ferricles</b>, <b>reschan</b>, and <b>blankman</b> with <a href = "../atlas" target = "_blank" class = "atlas link">Atlas Inc</a> (JavaScript required to function, nothing works without js)</p>
|
||||
<p>Hard refresh the page (Ctrl+Shift+R on windows/chrome) if it isn't updating correctly.</p>
|
||||
</div>
|
||||
<div id="credits">
|
||||
|
@ -1297,12 +1315,14 @@
|
|||
</div>
|
||||
</div>
|
||||
|
||||
<script src="https://cdn.jsdelivr.net/npm/@tarekraafat/autocomplete.js@10.2.6/dist/autoComplete.min.js"></script>
|
||||
<script src="https://cdn.jsdelivr.net/npm/macy@2"></script>
|
||||
<script src="/thirdparty/autoComplete.min.js"></script>
|
||||
<script src="/thirdparty/macy@2"></script>
|
||||
<script type="text/javascript" src="../js/utils.js"></script>
|
||||
<script type="text/javascript" src="../js/build_utils.js"></script>
|
||||
|
||||
<script type="text/javascript" src="../js/computation_graph.js"></script>
|
||||
<script type="text/javascript">COMPUTE_GRAPH_DEBUG=true</script>
|
||||
|
||||
<script type="text/javascript" src="../js/icons.js"></script>
|
||||
<script type="text/javascript" src="../js/powders.js"></script>
|
||||
<script type="text/javascript" src="../js/skillpoints.js"></script>
|
||||
|
@ -1321,13 +1341,11 @@
|
|||
<script type="text/javascript" src="../js/builder/builder_graph.js"></script>
|
||||
<script type="text/javascript" src="../js/builder/builder.js"></script>
|
||||
<!--script type="text/javascript" src="../js/builder/optimize.js"></script-->
|
||||
|
||||
<div id="graph_body" style="max-width: 100%; height: 100vh">
|
||||
<button id="saveButton">JANKY Export SVG</button>
|
||||
<a id="saveLink">savelink</a>
|
||||
</div>
|
||||
<script src="https://d3js.org/d3.v7.js"></script>
|
||||
<script type="text/javascript" src="../js/debug/render_compute_graph.js"></script>
|
||||
|
||||
</body>
|
||||
</html>
|
||||
|
|
File diff suppressed because one or more lines are too long
|
@ -15,9 +15,9 @@
|
|||
<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://cdn.jsdelivr.net/npm/bootstrap@5.1.3/dist/css/bootstrap.min.css" rel="stylesheet" integrity="sha384-1BmE4kWBq78iYhFldvKuhfTAU6auU8tT94WrHftjDbrCEXSU1oBoqyl2QvZ6jIW3" crossorigin="anonymous">
|
||||
<link href="/thirdparty/bootstrap.min.css" rel="stylesheet" integrity="sha384-1BmE4kWBq78iYhFldvKuhfTAU6auU8tT94WrHftjDbrCEXSU1oBoqyl2QvZ6jIW3" crossorigin="anonymous">
|
||||
|
||||
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/@tarekraafat/autocomplete.js@10.2.6/dist/css/autoComplete.min.css">
|
||||
<link rel="stylesheet" href="/thirdparty/autoComplete.min.css">
|
||||
|
||||
<link rel="stylesheet" href="../css/sq2bs.css">
|
||||
<link rel="stylesheet" href="../css/sidebar.css">
|
||||
|
@ -34,6 +34,8 @@
|
|||
<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://nori.fish/wynn/build/" target = "_blank"><img src = "../media/icons/new/nori_build.png" alt = "Build Search" title = "Build Search by Nori-Wynn"><b>Build Search</b></a>
|
||||
<a href = "https://nori.fish/wynn/recipe/" target = "_blank"><img src = "../media/icons/new/nori_recipe.png" alt = "Recipe Search" title = "Recipe Search by Nori-Wynn"><b>Recipe Search</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>
|
||||
<div id="mobile-navbar" class="navbar dark-5 dark-shadow fixed-top d-lg-none pb-0">
|
||||
|
@ -73,6 +75,14 @@
|
|||
<img src="../media/icons/new/reload.png" alt="" style="height: 100%;">
|
||||
<span>Swap Icon Style</span>
|
||||
</a>
|
||||
<a href="https://nori.fish/wynn/build/" class="w-100 mb-3 text-white" style="height: 5vh; text-decoration: none;">
|
||||
<img src="../media/icons/new/nori_build.png" alt="" style="height: 100%;">
|
||||
<span>Build Search</span>
|
||||
</a>
|
||||
<a href="https://nori.fish/wynn/recipe/" class="w-100 mb-3 text-white" style="height: 5vh; text-decoration: none;">
|
||||
<img src="../media/icons/new/nori_recipe.png" alt="" style="height: 100%;">
|
||||
<span>Recipe Search</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>
|
||||
|
@ -82,7 +92,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">
|
||||
|
@ -464,7 +474,7 @@
|
|||
War Scream
|
||||
</button>
|
||||
<button class="button-boost m-1 border-0 text-white dark-8u dark-shadow-sm" id="ragnarokkr-boost" onclick="update_boosts('ragnarokkr-boost')">
|
||||
Ragnarokkr (+30%)
|
||||
Ragnarokkr (+20%)
|
||||
</button>
|
||||
<button class="button-boost m-1 border-0 text-white dark-8u dark-shadow-sm" id="totem-boost" onclick="update_boosts('totem-boost')">
|
||||
Vengeful Spirit (+20%)
|
||||
|
@ -827,6 +837,30 @@
|
|||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-auto rounded">
|
||||
<div class="row h-100 dark-shadow rounded" id='lootrunTome1-dropdown'>
|
||||
<div class="col-auto g-0 rounded-end my-auto text-center scaled-item-icon" id="lootrunTome1-img-loc">
|
||||
<div id="lootrunTome1-img" class="img-fluid rounded tome-image"></div>
|
||||
</div>
|
||||
<div class="col-3">
|
||||
<div class="row row-cols-1 h-100 align-items-center">
|
||||
<div class="col scaled-font fw-bold gx-3">
|
||||
Lootrun
|
||||
</div>
|
||||
<div class="col scaled-font fw-bold gx-3">
|
||||
Tome
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col g-0 rounded">
|
||||
<div class="row row-cols-1 h-100 align-items-center">
|
||||
<div class="col d-flex justify-content-end">
|
||||
<input class="equipment-input border-dark text-light dark-10 rounded scaled-font form-control form-control-sm" id="lootrunTome1-choice" name="lootrunTome1-choice" placeholder="No Tome" value=""/>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class = "col dark-6 rounded-bottom my-3 my-xl-1" id = "atree-dropdown" style = "display:none;">
|
||||
|
@ -975,7 +1009,15 @@
|
|||
</div>
|
||||
</div>
|
||||
<div class = "col-lg-3 col-sm-6">
|
||||
|
||||
<div class = "row">
|
||||
Life Steal:
|
||||
</div>
|
||||
<div class = "row">
|
||||
<input type = "number" placeholder = "0" id="ls" name="ls" value="0" class="border-dark text-light dark-10 rounded scaled-font form-control form-control-sm"/>
|
||||
</div>
|
||||
<div class = "row" id = "ls-base">
|
||||
Original Value: 0
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class = "row big-title justify-content-center">
|
||||
|
@ -1297,8 +1339,8 @@
|
|||
</div>
|
||||
</div>
|
||||
|
||||
<script src="https://cdn.jsdelivr.net/npm/@tarekraafat/autocomplete.js@10.2.6/dist/autoComplete.min.js"></script>
|
||||
<script src="https://cdn.jsdelivr.net/npm/macy@2"></script>
|
||||
<script src="/thirdparty/autoComplete.min.js"></script>
|
||||
<script src="/thirdparty/macy@2"></script>
|
||||
<script type="text/javascript" src="../js/utils.js"></script>
|
||||
<script type="text/javascript" src="../js/build_utils.js"></script>
|
||||
<script type="text/javascript" src="../js/computation_graph.js"></script>
|
||||
|
@ -1320,5 +1362,11 @@
|
|||
<script type="text/javascript" src="../js/builder/builder_graph.js"></script>
|
||||
<script type="text/javascript" src="../js/builder/builder.js"></script>
|
||||
<!--script type="text/javascript" src="../js/builder/optimize.js"></script-->
|
||||
<!--div id="graph_body" style="max-width: 100%; height: 100vh">
|
||||
<button id="saveButton">JANKY Export SVG</button>
|
||||
<a id="saveLink">savelink</a>
|
||||
</div>
|
||||
<script src="https://d3js.org/d3.v7.js"></script>
|
||||
<script type="text/javascript" src="../js/debug/render_compute_graph.js"></script-->
|
||||
</body>
|
||||
</html>
|
||||
|
|
175328
clean.json
175328
clean.json
File diff suppressed because it is too large
Load diff
File diff suppressed because one or more lines are too long
|
@ -8,7 +8,7 @@
|
|||
|
||||
<meta name="viewport" content="width=device-width, initial-scale=.45, user-scalable=no">
|
||||
<link href="https://fonts.googleapis.com/css2?family=Nunito&display=swap" rel="stylesheet">
|
||||
<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.1.3/dist/css/bootstrap.min.css" rel="stylesheet" integrity="sha384-1BmE4kWBq78iYhFldvKuhfTAU6auU8tT94WrHftjDbrCEXSU1oBoqyl2QvZ6jIW3" crossorigin="anonymous">
|
||||
<link href="/thirdparty/bootstrap.min.css" rel="stylesheet" integrity="sha384-1BmE4kWBq78iYhFldvKuhfTAU6auU8tT94WrHftjDbrCEXSU1oBoqyl2QvZ6jIW3" crossorigin="anonymous">
|
||||
|
||||
<link rel="stylesheet" href="../css/sq2bs.css">
|
||||
<link rel="icon" href="../media/icons/new/crafter.png">
|
||||
|
|
|
@ -10,9 +10,9 @@
|
|||
<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://cdn.jsdelivr.net/npm/bootstrap@5.1.3/dist/css/bootstrap.min.css" rel="stylesheet" integrity="sha384-1BmE4kWBq78iYhFldvKuhfTAU6auU8tT94WrHftjDbrCEXSU1oBoqyl2QvZ6jIW3" crossorigin="anonymous">
|
||||
<link href="/thirdparty/bootstrap.min.css" rel="stylesheet" integrity="sha384-1BmE4kWBq78iYhFldvKuhfTAU6auU8tT94WrHftjDbrCEXSU1oBoqyl2QvZ6jIW3" crossorigin="anonymous">
|
||||
|
||||
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/@tarekraafat/autocomplete.js@10.2.6/dist/css/autoComplete.min.css">
|
||||
<link rel="stylesheet" href="/thirdparty/autoComplete.min.css">
|
||||
|
||||
|
||||
<link rel="stylesheet" href="../css/sq2bs.css">
|
||||
|
@ -29,6 +29,8 @@
|
|||
<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://nori.fish/wynn/build/" target = "_blank"><img src = "../media/icons/new/nori_build.png" alt = "Build Search" title = "Build Search by Nori-Wynn"><b>Build Search</b></a>
|
||||
<a href = "https://nori.fish/wynn/recipe/" target = "_blank"><img src = "../media/icons/new/nori_recipe.png" alt = "Recipe Search" title = "Recipe Search by Nori-Wynn"><b>Recipe Search</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>
|
||||
<div id="mobile-navbar" class="navbar dark-5 dark-shadow fixed-top d-lg-none pb-0">
|
||||
|
@ -68,6 +70,14 @@
|
|||
<img src="../media/icons/new/reload.png" alt="" style="height: 100%;">
|
||||
<span>Swap Icon Style</span>
|
||||
</a>
|
||||
<a href="https://nori.fish/wynn/build/" class="w-100 mb-3 text-white" style="height: 5vh; text-decoration: none;">
|
||||
<img src="../media/icons/new/nori_build.png" alt="" style="height: 100%;">
|
||||
<span>Build Search</span>
|
||||
</a>
|
||||
<a href="https://nori.fish/wynn/recipe/" class="w-100 mb-3 text-white" style="height: 5vh; text-decoration: none;">
|
||||
<img src="../media/icons/new/nori_recipe.png" alt="" style="height: 100%;">
|
||||
<span>Recipe Search</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>
|
||||
|
|
1
created a new file lmao.txt
Normal file
1
created a new file lmao.txt
Normal file
|
@ -0,0 +1 @@
|
|||
wrote some stuff in the file
|
|
@ -17,6 +17,7 @@ Additional Contributors, in no particular order:
|
|||
- lemonalade (ability tree pdf for us to copy from :) )
|
||||
- Lennon (Skill point formula reversing)
|
||||
- Phanta (WynnAtlas custom expression parser / item search)
|
||||
- RawFish (and WIM team) (wynn api shenanigans, major IDs, misc.)
|
||||
- nbcss (and WIM team) (Crafted Item mechanics reverse engineering, testing)
|
||||
- dr_carlos (Hiding UI elements properly, fade animations, proper error handling)
|
||||
- Atlas Inc discord (feedback, ideas, damage calc, etc)
|
||||
|
|
|
@ -16,41 +16,49 @@
|
|||
|
||||
/* rarity selectors */
|
||||
|
||||
#rarity-box {
|
||||
#tier-box {
|
||||
cursor: pointer;
|
||||
width: 58.33%;
|
||||
text-align: center;
|
||||
}
|
||||
#rarity-box > div {
|
||||
#tier-box > div {
|
||||
width: calc(100% / 7);
|
||||
aspect-ratio: 1/1;
|
||||
position: relative;
|
||||
display: inline-block;
|
||||
}
|
||||
#rarity-box > div > b {
|
||||
#tier-box > div > b {
|
||||
position: absolute;
|
||||
top: 50%;
|
||||
left: 50%;
|
||||
transform: translate(-50%, -50%);
|
||||
}
|
||||
#rarity-box > div.rarity-selected > b {
|
||||
#tier-box > div.tier-selected > b {
|
||||
color: black;
|
||||
}
|
||||
|
||||
#rarity-normal { color: #FFFFFF; }
|
||||
#rarity-normal.rarity-selected { background-color: #FFFFFF; }
|
||||
#rarity-unique { color: #FFFF55; }
|
||||
#rarity-unique.rarity-selected { background-color: #FFFF55; }
|
||||
#rarity-set { color: #55FF55; }
|
||||
#rarity-set.rarity-selected { background-color: #55FF55; }
|
||||
#rarity-rare { color: #FF55FF; }
|
||||
#rarity-rare.rarity-selected { background-color: #FF55FF; }
|
||||
#rarity-legendary { color: #55FFFF; }
|
||||
#rarity-legendary.rarity-selected { background-color: #55FFFF; }
|
||||
#rarity-fabled { color: #FF5555; }
|
||||
#rarity-fabled.rarity-selected { background-color: #FF5555; }
|
||||
#rarity-mythic { color: #AA00AA; }
|
||||
#rarity-mythic.rarity-selected { background-color: #AA00AA; }
|
||||
#tier-normal { color: #FFFFFF; }
|
||||
#tier-normal.tier-selected { background-color: #FFFFFF; }
|
||||
#tier-unique { color: #FFFF55; }
|
||||
#tier-unique.tier-selected { background-color: #FFFF55; }
|
||||
#tier-set { color: #55FF55; }
|
||||
#tier-set.tier-selected { background-color: #55FF55; }
|
||||
#tier-rare { color: #FF55FF; }
|
||||
#tier-rare.tier-selected { background-color: #FF55FF; }
|
||||
#tier-legendary { color: #55FFFF; }
|
||||
#tier-legendary.tier-selected { background-color: #55FFFF; }
|
||||
#tier-fabled { color: #FF5555; }
|
||||
#tier-fabled.tier-selected { background-color: #FF5555; }
|
||||
#tier-mythic { color: #AA00AA; }
|
||||
#tier-mythic.tier-selected { background-color: #AA00AA; }
|
||||
|
||||
#tier-zero { color: #FFFFFF; }
|
||||
#tier-zero.tier-selected { background-color: #FFFFFF; }
|
||||
#tier-one { color: #FFFFBB; }
|
||||
#tier-one.tier-selected { background-color: #FFFFBB; }
|
||||
#tier-two { color: #FFFF88; }
|
||||
#tier-two.tier-selected { background-color: #FFFF88; }
|
||||
#tier-three { color: #FFFF55; }
|
||||
#tier-three.tier-selected { background-color: #FFFF55; }
|
||||
|
||||
/* filters */
|
||||
.filter-row {
|
|
@ -10,9 +10,9 @@
|
|||
<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://cdn.jsdelivr.net/npm/bootstrap@5.1.3/dist/css/bootstrap.min.css" rel="stylesheet" integrity="sha384-1BmE4kWBq78iYhFldvKuhfTAU6auU8tT94WrHftjDbrCEXSU1oBoqyl2QvZ6jIW3" crossorigin="anonymous">
|
||||
<link href="/thirdparty/bootstrap.min.css" rel="stylesheet" integrity="sha384-1BmE4kWBq78iYhFldvKuhfTAU6auU8tT94WrHftjDbrCEXSU1oBoqyl2QvZ6jIW3" crossorigin="anonymous">
|
||||
|
||||
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/@tarekraafat/autocomplete.js@10.2.6/dist/css/autoComplete.min.css">
|
||||
<link rel="stylesheet" href="/thirdparty/autoComplete.min.css">
|
||||
|
||||
|
||||
<link rel="stylesheet" href="../css/sq2bs.css">
|
||||
|
@ -31,6 +31,8 @@
|
|||
<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://nori.fish/wynn/build/" target = "_blank"><img src = "../media/icons/new/nori_build.png" alt = "Build Search" title = "Build Search by Nori-Wynn"><b>Build Search</b></a>
|
||||
<a href = "https://nori.fish/wynn/recipe/" target = "_blank"><img src = "../media/icons/new/nori_recipe.png" alt = "Recipe Search" title = "Recipe Search by Nori-Wynn"><b>Recipe Search</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>
|
||||
<div id="mobile-navbar" class="navbar dark-5 dark-shadow fixed-top d-lg-none pb-0">
|
||||
|
@ -70,6 +72,14 @@
|
|||
<img src="../media/icons/new/reload.png" alt="" style="height: 100%;">
|
||||
<span>Swap Icon Style</span>
|
||||
</a>
|
||||
<a href="https://nori.fish/wynn/build/" class="w-100 mb-3 text-white" style="height: 5vh; text-decoration: none;">
|
||||
<img src="../media/icons/new/nori_build.png" alt="" style="height: 100%;">
|
||||
<span>Build Search</span>
|
||||
</a>
|
||||
<a href="https://nori.fish/wynn/recipe/" class="w-100 mb-3 text-white" style="height: 5vh; text-decoration: none;">
|
||||
<img src="../media/icons/new/nori_recipe.png" alt="" style="height: 100%;">
|
||||
<span>Recipe Search</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>
|
||||
|
|
|
@ -8,7 +8,7 @@
|
|||
|
||||
<meta name="viewport" content="width=device-width, initial-scale=.45, user-scalable=no">
|
||||
<link href="https://fonts.googleapis.com/css2?family=Nunito&display=swap" rel="stylesheet">
|
||||
<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.1.3/dist/css/bootstrap.min.css" rel="stylesheet" integrity="sha384-1BmE4kWBq78iYhFldvKuhfTAU6auU8tT94WrHftjDbrCEXSU1oBoqyl2QvZ6jIW3" crossorigin="anonymous">
|
||||
<link href="/thirdparty/bootstrap.min.css" rel="stylesheet" integrity="sha384-1BmE4kWBq78iYhFldvKuhfTAU6auU8tT94WrHftjDbrCEXSU1oBoqyl2QvZ6jIW3" crossorigin="anonymous">
|
||||
|
||||
<link rel="stylesheet" href="../css/sq2bs.css">
|
||||
<link rel="icon" href="../media/icons/new/crafter.png">
|
||||
|
|
1
data/2.0.1.1/majid.json
Normal file
1
data/2.0.1.1/majid.json
Normal file
|
@ -0,0 +1 @@
|
|||
{"MAGNET":{"displayName":"Magnet","description":"Pulls items within an 8 block radius towards you","abilities":[]},"PLAGUE":{"displayName":"Plague","description":"Poisoned mobs spread their poison to nearby mobs","abilities":[]},"HAWKEYE":{"displayName":"Hawkeye","description":"Condense Arrow Storm into a tight beam. Arrows deal ✤10%, ✦1%, and ❋1%","abilities":[{"class":"Archer","base_abil":7,"effects":[{"type":"add_spell_prop","base_spell":1,"target_part":"Single Stream","behavior":"overwrite","hits":{"Single Arrow":5}},{"type":"add_spell_prop","base_spell":1,"target_part":"Single Arrow","behavior":"overwrite","multipliers":[10,0,1,0,0,1]},{"type":"add_spell_prop","base_spell":1,"target_part":"Total Damage","behavior":"modify","hits":{"Single Stream":4}}]}]},"GREED":{"displayName":"Greed","description":"Picking up emeralds heals you and nearby players for 15% max health","abilities":[]},"CAVALRYMAN":{"displayName":"Cavalryman","description":"You may cast spells and attack with a 70% damage penalty while on a horse","abilities":[]},"GUARDIAN":{"displayName":"Guardian","description":"20% of the damage taken by nearby allies is redirected to you","abilities":[]},"HERO":{"displayName":"Saviour’s Sacrifice","description":"While under 50% maximum health, nearby allies gain 30% bonus damage and defense","abilities":[]},"ALTRUISM":{"displayName":"Heart of the Pack","description":"Nearby players gain 35% of the health you naturally regenerate","abilities":[]},"ARCANES":{"displayName":"Transcendence","description":"30% chance for spells to cost no mana when casted","abilities":[]},"ENTROPY":{"displayName":"Entropy","description":"Meteor falls three times faster","abilities":[]},"ROVINGASSASSIN":{"displayName":"Roving Assassin","description":"Vanish no longer drains mana while invisible","abilities":[]},"MADNESS":{"displayName":"Madness","description":"Cast a random ability every 3 seconds","abilities":[]},"LIGHTWEIGHT":{"displayName":"Lightweight","description":"You no longer take fall damage","abilities":[]},"SORCERY":{"displayName":"Sorcery","description":"30% chance for spells and attacks to cast a second time at no additional cost","abilities":[]},"TAUNT":{"displayName":"Taunt","description":"Mobs within 12 blocks target you upon casting War Scream","abilities":[]},"RALLY":{"displayName":"Rally","description":"Charge heals you by 10% and nearby allies by 15% on impact, but becomes harmless","abilities":[{"class":"Warrior","base_abil":4,"effects":[{"type":"add_spell_prop","base_spell":2,"display":"Rally Self Heal","target_part":"Rally Self Heal","power":0.1},{"type":"add_spell_prop","base_spell":2,"target_part":"Rally Ally Heal","power":0.15},{"type":"raw_stat","bonuses":[{"type":"stat","name":"damMult.Rally:2.Flying Kick","value":-100},{"type":"stat","name":"damMult.Rally:2.Collide","value":-100},{"type":"stat","name":"damMult.Rally:2.Heavy Impact","value":-100},{"type":"stat","name":"damMult.Rally:2.Flyby Jab","value":-100}]}]}]},"CHERRY_BOMBS":{"displayName":"Cherry Bombs","description":"Your Smoke Bombs explode instantly, and increase their Neutral Damage by +90%","abilities":[{"class":"Assassin","base_abil":7,"effects":[{"type":"add_spell_prop","base_spell":4,"target_part":"Per Tick","multipliers":[90,0,0,0,0,0]},{"type":"add_spell_prop","base_spell":4,"target_part":"Per Bomb","hits":{"Per Tick":-9}}]}]},"FREERUNNER":{"displayName":"Freerunner","description":"Double your sprint speed when your sprint bar is under 30%","abilities":[]},"PEACEFUL_EFFIGY":{"displayName":"Peaceful Effigy","description":"Your totem will last twice as long","abilities":[]},"FURIOUS_EFFIGY":{"displayName":"Furious Effigy","description":"Totem effects are twice as fast, but duration is halved","abilities":[{"class":"Shaman","base_abil":0,"properties":{"rate":-0.2,"totem_mul":2.5},"effects":[]}]},"FLASHFREEZE":{"displayName":"Flashfreeze","description":"Ice Snake is instant but has a reduced range","abilities":[]},"GRAVITYWELL":{"displayName":"Gravity Well","description":"Meteor has increased blast radius and pulls enemies instead","abilities":[]},"DESC_SNOWYSTEPS":{"displayName":"Snowy Steps","description":"Leaves a trail of snow behind you","abilities":[]},"GEOCENTRISM":{"displayName":"Geocentrism","description":"Aura radiates from you instead of your totem and can be cast anytime","abilities":[]},"DESC_FESTIVESPIRIT":{"displayName":"Festive Spirits","description":"Plays wintery tunes","abilities":[]}}
|
1
data/2.0.1.1/recipes.json
Normal file
1
data/2.0.1.1/recipes.json
Normal file
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
1
data/2.0.1.2/majid.json
Normal file
1
data/2.0.1.2/majid.json
Normal file
|
@ -0,0 +1 @@
|
|||
{"MAGNET":{"displayName":"Magnet","description":"Pulls items within an 8 block radius towards you","abilities":[]},"PLAGUE":{"displayName":"Plague","description":"Poisoned mobs spread their poison to nearby mobs","abilities":[]},"HAWKEYE":{"displayName":"Hawkeye","description":"Condense Arrow Storm into a tight beam. Arrows deal ✤10%, ✦1%, and ❋1%","abilities":[{"class":"Archer","base_abil":7,"effects":[{"type":"add_spell_prop","base_spell":1,"target_part":"Single Stream","behavior":"overwrite","hits":{"Single Arrow":5}},{"type":"add_spell_prop","base_spell":1,"target_part":"Single Arrow","behavior":"overwrite","multipliers":[10,0,1,0,0,1]},{"type":"add_spell_prop","base_spell":1,"target_part":"Total Damage","behavior":"modify","hits":{"Single Stream":4}}]}]},"GREED":{"displayName":"Greed","description":"Picking up emeralds heals you and nearby players for 15% max health","abilities":[]},"CAVALRYMAN":{"displayName":"Cavalryman","description":"You may cast spells and attack with a 70% damage penalty while on a horse","abilities":[]},"GUARDIAN":{"displayName":"Guardian","description":"20% of the damage taken by nearby allies is redirected to you","abilities":[]},"HERO":{"displayName":"Saviour’s Sacrifice","description":"While under 50% maximum health, nearby allies gain 30% bonus damage and defense","abilities":[]},"ALTRUISM":{"displayName":"Heart of the Pack","description":"Nearby players gain 35% of the health you naturally regenerate","abilities":[]},"ARCANES":{"displayName":"Transcendence","description":"30% chance for spells to cost no mana when casted","abilities":[]},"ENTROPY":{"displayName":"Entropy","description":"Meteor falls three times faster","abilities":[]},"ROVINGASSASSIN":{"displayName":"Roving Assassin","description":"Vanish no longer drains mana while invisible","abilities":[]},"MADNESS":{"displayName":"Madness","description":"Cast a random ability every 3 seconds","abilities":[]},"LIGHTWEIGHT":{"displayName":"Lightweight","description":"You no longer take fall damage","abilities":[]},"SORCERY":{"displayName":"Sorcery","description":"30% chance for spells and attacks to cast a second time at no additional cost","abilities":[]},"TAUNT":{"displayName":"Taunt","description":"Mobs within 12 blocks target you upon casting War Scream","abilities":[]},"RALLY":{"displayName":"Rally","description":"Charge heals you by 10% and nearby allies by 15% on impact, but becomes harmless","abilities":[{"class":"Warrior","base_abil":4,"effects":[{"type":"add_spell_prop","base_spell":2,"display":"Rally Self Heal","target_part":"Rally Self Heal","power":0.1},{"type":"add_spell_prop","base_spell":2,"target_part":"Rally Ally Heal","power":0.15},{"type":"raw_stat","bonuses":[{"type":"stat","name":"damMult.Rally:2.Flying Kick","value":-100},{"type":"stat","name":"damMult.Rally:2.Collide","value":-100},{"type":"stat","name":"damMult.Rally:2.Heavy Impact","value":-100},{"type":"stat","name":"damMult.Rally:2.Flyby Jab","value":-100}]}]}]},"CHERRY_BOMBS":{"displayName":"Cherry Bombs","description":"Your Smoke Bombs explode instantly, and increase their Neutral Damage by +90%","abilities":[{"class":"Assassin","base_abil":7,"effects":[{"type":"add_spell_prop","base_spell":4,"target_part":"Per Tick","multipliers":[90,0,0,0,0,0]},{"type":"add_spell_prop","base_spell":4,"target_part":"Per Bomb","hits":{"Per Tick":-9}}]}]},"FREERUNNER":{"displayName":"Freerunner","description":"Double your sprint speed when your sprint bar is under 30%","abilities":[]},"PEACEFUL_EFFIGY":{"displayName":"Peaceful Effigy","description":"Your totem will last twice as long","abilities":[]},"FURIOUS_EFFIGY":{"displayName":"Furious Effigy","description":"Totem effects are twice as fast, but duration is halved","abilities":[{"class":"Shaman","base_abil":0,"properties":{"rate":-0.2,"totem_mul":2.5},"effects":[]}]},"FLASHFREEZE":{"displayName":"Flashfreeze","description":"Ice Snake is instant but has a reduced range","abilities":[]},"GRAVITYWELL":{"displayName":"Gravity Well","description":"Meteor has increased blast radius and pulls enemies instead","abilities":[]},"DESC_SNOWYSTEPS":{"displayName":"Snowy Steps","description":"Leaves a trail of snow behind you","abilities":[]},"GEOCENTRISM":{"displayName":"Geocentrism","description":"Aura radiates from you instead of your totem and can be cast anytime","abilities":[]},"DESC_FESTIVESPIRIT":{"displayName":"Festive Spirits","description":"Plays wintery tunes","abilities":[]}}
|
1
data/2.0.1.2/recipes.json
Normal file
1
data/2.0.1.2/recipes.json
Normal file
File diff suppressed because one or more lines are too long
1
data/2.0.2.1/atree.json
Normal file
1
data/2.0.2.1/atree.json
Normal file
File diff suppressed because one or more lines are too long
1
data/2.0.2.1/ingreds.json
Normal file
1
data/2.0.2.1/ingreds.json
Normal file
File diff suppressed because one or more lines are too long
1
data/2.0.2.1/items.json
Normal file
1
data/2.0.2.1/items.json
Normal file
File diff suppressed because one or more lines are too long
1
data/2.0.2.1/majid.json
Normal file
1
data/2.0.2.1/majid.json
Normal file
|
@ -0,0 +1 @@
|
|||
{"MAGNET":{"displayName":"Magnet","description":"Pulls items within an 8 block radius towards you","abilities":[]},"PLAGUE":{"displayName":"Plague","description":"Poisoned mobs spread their poison to nearby mobs","abilities":[]},"HAWKEYE":{"displayName":"Hawkeye","description":"Condense Arrow Storm into a tight beam. Arrows deal ✤10%, ✦1%, and ❋1%","abilities":[{"class":"Archer","base_abil":7,"effects":[{"type":"add_spell_prop","base_spell":1,"target_part":"Single Stream","behavior":"overwrite","hits":{"Single Arrow":5}},{"type":"add_spell_prop","base_spell":1,"target_part":"Single Arrow","behavior":"overwrite","multipliers":[10,0,1,0,0,1]},{"type":"add_spell_prop","base_spell":1,"target_part":"Total Damage","behavior":"modify","hits":{"Single Stream":4}}]}]},"GREED":{"displayName":"Greed","description":"Picking up emeralds heals you and nearby players for 15% max health","abilities":[]},"CAVALRYMAN":{"displayName":"Cavalryman","description":"You may cast spells and attack with a 70% damage penalty while on a horse","abilities":[]},"GUARDIAN":{"displayName":"Guardian","description":"20% of the damage taken by nearby allies is redirected to you","abilities":[]},"HERO":{"displayName":"Saviour’s Sacrifice","description":"While under 50% maximum health, nearby allies gain 30% bonus damage and defense","abilities":[]},"ALTRUISM":{"displayName":"Heart of the Pack","description":"Nearby players gain 35% of the health you naturally regenerate","abilities":[]},"ARCANES":{"displayName":"Transcendence","description":"30% chance for spells to cost no mana when casted","abilities":[]},"ENTROPY":{"displayName":"Entropy","description":"Meteor falls three times faster","abilities":[]},"ROVINGASSASSIN":{"displayName":"Roving Assassin","description":"Vanish no longer drains mana while invisible","abilities":[]},"MADNESS":{"displayName":"Madness","description":"Cast a random ability every 3 seconds","abilities":[]},"LIGHTWEIGHT":{"displayName":"Lightweight","description":"You no longer take fall damage","abilities":[]},"SORCERY":{"displayName":"Sorcery","description":"30% chance for spells and attacks to cast a second time at no additional cost","abilities":[]},"TAUNT":{"displayName":"Taunt","description":"Mobs within 12 blocks target you upon casting War Scream","abilities":[]},"RALLY":{"displayName":"Rally","description":"Charge heals you by 10% and nearby allies by 15% on impact, but becomes harmless","abilities":[{"class":"Warrior","base_abil":4,"effects":[{"type":"add_spell_prop","base_spell":2,"display":"Rally Self Heal","target_part":"Rally Self Heal","power":0.1},{"type":"add_spell_prop","base_spell":2,"target_part":"Rally Ally Heal","power":0.15},{"type":"raw_stat","bonuses":[{"type":"stat","name":"damMult.Rally:2.Flying Kick","value":-100},{"type":"stat","name":"damMult.Rally:2.Collide","value":-100},{"type":"stat","name":"damMult.Rally:2.Heavy Impact","value":-100},{"type":"stat","name":"damMult.Rally:2.Flyby Jab","value":-100}]}]}]},"CHERRY_BOMBS":{"displayName":"Cherry Bombs","description":"Your Smoke Bombs explode instantly, and increase their Neutral Damage by +90%","abilities":[{"class":"Assassin","base_abil":7,"effects":[{"type":"add_spell_prop","base_spell":4,"target_part":"Per Tick","multipliers":[90,0,0,0,0,0]},{"type":"add_spell_prop","base_spell":4,"target_part":"Per Bomb","hits":{"Per Tick":-9}}]}]},"FREERUNNER":{"displayName":"Freerunner","description":"Double your sprint speed when your sprint bar is under 30%","abilities":[]},"PEACEFUL_EFFIGY":{"displayName":"Peaceful Effigy","description":"Your totem will last twice as long","abilities":[]},"FURIOUS_EFFIGY":{"displayName":"Furious Effigy","description":"Totem effects are twice as fast, but duration is halved","abilities":[{"class":"Shaman","base_abil":0,"properties":{"rate":-0.2,"totem_mul":2.5},"effects":[]}]},"FLASHFREEZE":{"displayName":"Flashfreeze","description":"Ice Snake is instant but has a reduced range","abilities":[]},"GRAVITYWELL":{"displayName":"Gravity Well","description":"Meteor has increased blast radius and pulls enemies instead","abilities":[]},"DESC_SNOWYSTEPS":{"displayName":"Snowy Steps","description":"Leaves a trail of snow behind you","abilities":[]},"GEOCENTRISM":{"displayName":"Geocentrism","description":"Aura radiates from you instead of your totem and can be cast anytime","abilities":[]},"DESC_FESTIVESPIRIT":{"displayName":"Festive Spirits","description":"Plays wintery tunes","abilities":[]}}
|
1
data/2.0.2.1/recipes.json
Normal file
1
data/2.0.2.1/recipes.json
Normal file
File diff suppressed because one or more lines are too long
1069
data/2.0.2.1/tomes.json
Normal file
1069
data/2.0.2.1/tomes.json
Normal file
File diff suppressed because it is too large
Load diff
1
data/2.0.2.3/atree.json
Normal file
1
data/2.0.2.3/atree.json
Normal file
File diff suppressed because one or more lines are too long
1
data/2.0.2.3/ingreds.json
Normal file
1
data/2.0.2.3/ingreds.json
Normal file
File diff suppressed because one or more lines are too long
1
data/2.0.2.3/items.json
Normal file
1
data/2.0.2.3/items.json
Normal file
File diff suppressed because one or more lines are too long
1
data/2.0.2.3/majid.json
Normal file
1
data/2.0.2.3/majid.json
Normal file
|
@ -0,0 +1 @@
|
|||
{"MAGNET":{"displayName":"Magnet","description":"Pulls items within an 8 block radius towards you","abilities":[]},"PLAGUE":{"displayName":"Plague","description":"Poisoned mobs spread their poison to nearby mobs","abilities":[]},"HAWKEYE":{"displayName":"Hawkeye","description":"Condense Arrow Storm into a tight beam. Arrows deal ✤10%, ✦1%, and ❋1%","abilities":[{"class":"Archer","base_abil":7,"effects":[{"type":"add_spell_prop","base_spell":1,"target_part":"Single Stream","behavior":"overwrite","hits":{"Single Arrow":5}},{"type":"add_spell_prop","base_spell":1,"target_part":"Single Arrow","behavior":"overwrite","multipliers":[10,0,1,0,0,1]},{"type":"add_spell_prop","base_spell":1,"target_part":"Total Damage","behavior":"modify","hits":{"Single Stream":4}}]}]},"GREED":{"displayName":"Greed","description":"Picking up emeralds heals you and nearby players for 15% max health","abilities":[]},"CAVALRYMAN":{"displayName":"Cavalryman","description":"You may cast spells and attack with a 70% damage penalty while on a horse","abilities":[]},"GUARDIAN":{"displayName":"Guardian","description":"20% of the damage taken by nearby allies is redirected to you","abilities":[]},"HERO":{"displayName":"Saviour’s Sacrifice","description":"While under 50% maximum health, nearby allies gain 30% bonus damage and defense","abilities":[]},"ALTRUISM":{"displayName":"Heart of the Pack","description":"Nearby players gain 35% of the health you naturally regenerate","abilities":[]},"ARCANES":{"displayName":"Transcendence","description":"30% chance for spells to cost no mana when casted","abilities":[]},"ENTROPY":{"displayName":"Entropy","description":"Meteor falls three times faster","abilities":[]},"ROVINGASSASSIN":{"displayName":"Roving Assassin","description":"Vanish no longer drains mana while invisible","abilities":[]},"MADNESS":{"displayName":"Madness","description":"Cast a random ability every 3 seconds","abilities":[]},"LIGHTWEIGHT":{"displayName":"Lightweight","description":"You no longer take fall damage","abilities":[]},"SORCERY":{"displayName":"Sorcery","description":"30% chance for spells and attacks to cast a second time at no additional cost","abilities":[]},"TAUNT":{"displayName":"Taunt","description":"Mobs within 12 blocks target you upon casting War Scream","abilities":[]},"RALLY":{"displayName":"Rally","description":"Charge heals you by 10% and nearby allies by 15% on impact, but becomes harmless","abilities":[{"class":"Warrior","base_abil":4,"effects":[{"type":"add_spell_prop","base_spell":2,"display":"Rally Self Heal","target_part":"Rally Self Heal","power":0.1},{"type":"add_spell_prop","base_spell":2,"target_part":"Rally Ally Heal","power":0.15},{"type":"raw_stat","bonuses":[{"type":"stat","name":"damMult.Rally:2.Flying Kick","value":-100},{"type":"stat","name":"damMult.Rally:2.Collide","value":-100},{"type":"stat","name":"damMult.Rally:2.Heavy Impact","value":-100},{"type":"stat","name":"damMult.Rally:2.Flyby Jab","value":-100}]}]}]},"CHERRY_BOMBS":{"displayName":"Cherry Bombs","description":"Your Smoke Bombs explode instantly, and increase their Neutral Damage by +90%","abilities":[{"class":"Assassin","base_abil":7,"effects":[{"type":"add_spell_prop","base_spell":4,"target_part":"Per Tick","multipliers":[90,0,0,0,0,0]},{"type":"add_spell_prop","base_spell":4,"target_part":"Per Bomb","hits":{"Per Tick":-9}}]}]},"FREERUNNER":{"displayName":"Freerunner","description":"Double your sprint speed when your sprint bar is under 30%","abilities":[]},"PEACEFUL_EFFIGY":{"displayName":"Peaceful Effigy","description":"Your totem will last twice as long","abilities":[]},"FURIOUS_EFFIGY":{"displayName":"Furious Effigy","description":"Totem effects are twice as fast, but duration is halved","abilities":[{"class":"Shaman","base_abil":0,"properties":{"rate":-0.2,"totem_mul":2.5},"effects":[]}]},"FLASHFREEZE":{"displayName":"Flashfreeze","description":"Ice Snake is instant but has a reduced range","abilities":[]},"GRAVITYWELL":{"displayName":"Gravity Well","description":"Meteor has increased blast radius and pulls enemies instead","abilities":[]},"DESC_SNOWYSTEPS":{"displayName":"Snowy Steps","description":"Leaves a trail of snow behind you","abilities":[]},"GEOCENTRISM":{"displayName":"Geocentrism","description":"Aura radiates from you instead of your totem and can be cast anytime","abilities":[]},"DESC_FESTIVESPIRIT":{"displayName":"Festive Spirits","description":"Plays wintery tunes","abilities":[]}}
|
1
data/2.0.2.3/recipes.json
Normal file
1
data/2.0.2.3/recipes.json
Normal file
File diff suppressed because one or more lines are too long
1069
data/2.0.2.3/tomes.json
Normal file
1069
data/2.0.2.3/tomes.json
Normal file
File diff suppressed because it is too large
Load diff
1
data/2.0.3.1/atree.json
Normal file
1
data/2.0.3.1/atree.json
Normal file
File diff suppressed because one or more lines are too long
1
data/2.0.3.1/ingreds.json
Normal file
1
data/2.0.3.1/ingreds.json
Normal file
File diff suppressed because one or more lines are too long
1
data/2.0.3.1/items.json
Normal file
1
data/2.0.3.1/items.json
Normal file
File diff suppressed because one or more lines are too long
1
data/2.0.3.1/majid.json
Normal file
1
data/2.0.3.1/majid.json
Normal file
File diff suppressed because one or more lines are too long
1
data/2.0.3.1/recipes.json
Normal file
1
data/2.0.3.1/recipes.json
Normal file
File diff suppressed because one or more lines are too long
1069
data/2.0.3.1/tomes.json
Normal file
1069
data/2.0.3.1/tomes.json
Normal file
File diff suppressed because it is too large
Load diff
1
data/2.0.4.1/atree.json
Normal file
1
data/2.0.4.1/atree.json
Normal file
File diff suppressed because one or more lines are too long
1
data/2.0.4.1/ingreds.json
Normal file
1
data/2.0.4.1/ingreds.json
Normal file
File diff suppressed because one or more lines are too long
1
data/2.0.4.1/items.json
Normal file
1
data/2.0.4.1/items.json
Normal file
File diff suppressed because one or more lines are too long
1
data/2.0.4.1/majid.json
Normal file
1
data/2.0.4.1/majid.json
Normal file
File diff suppressed because one or more lines are too long
1
data/2.0.4.1/recipes.json
Normal file
1
data/2.0.4.1/recipes.json
Normal file
File diff suppressed because one or more lines are too long
1069
data/2.0.4.1/tomes.json
Normal file
1069
data/2.0.4.1/tomes.json
Normal file
File diff suppressed because it is too large
Load diff
1
data/2.0.4.3/atree.json
Normal file
1
data/2.0.4.3/atree.json
Normal file
File diff suppressed because one or more lines are too long
1
data/2.0.4.3/ingreds.json
Normal file
1
data/2.0.4.3/ingreds.json
Normal file
File diff suppressed because one or more lines are too long
1
data/2.0.4.3/items.json
Normal file
1
data/2.0.4.3/items.json
Normal file
File diff suppressed because one or more lines are too long
1
data/2.0.4.3/majid.json
Normal file
1
data/2.0.4.3/majid.json
Normal file
File diff suppressed because one or more lines are too long
1
data/2.0.4.3/recipes.json
Normal file
1
data/2.0.4.3/recipes.json
Normal file
File diff suppressed because one or more lines are too long
1069
data/2.0.4.3/tomes.json
Normal file
1069
data/2.0.4.3/tomes.json
Normal file
File diff suppressed because it is too large
Load diff
1
data/2.0.4.4/atree.json
Normal file
1
data/2.0.4.4/atree.json
Normal file
File diff suppressed because one or more lines are too long
1
data/2.0.4.4/ingreds.json
Normal file
1
data/2.0.4.4/ingreds.json
Normal file
File diff suppressed because one or more lines are too long
1
data/2.0.4.4/items.json
Normal file
1
data/2.0.4.4/items.json
Normal file
File diff suppressed because one or more lines are too long
1
data/2.0.4.4/majid.json
Normal file
1
data/2.0.4.4/majid.json
Normal file
File diff suppressed because one or more lines are too long
1
data/2.0.4.4/recipes.json
Normal file
1
data/2.0.4.4/recipes.json
Normal file
File diff suppressed because one or more lines are too long
1
data/2.0.4.4/tomes.json
Normal file
1
data/2.0.4.4/tomes.json
Normal file
File diff suppressed because one or more lines are too long
1
data/2.1.0.0/atree.json
Normal file
1
data/2.1.0.0/atree.json
Normal file
File diff suppressed because one or more lines are too long
1
data/2.1.0.0/compress.json
Normal file
1
data/2.1.0.0/compress.json
Normal file
File diff suppressed because one or more lines are too long
1
data/2.1.0.0/ingreds.json
Normal file
1
data/2.1.0.0/ingreds.json
Normal file
File diff suppressed because one or more lines are too long
1
data/2.1.0.0/items.json
Normal file
1
data/2.1.0.0/items.json
Normal file
File diff suppressed because one or more lines are too long
1
data/2.1.0.0/majid.json
Normal file
1
data/2.1.0.0/majid.json
Normal file
File diff suppressed because one or more lines are too long
1
data/2.1.0.0/recipes.json
Normal file
1
data/2.1.0.0/recipes.json
Normal file
File diff suppressed because one or more lines are too long
1
data/2.1.0.0/tomes.json
Normal file
1
data/2.1.0.0/tomes.json
Normal file
File diff suppressed because one or more lines are too long
0
dev/builder_colorcode.png
Executable file → Normal file
0
dev/builder_colorcode.png
Executable file → Normal file
Before Width: | Height: | Size: 178 KiB After Width: | Height: | Size: 178 KiB |
0
dev/compute_graph.svg
Executable file → Normal file
0
dev/compute_graph.svg
Executable file → Normal file
Before Width: | Height: | Size: 63 KiB After Width: | Height: | Size: 63 KiB |
|
@ -14,11 +14,11 @@
|
|||
<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="https://cdn.jsdelivr.net/npm/bootstrap@5.1.3/dist/css/bootstrap.min.css" rel="stylesheet"
|
||||
<link href="/thirdparty/bootstrap.min.css" rel="stylesheet"
|
||||
integrity="sha384-1BmE4kWBq78iYhFldvKuhfTAU6auU8tT94WrHftjDbrCEXSU1oBoqyl2QvZ6jIW3" crossorigin="anonymous">
|
||||
|
||||
<link rel="stylesheet"
|
||||
href="https://cdn.jsdelivr.net/npm/@tarekraafat/autocomplete.js@10.2.6/dist/css/autoComplete.min.css">
|
||||
href="/thirdparty/autoComplete.min.css">
|
||||
|
||||
|
||||
<link rel="stylesheet" href="../css/sq2bs.css">
|
||||
|
@ -43,6 +43,8 @@
|
|||
<a href="" 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://nori.fish/wynn/build/" target = "_blank"><img src = "../media/icons/new/nori_build.png" alt = "Build Search" title = "Build Search by Nori-Wynn"><b>Build Search</b></a>
|
||||
<a href = "https://nori.fish/wynn/recipe/" target = "_blank"><img src = "../media/icons/new/nori_recipe.png" alt = "Recipe Search" title = "Recipe Search by Nori-Wynn"><b>Recipe Search</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>
|
||||
<div class="container text-light px-5 scaled-font">
|
||||
|
|
|
@ -8,7 +8,7 @@
|
|||
|
||||
<meta name="viewport" content="width=device-width, initial-scale=.45, user-scalable=no">
|
||||
<link href="https://fonts.googleapis.com/css2?family=Nunito&display=swap" rel="stylesheet">
|
||||
<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.1.3/dist/css/bootstrap.min.css" rel="stylesheet" integrity="sha384-1BmE4kWBq78iYhFldvKuhfTAU6auU8tT94WrHftjDbrCEXSU1oBoqyl2QvZ6jIW3" crossorigin="anonymous">
|
||||
<link href="/thirdparty/bootstrap.min.css" rel="stylesheet" integrity="sha384-1BmE4kWBq78iYhFldvKuhfTAU6auU8tT94WrHftjDbrCEXSU1oBoqyl2QvZ6jIW3" crossorigin="anonymous">
|
||||
|
||||
<link rel="stylesheet" href="../css/sq2bs.css">
|
||||
<link rel="icon" href="../media/icons/new/builder.png">
|
||||
|
|
184
ingredients/index.html
Normal file
184
ingredients/index.html
Normal file
|
@ -0,0 +1,184 @@
|
|||
<!DOCTYPE html>
|
||||
<html scroll-behavior="smooth">
|
||||
<head>
|
||||
<title>WynnAtlas</title>
|
||||
<link rel="icon" href="../media/icons/new/searcher.png" type="image/icon type">
|
||||
|
||||
<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="/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/search.css">
|
||||
</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 = "../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://nori.fish/wynn/build/" target = "_blank"><img src = "../media/icons/new/nori_build.png" alt = "Build Search" title = "Build Search by Nori-Wynn"><b>Build Search</b></a>
|
||||
<a href = "https://nori.fish/wynn/recipe/" target = "_blank"><img src = "../media/icons/new/nori_recipe.png" alt = "Recipe Search" title = "Recipe Search by Nori-Wynn"><b>Recipe Search</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>
|
||||
<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;">
|
||||
<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://nori.fish/wynn/build/" class="w-100 mb-3 text-white" style="height: 5vh; text-decoration: none;">
|
||||
<img src="../media/icons/new/nori_build.png" alt="" style="height: 100%;">
|
||||
<span>Build Search</span>
|
||||
</a>
|
||||
<a href="https://nori.fish/wynn/recipe/" class="w-100 mb-3 text-white" style="height: 5vh; text-decoration: none;">
|
||||
<img src="../media/icons/new/nori_recipe.png" alt="" style="height: 100%;">
|
||||
<span>Recipe Search</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>
|
||||
<div class = "container py-5 vh-100 mx-0 mx-lg-auto scaled-font">
|
||||
<div class = "row">
|
||||
<div class = "row" style = "margin-top: 3ch;">
|
||||
<div class = "col text-start" id = "credits">
|
||||
<a href="../items/" class="link">Item Searching</a>
|
||||
</div>
|
||||
<div class = "col text-end">
|
||||
<a href = "../ingredients_adv/">Advanced Ingredient Search</a>
|
||||
</div>
|
||||
</div>
|
||||
<div class = "col-auto" style = "width: 12.5%;"></div>
|
||||
<div class = "col-lg-4">
|
||||
<div class = "row">
|
||||
<div class = "col-lg col-sm-12">
|
||||
<div class = "col fw-bold">Name:</div>
|
||||
<input class = "col border-dark text-light dark-5 rounded scaled-font form-control form-control-sm" style="width: 100%!important;" type="text" id="item-name-choice" name="item-name-choice" placeholder="Ingredient name (case insensitive)"/>
|
||||
<p class="error col-auto"></p>
|
||||
</div>
|
||||
</div>
|
||||
<div class = "row">
|
||||
<div class = "col-lg col-sm-12">
|
||||
<div class = "col"><span class = "fw-bold">Types:</span> <span style = "cursor: pointer; float: right;"><span id = "all-types">All</span> <span id = "none-types">None</span></span></div>
|
||||
<div id = "type-box">
|
||||
<p id = "type-armouring" style = "margin: 0; ">Armouring</p>
|
||||
<p id = "type-tailoring" style = "margin: 0;">Tailoring</p>
|
||||
<p id = "type-weaponsmithing" style = "margin: 0;">Weaponsmithing</p>
|
||||
<p id = "type-woodworking" style = "margin: 0;">Woodworking</p>
|
||||
<p id = "type-jeweling" style = "margin: 0;">Jeweling</p>
|
||||
<p id = "type-cooking" style = "margin: 0;">Cooking</p>
|
||||
<p id = "type-alchemism" style = "margin: 0;">Alchemism</p>
|
||||
<p id = "type-scribing" style = "margin: 0;">Scribing</p>
|
||||
</div>
|
||||
<p class="error col-auto"></p>
|
||||
</div>
|
||||
</div>
|
||||
<div class = "row">
|
||||
<div class = "col-lg col-sm-12">
|
||||
<div class = "col"><span class = "fw-bold">Stars:</span> <span style = "cursor: pointer; float: right;"><span id = "all-tiers">All</span> <span id = "none-tiers">None</span></span></div>
|
||||
<div id = "tier-box">
|
||||
<!-- unfortunately they must be stacked up like this because newlines are considered spaces and muck up the organization -->
|
||||
<div id = "tier-zero" class = "tier-selected"><b>0</b></div><div id = "tier-one" class = "tier-selected"><b>1</b></div><div id = "tier-two" class = "tier-selected"><b>2</b></div><div id = "tier-three" class = "tier-selected"><b>3</b></div>
|
||||
</div>
|
||||
<p class="error col-auto"></p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class = "col-lg-5">
|
||||
<div id = "filter-container" class = "col">
|
||||
<div class = "col fw-bold">Filters:</div>
|
||||
<div class = "row">
|
||||
<div id = "add-filter" class = "col fw-bold" style = "cursor: pointer; padding-top: 5px;">
|
||||
+ Add Filter
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<br/>
|
||||
<div id = "exclude-container" class = "col">
|
||||
<div class = "col fw-bold">Excluded Filters:</div>
|
||||
<div class = "row">
|
||||
<div id = "add-exclude" class = "col fw-bold" style = "cursor: pointer; padding-top: 5px;">
|
||||
+ Add Excluded Filter
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class = "row">
|
||||
<div class = "col-auto" style = "width: 12.5%;"></div>
|
||||
<div class = "col-auto">
|
||||
<button class = "button rounded scaled-font fw-bold text-light dark-5" id = "search-button" onclick = "do_item_search()">
|
||||
Search!
|
||||
</button>
|
||||
</div>
|
||||
<div class = "col-auto">
|
||||
<button class = "button rounded scaled-font fw-bold text-light dark-5" id = "reset-button" onclick = "reset_item_search()">
|
||||
Reset
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
<div class = "row box-title justify-content-center" id = "summary">
|
||||
</div>
|
||||
<div class = "row" id = "search-results">
|
||||
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<script src="/thirdparty/autoComplete.min.js"></script>
|
||||
<script type="text/javascript" src="../js/drag_drop_touch.js"></script>
|
||||
<script type="text/javascript" src="../js/utils.js"></script>
|
||||
<script type="text/javascript" src="../js/build_utils.js"></script>
|
||||
<script type="text/javascript" src="../js/icons.js"></script>
|
||||
<script type="text/javascript" src="../js/damage_calc.js"></script>
|
||||
<script type="text/javascript" src="../js/display_constants.js"></script>
|
||||
<script type="text/javascript" src="../js/display.js"></script>
|
||||
<script type="text/javascript" src="../js/query.js"></script>
|
||||
<script type="text/javascript" src="../js/expr_parser.js"></script>
|
||||
<script type="text/javascript" src="../js/load_ing.js"></script>
|
||||
<script type="text/javascript" src="../js/search.js"></script>
|
||||
<script type="text/javascript" src="../js/ingredients.js"></script>
|
||||
<script type="text/javascript" src="../js/powders.js"></script>
|
||||
</body>
|
||||
</html>
|
89
ingredients_adv/index.html
Normal file
89
ingredients_adv/index.html
Normal file
|
@ -0,0 +1,89 @@
|
|||
<!DOCTYPE html>
|
||||
<html scroll-behavior="smooth">
|
||||
<head>
|
||||
<title>WynnAtlas</title>
|
||||
<link rel="icon" href="../media/icons/new/searcher.png" type="image/icon type">
|
||||
|
||||
<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="/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/items_adv.css">
|
||||
<link rel="stylesheet" href="../css/sidebar.css">
|
||||
<link rel="stylesheet" href="../css/wynnstyles.css">
|
||||
</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>
|
||||
<hr/>
|
||||
<a href = "https://nori.fish/wynn/build/" target = "_blank"><img src = "../media/icons/new/nori_build.png" alt = "Build Search" title = "Build Search by Nori-Wynn"><b>Build Search</b></a>
|
||||
<a href = "https://nori.fish/wynn/recipe/" target = "_blank"><img src = "../media/icons/new/nori_recipe.png" alt = "Recipe Search" title = "Recipe Search by Nori-Wynn"><b>Recipe Search</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>
|
||||
<div class = "container py-5 vh-100 mx-0 mx-lg-auto scaled-font">
|
||||
<div class = "col">
|
||||
<div class = "row">
|
||||
<div class = "col text-start" id = "credits">
|
||||
<a href="../credits.txt" class="link">Additional credits</a>
|
||||
</div>
|
||||
<div class = "col text-end">
|
||||
<a href = "../ingredients/">Basic Ingredient Search</a>
|
||||
</div>
|
||||
</div>
|
||||
<div class = "row">
|
||||
<div class="col" id="main">
|
||||
<div class = "row" id="search-container">
|
||||
<div class="col search-field-container" id="search-filter">
|
||||
<div class="col fw-bold">Filter By:</div>
|
||||
<input class="col border-dark text-light dark-5 rounded scaled-font form-control form-control-sm" id="search-filter-field" type="text" autofocus="true"
|
||||
placeholder="name ?= "blue" & str >= 15 & dex >= 10">
|
||||
<div class="search-field-error" id="search-filter-error"></div>
|
||||
<div class="search-field-compl" id="search-filter-compl"></div>
|
||||
</div>
|
||||
<div class="col search-field-container" id="search-sort">
|
||||
<div class="col fw-bold">Sort By:</div>
|
||||
<input class="col border-dark text-light dark-5 rounded scaled-font form-control form-control-sm" id="search-sort-field" type="text"
|
||||
placeholder="str + dex; meleerawdmg + spellrawdmg">
|
||||
<div class="search-field-error" id="search-sort-error"></div>
|
||||
<div class="search-field-compl" id="search-sort-compl"></div>
|
||||
</div>
|
||||
</div>
|
||||
<div class = "row" id="item-list-container">
|
||||
<div class="row" id="item-list"></div>
|
||||
<div class="row" id="item-list-footer"></div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class = "row" id="scroll-up">↑</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
||||
<script type="text/javascript" src="/js/utils.js"></script>
|
||||
<script type="text/javascript" src="/js/build_utils.js"></script>
|
||||
<script type="text/javascript" src="/js/icons.js"></script>
|
||||
<script type="text/javascript" src="/js/powders.js"></script>
|
||||
<script type="text/javascript" src="/js/damage_calc.js"></script>
|
||||
<script type="text/javascript" src="/js/display_constants.js"></script>
|
||||
<script type="text/javascript" src="/js/display.js"></script>
|
||||
<script type="text/javascript" src="/js/query.js"></script>
|
||||
<script type="text/javascript" src="/js/expr_parser.js"></script>
|
||||
<script type="text/javascript" src="/js/load_ing.js"></script>
|
||||
<script type="text/javascript" src="/js/search_adv.js"></script>
|
||||
<script type="text/javascript" src="/js/ingredients_adv.js"></script>
|
||||
</body>
|
||||
</html>
|
57038
ingreds_clean.json
57038
ingreds_clean.json
File diff suppressed because it is too large
Load diff
File diff suppressed because one or more lines are too long
|
@ -11,9 +11,9 @@
|
|||
<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://cdn.jsdelivr.net/npm/bootstrap@5.1.3/dist/css/bootstrap.min.css" rel="stylesheet" integrity="sha384-1BmE4kWBq78iYhFldvKuhfTAU6auU8tT94WrHftjDbrCEXSU1oBoqyl2QvZ6jIW3" crossorigin="anonymous">
|
||||
<link href="/thirdparty/bootstrap.min.css" rel="stylesheet" integrity="sha384-1BmE4kWBq78iYhFldvKuhfTAU6auU8tT94WrHftjDbrCEXSU1oBoqyl2QvZ6jIW3" crossorigin="anonymous">
|
||||
|
||||
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/@tarekraafat/autocomplete.js@10.2.6/dist/css/autoComplete.min.css">
|
||||
<link rel="stylesheet" href="/thirdparty/autoComplete.min.css">
|
||||
|
||||
|
||||
<link rel="stylesheet" href="../css/sq2bs.css">
|
||||
|
@ -30,6 +30,8 @@
|
|||
<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://nori.fish/wynn/build/" target = "_blank"><img src = "../media/icons/new/nori_build.png" alt = "Build Search" title = "Build Search by Nori-Wynn"><b>Build Search</b></a>
|
||||
<a href = "https://nori.fish/wynn/recipe/" target = "_blank"><img src = "../media/icons/new/nori_recipe.png" alt = "Recipe Search" title = "Recipe Search by Nori-Wynn"><b>Recipe Search</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>
|
||||
|
||||
|
@ -56,6 +58,7 @@
|
|||
</div>
|
||||
<script type="text/javascript" src="/js/utils.js"></script>
|
||||
<script type="text/javascript" src="/js/build_utils.js"></script>
|
||||
<script type="text/javascript" src="/js/builder/build_encode_decode.js"></script>
|
||||
<script type="text/javascript" src="/js/icons.js"></script>
|
||||
<script type="text/javascript" src="/js/damage_calc.js"></script>
|
||||
<script type="text/javascript" src="/js/powders.js"></script>
|
||||
|
|
|
@ -10,15 +10,15 @@
|
|||
<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://cdn.jsdelivr.net/npm/bootstrap@5.1.3/dist/css/bootstrap.min.css" rel="stylesheet" integrity="sha384-1BmE4kWBq78iYhFldvKuhfTAU6auU8tT94WrHftjDbrCEXSU1oBoqyl2QvZ6jIW3" crossorigin="anonymous">
|
||||
<link href="/thirdparty/bootstrap.min.css" rel="stylesheet" integrity="sha384-1BmE4kWBq78iYhFldvKuhfTAU6auU8tT94WrHftjDbrCEXSU1oBoqyl2QvZ6jIW3" crossorigin="anonymous">
|
||||
|
||||
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/@tarekraafat/autocomplete.js@10.2.6/dist/css/autoComplete.min.css">
|
||||
<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/items.css">
|
||||
<link rel="stylesheet" href="../css/search.css">
|
||||
</head>
|
||||
<body class = "text-light d-flex justify-content-center" id = "body">
|
||||
<div id="main-sidebar" class="sidebar dark-7 dark-shadow">
|
||||
|
@ -30,6 +30,8 @@
|
|||
<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://nori.fish/wynn/build/" target = "_blank"><img src = "../media/icons/new/nori_build.png" alt = "Build Search" title = "Build Search by Nori-Wynn"><b>Build Search</b></a>
|
||||
<a href = "https://nori.fish/wynn/recipe/" target = "_blank"><img src = "../media/icons/new/nori_recipe.png" alt = "Recipe Search" title = "Recipe Search by Nori-Wynn"><b>Recipe Search</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>
|
||||
<div id="mobile-navbar" class="navbar dark-5 dark-shadow fixed-top d-lg-none pb-0">
|
||||
|
@ -69,6 +71,14 @@
|
|||
<img src="../media/icons/new/reload.png" alt="" style="height: 100%;">
|
||||
<span>Swap Icon Style</span>
|
||||
</a>
|
||||
<a href="https://nori.fish/wynn/build/" class="w-100 mb-3 text-white" style="height: 5vh; text-decoration: none;">
|
||||
<img src="../media/icons/new/nori_build.png" alt="" style="height: 100%;">
|
||||
<span>Build Search</span>
|
||||
</a>
|
||||
<a href="https://nori.fish/wynn/recipe/" class="w-100 mb-3 text-white" style="height: 5vh; text-decoration: none;">
|
||||
<img src="../media/icons/new/nori_recipe.png" alt="" style="height: 100%;">
|
||||
<span>Recipe Search</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>
|
||||
|
@ -78,6 +88,9 @@
|
|||
<div class = "container py-5 vh-100 mx-0 mx-lg-auto scaled-font">
|
||||
<div class = "row">
|
||||
<div class = "row" style = "margin-top: 3ch;">
|
||||
<div class = "col text-start" id = "credits">
|
||||
<a href="../ingredients/" class="link">Ingredient Searching</a>
|
||||
</div>
|
||||
<div class = "col text-end">
|
||||
<a href = "../items_adv/">Advanced Item Search</a>
|
||||
</div>
|
||||
|
@ -113,10 +126,10 @@
|
|||
</div>
|
||||
<div class = "row">
|
||||
<div class = "col-lg col-sm-12">
|
||||
<div class = "col"><span class = "fw-bold">Rarity:</span> <span style = "cursor: pointer; float: right;"><span id = "all-rarities">All</span> <span id = "none-rarities">None</span></span></div>
|
||||
<div id = "rarity-box">
|
||||
<div class = "col"><span class = "fw-bold">Rarity:</span> <span style = "cursor: pointer; float: right;"><span id = "all-tiers">All</span> <span id = "none-tiers">None</span></span></div>
|
||||
<div id = "tier-box">
|
||||
<!-- unfortunately they must be stacked up like this because newlines are considered spaces and muck up the organization -->
|
||||
<div id = "rarity-normal" class = "rarity-selected"><b>N</b></div><div id = "rarity-unique" class = "rarity-selected"><b>U</b></div><div id = "rarity-set" class = "rarity-selected"><b>S</b></div><div id = "rarity-rare" class = "rarity-selected"><b>R</b></div><div id = "rarity-legendary" class = "rarity-selected"><b>L</b></div><div id = "rarity-fabled" class = "rarity-selected"><b>F</b></div><div id = "rarity-mythic" class = "rarity-selected"><b>M</b></div>
|
||||
<div id = "tier-normal" class = "tier-selected"><b>N</b></div><div id = "tier-unique" class = "tier-selected"><b>U</b></div><div id = "tier-set" class = "tier-selected"><b>S</b></div><div id = "tier-rare" class = "tier-selected"><b>R</b></div><div id = "tier-legendary" class = "tier-selected"><b>L</b></div><div id = "tier-fabled" class = "tier-selected"><b>F</b></div><div id = "tier-mythic" class = "tier-selected"><b>M</b></div>
|
||||
</div>
|
||||
<p class="error col-auto"></p>
|
||||
</div>
|
||||
|
@ -161,18 +174,20 @@
|
|||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<script src="https://cdn.jsdelivr.net/npm/@tarekraafat/autocomplete.js@10.2.6/dist/autoComplete.min.js"></script>
|
||||
<script type="text/javascript" src="../js/drag_drop_touch.js"></script>
|
||||
<script type="text/javascript" src="../js/utils.js"></script>
|
||||
<script type="text/javascript" src="../js/build_utils.js"></script>
|
||||
<script type="text/javascript" src="../js/icons.js"></script>
|
||||
<script type="text/javascript" src="../js/damage_calc.js"></script>
|
||||
<script type="text/javascript" src="../js/display_constants.js"></script>
|
||||
<script type="text/javascript" src="../js/display.js"></script>
|
||||
<script type="text/javascript" src="../js/query.js"></script>
|
||||
<script type="text/javascript" src="../js/expr_parser.js"></script>
|
||||
<script type="text/javascript" src="../js/load.js"></script>
|
||||
<script type="text/javascript" src="../js/items.js"></script>
|
||||
<script type="text/javascript" src="../js/powders.js"></script>
|
||||
<script src="/thirdparty/autoComplete.min.js"></script>
|
||||
<script type="text/javascript" src="/js/drag_drop_touch.js"></script>
|
||||
<script type="text/javascript" src="/js/utils.js"></script>
|
||||
<script type="text/javascript" src="/js/build_utils.js"></script>
|
||||
<script type="text/javascript" src="/js/builder/build_encode_decode.js"></script>
|
||||
<script type="text/javascript" src="/js/icons.js"></script>
|
||||
<script type="text/javascript" src="/js/damage_calc.js"></script>
|
||||
<script type="text/javascript" src="/js/display_constants.js"></script>
|
||||
<script type="text/javascript" src="/js/display.js"></script>
|
||||
<script type="text/javascript" src="/js/query.js"></script>
|
||||
<script type="text/javascript" src="/js/expr_parser.js"></script>
|
||||
<script type="text/javascript" src="/js/load.js"></script>
|
||||
<script type="text/javascript" src="/js/search.js"></script>
|
||||
<script type="text/javascript" src="/js/powders.js"></script>
|
||||
<script type="text/javascript" src="/js/items.js"></script>
|
||||
</body>
|
||||
</html>
|
||||
|
|
|
@ -10,9 +10,9 @@
|
|||
<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://cdn.jsdelivr.net/npm/bootstrap@5.1.3/dist/css/bootstrap.min.css" rel="stylesheet" integrity="sha384-1BmE4kWBq78iYhFldvKuhfTAU6auU8tT94WrHftjDbrCEXSU1oBoqyl2QvZ6jIW3" crossorigin="anonymous">
|
||||
<link href="/thirdparty/bootstrap.min.css" rel="stylesheet" integrity="sha384-1BmE4kWBq78iYhFldvKuhfTAU6auU8tT94WrHftjDbrCEXSU1oBoqyl2QvZ6jIW3" crossorigin="anonymous">
|
||||
|
||||
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/@tarekraafat/autocomplete.js@10.2.6/dist/css/autoComplete.min.css">
|
||||
<link rel="stylesheet" href="/thirdparty/autoComplete.min.css">
|
||||
|
||||
|
||||
<link rel="stylesheet" href="../css/sq2bs.css">
|
||||
|
@ -76,6 +76,7 @@
|
|||
|
||||
<script type="text/javascript" src="/js/utils.js"></script>
|
||||
<script type="text/javascript" src="/js/build_utils.js"></script>
|
||||
<script type="text/javascript" src="/js/builder/build_encode_decode.js"></script>
|
||||
<script type="text/javascript" src="/js/icons.js"></script>
|
||||
<script type="text/javascript" src="/js/powders.js"></script>
|
||||
<script type="text/javascript" src="/js/damage_calc.js"></script>
|
||||
|
@ -84,6 +85,7 @@
|
|||
<script type="text/javascript" src="/js/query.js"></script>
|
||||
<script type="text/javascript" src="/js/expr_parser.js"></script>
|
||||
<script type="text/javascript" src="/js/load.js"></script>
|
||||
<script type="text/javascript" src="/js/search_adv.js"></script>
|
||||
<script type="text/javascript" src="/js/items_adv.js"></script>
|
||||
</body>
|
||||
</html>
|
||||
|
|
|
@ -13,9 +13,9 @@
|
|||
<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="https://cdn.jsdelivr.net/npm/bootstrap@5.1.3/dist/css/bootstrap.min.css" rel="stylesheet" integrity="sha384-1BmE4kWBq78iYhFldvKuhfTAU6auU8tT94WrHftjDbrCEXSU1oBoqyl2QvZ6jIW3" crossorigin="anonymous">
|
||||
<link href="/thirdparty/bootstrap.min.css" rel="stylesheet" integrity="sha384-1BmE4kWBq78iYhFldvKuhfTAU6auU8tT94WrHftjDbrCEXSU1oBoqyl2QvZ6jIW3" crossorigin="anonymous">
|
||||
|
||||
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/@tarekraafat/autocomplete.js@10.2.6/dist/css/autoComplete.min.css">
|
||||
<link rel="stylesheet" href="/thirdparty/autoComplete.min.css">
|
||||
|
||||
|
||||
<link rel="stylesheet" href="../css/article.css">
|
||||
|
@ -33,6 +33,8 @@
|
|||
<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>
|
||||
<hr/>
|
||||
<a href = "https://nori.fish/wynn/build/" target = "_blank"><img src = "../media/icons/new/nori_build.png" alt = "Build Search" title = "Build Search by Nori-Wynn"><b>Build Search</b></a>
|
||||
<a href = "https://nori.fish/wynn/recipe/" target = "_blank"><img src = "../media/icons/new/nori_recipe.png" alt = "Recipe Search" title = "Recipe Search by Nori-Wynn"><b>Recipe Search</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>
|
||||
|
@ -152,7 +154,7 @@
|
|||
['waterDmg%', 'number', ['waterDam%', 'wDmg%', 'wDam%', 'wDamPct'], 'The bonus water damage modifier on an item.'],
|
||||
['fireDmg%', 'number', ['fireDam%', 'fDmg%', 'fDam%', 'fDamPct'], 'The bonus fire damage modifier on an item.'],
|
||||
['airDmg%', 'number', ['airDam%', 'aDmg%', 'aDam%', 'aDamPct'], 'The bonus air damage modifier on an item.'],
|
||||
['sumDmg%', 'number', ['sumDam%', 'totalDmg%', 'totalDam%', 'sumDamPct', 'totalDamPct'], 'The sum of the bonus elemental damage modifiers on an item.'],
|
||||
//['sumDmg%', 'number', ['sumDam%', 'totalDmg%', 'totalDam%', 'sumDamPct', 'totalDamPct'], 'The sum of the bonus elemental damage modifiers on an item.'],
|
||||
['meleeDmg', 'number', ['meleeDam', 'meleeDmg%', 'meleeDam%', 'mdPct'], 'The bonus main-attack damage modifier on an item.'],
|
||||
['meleeNeutralDmg', 'number', ['meleeRawDam', 'meleeNeutralDmg', 'meleeNeutralDam', 'mdRaw'], 'The neutral main-attack damage on an item.'],
|
||||
['spellDmg', 'number', ['spellDam', 'spellDmg%', 'spellDam%', 'sdPct'], 'The bonus spell damage modifier on an item.'],
|
||||
|
|
196538
items_clean.json
Normal file
196538
items_clean.json
Normal file
File diff suppressed because it is too large
Load diff
1
items_compress.json
Normal file
1
items_compress.json
Normal file
File diff suppressed because one or more lines are too long
|
@ -60,7 +60,15 @@ const armorTypes = [ "helmet", "chestplate", "leggings", "boots" ];
|
|||
const accessoryTypes = [ "ring", "bracelet", "necklace" ];
|
||||
const weaponTypes = [ "wand", "spear", "bow", "dagger", "relik" ];
|
||||
const consumableTypes = [ "potion", "scroll", "food"];
|
||||
const tome_types = ['weaponTome', 'armorTome', 'guildTome'];
|
||||
const tome_types = ['weaponTome', 'armorTome', 'guildTome', 'lootrunTome', 'gatherXpTome', 'dungeonXpTome', 'mobXpTome'];
|
||||
const tome_type_map = new Map([["weaponTome", "Weapon Tome"],
|
||||
["armorTome", "Armor Tome"],
|
||||
["guildTome", "Guild Tome"],
|
||||
["gatherXpTome", "Gather XP Tome"],
|
||||
["dungeonXpTome", "Dungeon XP Tome"],
|
||||
["mobXpTome", "Slaying XP Tome"],
|
||||
]);
|
||||
|
||||
const attackSpeeds = ["SUPER_SLOW", "VERY_SLOW", "SLOW", "NORMAL", "FAST", "VERY_FAST", "SUPER_FAST"];
|
||||
const baseDamageMultiplier = [ 0.51, 0.83, 1.5, 2.05, 2.5, 3.1, 4.3 ];
|
||||
//0.51, 0.82, 1.50, 2.05, 2.50, 3.11, 4.27
|
||||
|
@ -75,7 +83,10 @@ let item_types = armorTypes.concat(accessoryTypes).concat(weaponTypes).concat(to
|
|||
let elementIcons = ["\u2724","\u2726", "\u2749", "\u2739", "\u274b" ];
|
||||
let skpReqs = skp_order.map(x => x + "Req");
|
||||
|
||||
let item_fields = [ "name", "displayName", "lore", "color", "tier", "set", "slots", "type", "material", "drop", "quest", "restrict", "nDam", "fDam", "wDam", "aDam", "tDam", "eDam", "atkSpd", "hp", "fDef", "wDef", "aDef", "tDef", "eDef", "lvl", "classReq", "strReq", "dexReq", "intReq", "defReq", "agiReq", "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", "id", "majorIds", "damMobs", "defMobs",
|
||||
let item_fields = [ "name", "displayName", "lore", "color", "tier", "set", "slots", "type", "material", "drop", "quest", "restrict", "nDam", "fDam", "wDam", "aDam", "tDam", "eDam", "atkSpd", "hp", "fDef", "wDef", "aDef", "tDef", "eDef", "lvl", "classReq", "strReq", "dexReq", "intReq", "defReq", "agiReq", "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", "id", "majorIds", "damMobs", "defMobs",
|
||||
|
||||
// wynn2 damages.
|
||||
"eMdPct","eMdRaw","eSdPct","eSdRaw",/*"eDamPct,"*/"eDamRaw","eDamAddMin","eDamAddMax",
|
||||
|
@ -87,17 +98,20 @@ let item_fields = [ "name", "displayName", "lore", "color", "tier", "set", "slot
|
|||
/*"mdPct","mdRaw","sdPct","sdRaw",*/"damPct","damRaw","damAddMin","damAddMax", // These are the old ids. Become proportional.
|
||||
"rMdPct","rMdRaw","rSdPct",/*"rSdRaw",*/"rDamPct","rDamRaw","rDamAddMin","rDamAddMax", // rainbow (the "element" of all minus neutral). rSdRaw is rainraw
|
||||
"critDamPct",
|
||||
"spPct1Final", "spPct2Final", "spPct3Final", "spPct4Final"
|
||||
"spPct1Final", "spPct2Final", "spPct3Final", "spPct4Final",
|
||||
"healPct", "kb", "weakenEnemy", "slowEnemy", "rDefPct"
|
||||
];
|
||||
// Extra fake IDs (reserved for use in spell damage calculation) : damMult, defMult, poisonPct, activeMajorIDs
|
||||
let str_item_fields = [ "name", "displayName", "lore", "color", "tier", "set", "type", "material", "drop", "quest", "restrict", "category", "atkSpd" ]
|
||||
|
||||
//File reading for ID translations for JSON purposes
|
||||
let reversetranslations = new Map();
|
||||
let translations = new Map([["name", "name"],["displayName", "displayName"],["tier", "tier"],["set", "set"],["sockets", "slots"],["type", "type"],["armorColor", "color"],["addedLore", "lore"],["dropType", "drop"],["quest", "quest"],["restrictions", "restrict"],["damage", "nDam"],["fireDamage", "fDam"],["waterDamage", "wDam"],["airDamage", "aDam"],["thunderDamage", "tDam"],["earthDamage", "eDam"],["attackSpeed", "atkSpd"],["health", "hp"],["fireDefense", "fDef"],["waterDefense", "wDef"],["airDefense", "aDef"],["thunderDefense", "tDef"],["earthDefense", "eDef"],["level", "lvl"],["classRequirement", "classReq"],["strength", "strReq"],["dexterity", "dexReq"],["intelligence", "intReq"],["agility", "agiReq"],["defense", "defReq"],["healthRegen", "hprPct"],["manaRegen", "mr"],["spellDamageBonus", "sdPct"],["spellElementalDamageBonus", "rSdPct"],["spellNeutralDamageBonus", "nSdPct"],["spellFireDamageBonus", "fSdPct"],["spellWaterDamageBonus", "wSdPct"],["spellAirDamageBonus", "aSdPct"],["spellThunderDamageBonus", "tSdPct"],["spellEarthDamageBonus", "eSdPct"],["mainAttackDamageBonus", "mdPct"],["mainAttackElementalDamageBonus", "rMdPct"],["mainAttackNeutralDamageBonus", "nMdPct"],["mainAttackFireDamageBonus", "fMdPct"],["mainAttackWaterDamageBonus", "wMdPct"],["mainAttackAirDamageBonus", "aMdPct"],["mainAttackThunderDamageBonus", "tMdPct"],["mainAttackEarthDamageBonus", "eMdPct"],["lifeSteal", "ls"],["manaSteal", "ms"],["xpBonus", "xpb"],["lootBonus", "lb"],["reflection", "ref"],["strengthPoints", "str"],["dexterityPoints", "dex"],["intelligencePoints", "int"],["agilityPoints", "agi"],["defensePoints", "def"],["thorns", "thorns"],["exploding", "expd"],["speed", "spd"],["attackSpeedBonus", "atkTier"],["poison", "poison"],["healthBonus", "hpBonus"],["soulPoints", "spRegen"],["emeraldStealing", "eSteal"],["healthRegenRaw", "hprRaw"],["spellDamageBonusRaw", "sdRaw"],["spellElementalDamageBonusRaw", "rSdRaw"],["spellNeutralDamageBonusRaw", "nSdRaw"],["spellFireDamageBonusRaw", "fSdRaw"],["spellWaterDamageBonusRaw", "wSdRaw"],["spellAirDamageBonusRaw", "aSdRaw"],["spellThunderDamageBonusRaw", "tSdRaw"],["spellEarthDamageBonusRaw", "eSdRaw"],["mainAttackDamageBonusRaw", "mdRaw"],["mainAttackElementalDamageBonusRaw", "rMdRaw"],["mainAttackNeutralDamageBonusRaw", "nMdRaw"],["mainAttackFireDamageBonusRaw", "fMdRaw"],["mainAttackWaterDamageBonusRaw", "wMdRaw"],["mainAttackAirDamageBonusRaw", "aMdRaw"],["mainAttackThunderDamageBonusRaw", "tMdRaw"],["mainAttackEarthDamageBonusRaw", "eMdRaw"],["fireDamageBonus", "fDamPct"],["waterDamageBonus", "wDamPct"],["airDamageBonus", "aDamPct"],["thunderDamageBonus", "tDamPct"],["earthDamageBonus", "eDamPct"],["bonusFireDefense", "fDefPct"],["bonusWaterDefense", "wDefPct"],["bonusAirDefense", "aDefPct"],["bonusThunderDefense", "tDefPct"],["bonusEarthDefense", "eDefPct"],["accessoryType", "type"],["identified", "fixID"],["skin", "skin"],["category", "category"],["spellCostPct1", "spPct1"],["spellCostRaw1", "spRaw1"],["spellCostPct2", "spPct2"],["spellCostRaw2", "spRaw2"],["spellCostPct3", "spPct3"],["spellCostRaw3", "spRaw3"],["spellCostPct4", "spPct4"],["spellCostRaw4", "spRaw4"],["sprint", "sprint"],["sprintRegen", "sprintReg"],["jumpHeight", "jh"],["lootQuality", "lq"],["gatherXpBonus", "gXp"],["gatherSpeed", "gSpd"]]);
|
||||
let _translations_list = [["name", "name"],["displayName", "displayName"],["tier", "tier"],["set", "set"],["sockets", "slots"],["type", "type"],["armorColor", "color"],["addedLore", "lore"],["dropType", "drop"],["quest", "quest"],["restrictions", "restrict"],["damage", "nDam"],["fireDamage", "fDam"],["waterDamage", "wDam"],["airDamage", "aDam"],["thunderDamage", "tDam"],["earthDamage", "eDam"],["attackSpeed", "atkSpd"],["health", "hp"],["fireDefense", "fDef"],["waterDefense", "wDef"],["airDefense", "aDef"],["thunderDefense", "tDef"],["earthDefense", "eDef"],["level", "lvl"],["classRequirement", "classReq"],["strength", "strReq"],["dexterity", "dexReq"],["intelligence", "intReq"],["agility", "agiReq"],["defense", "defReq"],["healthRegen", "hprPct"],["manaRegen", "mr"],["spellDamageBonus", "sdPct"],["spellElementalDamageBonus", "rSdPct"],["spellNeutralDamageBonus", "nSdPct"],["spellFireDamageBonus", "fSdPct"],["spellWaterDamageBonus", "wSdPct"],["spellAirDamageBonus", "aSdPct"],["spellThunderDamageBonus", "tSdPct"],["spellEarthDamageBonus", "eSdPct"],["mainAttackDamageBonus", "mdPct"],["mainAttackElementalDamageBonus", "rMdPct"],["mainAttackNeutralDamageBonus", "nMdPct"],["mainAttackFireDamageBonus", "fMdPct"],["mainAttackWaterDamageBonus", "wMdPct"],["mainAttackAirDamageBonus", "aMdPct"],["mainAttackThunderDamageBonus", "tMdPct"],["mainAttackEarthDamageBonus", "eMdPct"],["lifeSteal", "ls"],["manaSteal", "ms"],["xpBonus", "xpb"],["lootBonus", "lb"],["reflection", "ref"],["strengthPoints", "str"],["dexterityPoints", "dex"],["intelligencePoints", "int"],["agilityPoints", "agi"],["defensePoints", "def"],["thorns", "thorns"],["exploding", "expd"],["speed", "spd"],["attackSpeedBonus", "atkTier"],["poison", "poison"],["healthBonus", "hpBonus"],["soulPoints", "spRegen"],["emeraldStealing", "eSteal"],["healthRegenRaw", "hprRaw"],["spellDamageBonusRaw", "sdRaw"],["spellElementalDamageBonusRaw", "rSdRaw"],["spellNeutralDamageBonusRaw", "nSdRaw"],["spellFireDamageBonusRaw", "fSdRaw"],["spellWaterDamageBonusRaw", "wSdRaw"],["spellAirDamageBonusRaw", "aSdRaw"],["spellThunderDamageBonusRaw", "tSdRaw"],["spellEarthDamageBonusRaw", "eSdRaw"],["mainAttackDamageBonusRaw", "mdRaw"],["mainAttackElementalDamageBonusRaw", "rMdRaw"],["mainAttackNeutralDamageBonusRaw", "nMdRaw"],["mainAttackFireDamageBonusRaw", "fMdRaw"],["mainAttackWaterDamageBonusRaw", "wMdRaw"],["mainAttackAirDamageBonusRaw", "aMdRaw"],["mainAttackThunderDamageBonusRaw", "tMdRaw"],["mainAttackEarthDamageBonusRaw", "eMdRaw"],["fireDamageBonus", "fDamPct"],["waterDamageBonus", "wDamPct"],["airDamageBonus", "aDamPct"],["thunderDamageBonus", "tDamPct"],["earthDamageBonus", "eDamPct"],["bonusFireDefense", "fDefPct"],["bonusWaterDefense", "wDefPct"],["bonusAirDefense", "aDefPct"],["bonusThunderDefense", "tDefPct"],["bonusEarthDefense", "eDefPct"],["accessoryType", "type"],["identified", "fixID"],["skin", "skin"],["category", "category"],["spellCostPct1", "spPct1"],["spellCostRaw1", "spRaw1"],["spellCostPct2", "spPct2"],["spellCostRaw2", "spRaw2"],["spellCostPct3", "spPct3"],["spellCostRaw3", "spRaw3"],["spellCostPct4", "spPct4"],["spellCostRaw4", "spRaw4"],["sprint", "sprint"],["sprintRegen", "sprintReg"],["jumpHeight", "jh"],["lootQuality", "lq"],["gatherXpBonus", "gXp"],["gatherSpeed", "gSpd"],["healingEfficiency", "healPct"], ["knockback", "kb"], ["weakenEnemy", "weakenEnemy"], ["slowEnemy", "slowEnemy"], ["elementalDefense", "rDefPct"]];
|
||||
let translations = new Map(_translations_list);
|
||||
|
||||
//does not include damMobs (wep tomes) and defMobs (armor tomes)
|
||||
for (const [k, v] of translations) {
|
||||
for (const [k, v] of _translations_list) {
|
||||
if (reversetranslations.has(v)) { continue; }
|
||||
reversetranslations.set(v, k);
|
||||
}
|
||||
|
||||
|
@ -174,10 +188,13 @@ let rolledIDs = [
|
|||
"nMdPct","nMdRaw","nSdPct","nSdRaw","nDamPct","nDamRaw","nDamAddMin","nDamAddMax", // neutral which is now an element
|
||||
/*"mdPct","mdRaw","sdPct","sdRaw",*/"damPct","damRaw","damAddMin","damAddMax", // These are the old ids. Become proportional.
|
||||
"rMdPct","rMdRaw","rSdPct",/*"rSdRaw",*/"rDamPct","rDamRaw","rDamAddMin","rDamAddMax", // rainbow (the "element" of all minus neutral). rSdRaw is rainraw
|
||||
"spPct1Final", "spPct2Final", "spPct3Final", "spPct4Final"
|
||||
"spPct1Final", "spPct2Final", "spPct3Final", "spPct4Final",
|
||||
"healPct", "kb", "weakenEnemy", "slowEnemy", "rDefPct"
|
||||
];
|
||||
let reversedIDs = [ "spPct1", "spRaw1", "spPct2", "spRaw2", "spPct3", "spRaw3", "spPct4", "spRaw4" ];
|
||||
|
||||
let ingFields = rolledIDs.concat(["str", "dex", "int", "def", "agi"]);
|
||||
|
||||
/**
|
||||
* Take an item with id list and turn it into a set of minrolls and maxrolls.
|
||||
*/
|
||||
|
@ -195,28 +212,16 @@ function expandItem(item) {
|
|||
} else { //The item does not have fixed IDs.
|
||||
for (const id of rolledIDs) {
|
||||
let val = (item[id] || 0);
|
||||
if (val > 0) { // positive rolled IDs
|
||||
if (reversedIDs.includes(id)) {
|
||||
maxRolls.set(id,idRound(val*0.7));
|
||||
minRolls.set(id,idRound(val*1.3));
|
||||
} else {
|
||||
maxRolls.set(id,idRound(val*1.3));
|
||||
minRolls.set(id,idRound(val*0.3));
|
||||
}
|
||||
} else if (val < 0) { //negative rolled IDs
|
||||
if (reversedIDs.includes(id)) {
|
||||
maxRolls.set(id,idRound(val*1.3));
|
||||
minRolls.set(id,idRound(val*0.3));
|
||||
}
|
||||
else {
|
||||
maxRolls.set(id,idRound(val*0.7));
|
||||
minRolls.set(id,idRound(val*1.3));
|
||||
}
|
||||
}
|
||||
else { // if val == 0
|
||||
if (val == 0) {
|
||||
// NOTE: DO NOT remove this case! idRound behavior does not round to 0!
|
||||
maxRolls.set(id,0);
|
||||
minRolls.set(id,0);
|
||||
} else if ((val > 0) != (reversedIDs.includes(id))) { // logical XOR. positive IDs
|
||||
maxRolls.set(id,idRound(val*1.3));
|
||||
minRolls.set(id,idRound(val*0.3));
|
||||
} else { //negative rolled IDs
|
||||
maxRolls.set(id,idRound(val*0.7));
|
||||
minRolls.set(id,idRound(val*1.3));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -300,7 +305,7 @@ function expandRecipe(recipe) {
|
|||
function idRound(id){
|
||||
rounded = Math.round(id);
|
||||
if(rounded == 0){
|
||||
return 1; //this is a hack, will need changing along w/ rest of ID system if anything changes
|
||||
return Math.sign(id); //this is a hack, will need changing along w/ rest of ID system if anything changes
|
||||
}else{
|
||||
return rounded;
|
||||
}
|
||||
|
@ -310,8 +315,8 @@ function idRound(id){
|
|||
* stupid stupid multiplicative stats
|
||||
*/
|
||||
function merge_stat(stats, name, value) {
|
||||
const start = name.slice(0, 7);
|
||||
if (start === 'damMult' || start === 'defMult') {
|
||||
const start = name.split('.', limit=1)[0];
|
||||
if (start === 'damMult' || start === 'defMult' || start === 'healMult') {
|
||||
if (!stats.has(start)) {
|
||||
stats.set(start, new Map());
|
||||
}
|
||||
|
@ -322,7 +327,7 @@ function merge_stat(stats, name, value) {
|
|||
}
|
||||
return;
|
||||
}
|
||||
merge_stat(map, name.slice(8), value);
|
||||
merge_stat(map, name.slice(name.indexOf('.')+1), value);
|
||||
return;
|
||||
}
|
||||
if (stats.has(name)) {
|
||||
|
|
|
@ -45,9 +45,10 @@ add_spell_prop: {
|
|||
base_spell: int // spell identifier
|
||||
target_part: Optional[str] // Part of the spell to modify. Can be not present/empty for ex. cost modifier.
|
||||
// If target part does not exist, a new part is created.
|
||||
behavior: Optional[str] // One of: "merge", "modify". default: merge
|
||||
behavior: Optional[str] // One of: "merge", "modify", "overwrite". default: merge
|
||||
// merge: add if exist, make new part if not exist
|
||||
// modify: increment existing part. do nothing if not exist
|
||||
// overwrite: set part. do nothing if not exist
|
||||
cost: Optional[int] // change to spellcost. If the spell is not spell 1-4, this must be left empty.
|
||||
multipliers: Optional[array[float, 6]] // Additive changes to spellmult (for damage spell)
|
||||
power: Optional[float] // Additive change to healing power (for heal spell)
|
||||
|
@ -75,22 +76,23 @@ raw_stat: {
|
|||
bonuses: List[stat_bonus]
|
||||
}
|
||||
stat_bonus: {
|
||||
"type": "stat" | "prop",
|
||||
"abil": Optional[int],
|
||||
"name": str,
|
||||
"value": float
|
||||
type: "stat" | "prop",
|
||||
abil: Optional[int],
|
||||
name: str,
|
||||
value: float
|
||||
}
|
||||
stat_scaling: {
|
||||
"type": "stat_scaling",
|
||||
"slider": bool,
|
||||
type: "stat_scaling",
|
||||
slider: bool,
|
||||
positive: bool // True to keep stat above 0. False to ignore floor. Default: True for normal, False for scaling
|
||||
"slider_name": Optional[str],
|
||||
"slider_step": Optional[float],
|
||||
round: Optional[bool] // Control floor behavior. True for stats and false for slider by default
|
||||
slider_behavior: Optional[str] // One of: "merge", "modify". default: merge
|
||||
slider_name: Optional[str],
|
||||
slider_step: Optional[float],
|
||||
round: Optional[bool] // Control floor behavior. True for stats and false for slider by default
|
||||
behavior: Optional[str] // One of: "merge", "modify". default: merge
|
||||
// merge: add if exist, make new part if not exist
|
||||
// modify: change existing part, by incrementing properties. do nothing if not exist
|
||||
slider_max: Optional[float] // affected by slider_behavior
|
||||
slider_max: Optional[int] // affected by behavior
|
||||
slider_default: Optional[int] // affected by behavior
|
||||
inputs: Optional[list[scaling_target]] // List of things to scale. Omit this if using slider
|
||||
|
||||
output: Optional[scaling_target | List[scaling_target]] // One of the following:
|
||||
|
@ -98,12 +100,12 @@ stat_scaling: {
|
|||
// 2. List of scaling targets (all scaled the same)
|
||||
// 3. Omitted. no output (useful for modifying slider only without input or output)
|
||||
scaling: Optional[list[float]] // One float for each input. Sums into output.
|
||||
max: float
|
||||
max: float // Hardcap on this effect (slider value * slider_step). Can be negative if scaling is negative
|
||||
}
|
||||
scaling_target: {
|
||||
"type": "stat" | "prop",
|
||||
"abil": Optional[int],
|
||||
"name": str
|
||||
type: "stat" | "prop",
|
||||
abil: Optional[int],
|
||||
name: str
|
||||
}
|
||||
*/
|
||||
|
||||
|
@ -164,6 +166,64 @@ const default_abils = {
|
|||
}, elem_mastery_abil ],
|
||||
};
|
||||
|
||||
/**
|
||||
* Given a json of raw atree data, and a wynn class name (ex. Archer, Mage),
|
||||
* sort out their ability tree and return it as a list in roughly topologically
|
||||
* sorted order.
|
||||
*
|
||||
* TODO: Why do we care about the toposort?
|
||||
* This is not a useful representation of the tree.
|
||||
* It's useless.
|
||||
* atree needs a cleanup and anything depending on the ordering of items
|
||||
* coming out of this function is probably doing something wrong.
|
||||
* NOTE2: Actually this might be more complicated because some nodes do need
|
||||
* an application ordering and that matters (esp. replace_spell nodes).
|
||||
*
|
||||
* Parameters:
|
||||
* --------------------------
|
||||
* atrees: Raw atree data. This is a parameter to allow oldversion shenanigans
|
||||
* player_class: Wynn class name (string)
|
||||
*
|
||||
* Return:
|
||||
* List of atree nodes.
|
||||
*/
|
||||
function get_sorted_class_atree(atrees, player_class) {
|
||||
const atree_raw = atrees[player_class];
|
||||
if (!atree_raw) return [];
|
||||
|
||||
let atree_map = new Map();
|
||||
let atree_head;
|
||||
for (const i of atree_raw) {
|
||||
atree_map.set(i.id, {children: [], ability: i});
|
||||
if (i.parents.length == 0) {
|
||||
// Assuming there is only one head.
|
||||
atree_head = atree_map.get(i.id);
|
||||
}
|
||||
}
|
||||
for (const i of atree_raw) {
|
||||
let node = atree_map.get(i.id);
|
||||
let parents = [];
|
||||
for (const parent_id of node.ability.parents) {
|
||||
let parent_node = atree_map.get(parent_id);
|
||||
parent_node.children.push(node);
|
||||
parents.push(parent_node);
|
||||
}
|
||||
node.parents = parents;
|
||||
}
|
||||
|
||||
let sccs = make_SCC_graph(atree_head, atree_map.values());
|
||||
let atree_topo_sort = [];
|
||||
for (const scc of sccs) {
|
||||
for (const node of scc.nodes) {
|
||||
delete node.visited;
|
||||
delete node.assigned;
|
||||
delete node.scc;
|
||||
atree_topo_sort.push(node);
|
||||
}
|
||||
}
|
||||
return atree_topo_sort;
|
||||
}
|
||||
|
||||
/**
|
||||
* Update ability tree internal representation. (topologically sorted node list)
|
||||
*
|
||||
|
@ -175,43 +235,7 @@ const atree_node = new (class extends ComputeNode {
|
|||
compute_func(input_map) {
|
||||
if (input_map.size !== 1) { throw "AbilityTreeUpdateNode accepts exactly one input (player-class)"; }
|
||||
const [player_class] = input_map.values(); // Extract values, pattern match it into size one list and bind to first element
|
||||
|
||||
const atree_raw = atrees[player_class];
|
||||
if (!atree_raw) return [];
|
||||
|
||||
let atree_map = new Map();
|
||||
let atree_head;
|
||||
for (const i of atree_raw) {
|
||||
atree_map.set(i.id, {children: [], ability: i});
|
||||
if (i.parents.length == 0) {
|
||||
// Assuming there is only one head.
|
||||
atree_head = atree_map.get(i.id);
|
||||
}
|
||||
}
|
||||
for (const i of atree_raw) {
|
||||
let node = atree_map.get(i.id);
|
||||
let parents = [];
|
||||
for (const parent_id of node.ability.parents) {
|
||||
let parent_node = atree_map.get(parent_id);
|
||||
parent_node.children.push(node);
|
||||
parents.push(parent_node);
|
||||
}
|
||||
node.parents = parents;
|
||||
}
|
||||
|
||||
let sccs = make_SCC_graph(atree_head, atree_map.values());
|
||||
let atree_topo_sort = [];
|
||||
for (const scc of sccs) {
|
||||
for (const node of scc.nodes) {
|
||||
delete node.visited;
|
||||
delete node.assigned;
|
||||
delete node.scc;
|
||||
atree_topo_sort.push(node);
|
||||
}
|
||||
}
|
||||
//console.log("Approximate topological order ability tree:");
|
||||
//console.log(atree_topo_sort);
|
||||
return atree_topo_sort;
|
||||
return get_sorted_class_atree(atrees, player_class);
|
||||
}
|
||||
})();
|
||||
|
||||
|
@ -421,6 +445,7 @@ const atree_merge = new (class extends ComputeNode {
|
|||
const [hard_error, errors] = input_map.get('atree-errors');
|
||||
if (hard_error) { return null; }
|
||||
const player_class = input_map.get('player-class');
|
||||
const build = input_map.get('build');
|
||||
const atree_state = input_map.get('atree-state');
|
||||
const atree_order = input_map.get('atree');
|
||||
|
||||
|
@ -433,26 +458,20 @@ const atree_merge = new (class extends ComputeNode {
|
|||
else if (!Array.isArray(tmp_abil.desc)) {
|
||||
tmp_abil.desc = [tmp_abil.desc];
|
||||
}
|
||||
tmp_abil.subparts = [abil.id];
|
||||
abils_merged.set(abil.id, tmp_abil);
|
||||
}
|
||||
|
||||
for (const node of atree_order) {
|
||||
const abil_id = node.ability.id;
|
||||
if (!atree_state.get(abil_id).active) {
|
||||
continue;
|
||||
}
|
||||
const abil = node.ability;
|
||||
|
||||
function merge_abil(abil) {
|
||||
if ('base_abil' in abil) {
|
||||
if (abils_merged.has(abil.base_abil)) {
|
||||
// Merge abilities.
|
||||
// TODO: What if there is more than one base abil?
|
||||
let base_abil = abils_merged.get(abil.base_abil);
|
||||
if (Array.isArray(abil.desc)) { base_abil.desc = base_abil.desc.concat(abil.desc); }
|
||||
else { base_abil.desc.push(abil.desc); }
|
||||
if (abil.desc) {
|
||||
if (Array.isArray(abil.desc)) { base_abil.desc = base_abil.desc.concat(abil.desc); }
|
||||
else { base_abil.desc.push(abil.desc); }
|
||||
}
|
||||
|
||||
base_abil.subparts.push(abil.id);
|
||||
base_abil.effects = base_abil.effects.concat(abil.effects);
|
||||
for (let propname in abil.properties) {
|
||||
if (propname in base_abil.properties) {
|
||||
|
@ -468,10 +487,54 @@ const atree_merge = new (class extends ComputeNode {
|
|||
if (!Array.isArray(tmp_abil.desc)) {
|
||||
tmp_abil.desc = [tmp_abil.desc];
|
||||
}
|
||||
tmp_abil.subparts = [abil.id];
|
||||
abils_merged.set(abil_id, tmp_abil);
|
||||
abils_merged.set(abil.id, tmp_abil);
|
||||
}
|
||||
}
|
||||
|
||||
for (const node of atree_order) {
|
||||
const abil_id = node.ability.id;
|
||||
if (!atree_state.get(abil_id).active) {
|
||||
continue;
|
||||
}
|
||||
merge_abil(node.ability);
|
||||
}
|
||||
|
||||
// Apply major IDs.
|
||||
const build_class = wep_to_class.get(build.weapon.statMap.get("type"));
|
||||
for (const major_id_name of build.statMap.get("activeMajorIDs")) {
|
||||
|
||||
// Sometimes, something silly happens and we haven't implemented a major ID that
|
||||
// exists. This makes sure we don't try to apply unimplemented major IDs.
|
||||
//
|
||||
// `major_ids` is a global map loaded from data json.
|
||||
if (major_id_name in major_ids) {
|
||||
|
||||
// A major ID can have multiple abilities, specified as atree nodes,
|
||||
// as part of its effects. Apply each of them.
|
||||
for (const abil of major_ids[major_id_name].abilities) {
|
||||
|
||||
// But only the ones that match the current class.
|
||||
if (abil["class"] === build_class) {
|
||||
|
||||
// Major IDs can have ability dependencies.
|
||||
// By default they are always on.
|
||||
if (abil.dependencies !== undefined) {
|
||||
|
||||
let dep_satisfied = true;
|
||||
for (const dep_id of abil.dependencies) {
|
||||
if (!atree_state.get(dep_id).active) {
|
||||
dep_satisfied = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (!dep_satisfied) { continue; }
|
||||
}
|
||||
merge_abil(abil);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
console.log(abils_merged)
|
||||
return abils_merged;
|
||||
}
|
||||
})().link_to(atree_node, 'atree').link_to(atree_state_node, 'atree-state').link_to(atree_validate, 'atree-errors');
|
||||
|
@ -511,27 +574,43 @@ const atree_make_interactives = new (class extends ComputeNode {
|
|||
const slider_map = new Map();
|
||||
const button_map = new Map();
|
||||
|
||||
// first, pull out all the sliders and toggles.
|
||||
for (const [abil_id, ability] of merged_abils.entries()) {
|
||||
let to_process = [];
|
||||
for (const [abil_id, ability] of merged_abils) {
|
||||
for (const effect of ability.effects) {
|
||||
if (effect['type'] === "stat_scaling" && effect['slider'] === true) {
|
||||
const { slider_name, slider_behavior = 'merge', slider_max, slider_step } = effect;
|
||||
to_process.push([effect, abil_id, ability]);
|
||||
}
|
||||
if (effect['type'] === "raw_stat" && effect['toggle']) {
|
||||
to_process.push([effect, abil_id, ability]);
|
||||
}
|
||||
}
|
||||
}
|
||||
let unprocessed = [];
|
||||
// first, pull out all the sliders and toggles.
|
||||
let k = to_process.length;
|
||||
for (let i = 0; i < k; ++i) {
|
||||
for (const [effect, abil_id, ability] of to_process) {
|
||||
if (effect['type'] === "stat_scaling" && effect['slider'] === true) {
|
||||
const { slider_name, behavior = 'merge', slider_max = 0, slider_step, slider_default = 0 } = effect;
|
||||
if (slider_map.has(slider_name)) {
|
||||
if (slider_max !== undefined) {
|
||||
const slider_info = slider_map.get(slider_name);
|
||||
slider_info.max += slider_max;
|
||||
}
|
||||
const slider_info = slider_map.get(slider_name);
|
||||
slider_info.max += slider_max;
|
||||
slider_info.default_val += slider_default;
|
||||
}
|
||||
else if (slider_behavior === 'merge') {
|
||||
else if (behavior === 'merge') {
|
||||
slider_map.set(slider_name, {
|
||||
label_name: slider_name+' ('+ability.display_name+')',
|
||||
max: slider_max,
|
||||
default_val: slider_default,
|
||||
step: slider_step,
|
||||
id: "ability-slider"+ability.id,
|
||||
//color: effect['slider_color'] TODO: add colors to json
|
||||
abil: ability
|
||||
});
|
||||
}
|
||||
else {
|
||||
unprocessed.push([effect, abil_id, ability]);
|
||||
}
|
||||
}
|
||||
if (effect['type'] === "raw_stat" && effect['toggle']) {
|
||||
const { toggle: toggle_name } = effect;
|
||||
|
@ -540,6 +619,9 @@ const atree_make_interactives = new (class extends ComputeNode {
|
|||
});
|
||||
}
|
||||
}
|
||||
if (unprocessed.length == to_process.length) { break; }
|
||||
to_process = unprocessed;
|
||||
unprocessed = [];
|
||||
}
|
||||
// next, render the sliders and toggles onto the abilities.
|
||||
for (const [slider_name, slider_info] of slider_map.entries()) {
|
||||
|
@ -623,9 +705,13 @@ const atree_scaling = new (class extends ComputeNode {
|
|||
continue;
|
||||
case 'stat_scaling':
|
||||
let total = 0;
|
||||
const {slider = false, scaling = [0]} = effect;
|
||||
const {slider = false, scaling = [0], behavior="merge"} = effect;
|
||||
let { positive = true, round = true } = effect;
|
||||
if (slider) {
|
||||
if (behavior == "modify" && !slider_map.has(effect.slider_name)) {
|
||||
// Dangerous control flow.. early continue
|
||||
continue;
|
||||
}
|
||||
const slider_val = slider_map.get(effect.slider_name).slider.value;
|
||||
total = parseInt(slider_val) * scaling[0];
|
||||
round = false;
|
||||
|
@ -641,7 +727,10 @@ const atree_scaling = new (class extends ComputeNode {
|
|||
if ('output' in effect) { // sometimes nodes will modify slider without having effect.
|
||||
if (round) { total = Math.floor(round_near(total)); }
|
||||
if (positive && total < 0) { total = 0; } // Normal stat scaling will not go negative.
|
||||
if ('max' in effect && total > effect.max) { total = effect.max; }
|
||||
if ('max' in effect) {
|
||||
if (effect.max > 0 && total > effect.max) { total = effect.max; }
|
||||
if (effect.max < 0 && total < effect.max) { total = effect.max; }
|
||||
}
|
||||
if (Array.isArray(effect.output)) {
|
||||
for (const output of effect.output) {
|
||||
apply_bonus(output, total);
|
||||
|
@ -814,33 +903,45 @@ const atree_collect_spells = new (class extends ComputeNode {
|
|||
continue;
|
||||
case 'add_spell_prop': {
|
||||
const { base_spell, target_part = null, cost = 0, behavior = 'merge'} = effect;
|
||||
const ret_spell = ret_spells.get(base_spell);
|
||||
// TODO: unjankify this...
|
||||
if ('cost' in ret_spell) { ret_spell.cost += cost; }
|
||||
|
||||
if (target_part === null) {
|
||||
if (!ret_spells.has(base_spell)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
const ret_spell = ret_spells.get(base_spell);
|
||||
|
||||
// :enraged:
|
||||
// NOTE to hpp: this is out here because:
|
||||
// target_part doesn't exist for spell cost modification abilities
|
||||
// except when it does... in which case it should apply exactly once.
|
||||
if ('cost' in ret_spell) { ret_spell.cost += cost; }
|
||||
|
||||
// NOTE: see above comment for the weird placement of this code block.
|
||||
if (target_part === null) { continue; }
|
||||
|
||||
let found_part = false;
|
||||
for (let part of ret_spell.parts) { // TODO: replace with Map? to avoid this linear search... idk prolly good since its not more verbose to type in json
|
||||
if (part.name !== target_part) {
|
||||
continue;
|
||||
}
|
||||
|
||||
// we found the part. merge or modify it!
|
||||
if ('multipliers' in effect) {
|
||||
for (const [idx, v] of effect.multipliers.entries()) { // python: enumerate()
|
||||
part.multipliers[idx] += v;
|
||||
if (behavior === 'overwrite') { part.multipliers[idx] = v; }
|
||||
else { part.multipliers[idx] += v; }
|
||||
}
|
||||
}
|
||||
else if ('power' in effect) {
|
||||
part.power += effect.power;
|
||||
if (behavior === 'overwrite') { part.power = effect.power; }
|
||||
else { part.power += effect.power; }
|
||||
}
|
||||
else if ('hits' in effect) {
|
||||
for (const [idx, _v] of Object.entries(effect.hits)) { // looks kinda similar to multipliers case... hmm... can we unify all of these three? (make healpower a list)
|
||||
let v = translate(_v);
|
||||
if (idx in part.hits) { part.hits[idx] += v; }
|
||||
else { part.hits[idx] = v; }
|
||||
if (behavior === 'overwrite') { part.hits[idx] = v; }
|
||||
else {
|
||||
if (idx in part.hits) { part.hits[idx] += v; }
|
||||
else { part.hits[idx] = v; }
|
||||
}
|
||||
}
|
||||
}
|
||||
else {
|
||||
|
@ -864,6 +965,7 @@ const atree_collect_spells = new (class extends ComputeNode {
|
|||
}
|
||||
continue;
|
||||
}
|
||||
// NOTE: Legacy support
|
||||
case 'convert_spell_conv':
|
||||
const { base_spell, target_part, conversion } = effect;
|
||||
const ret_spell = ret_spells.get(base_spell);
|
||||
|
@ -964,13 +1066,9 @@ class AbilityTreeEnsureNodesNode extends ComputeNode {
|
|||
// TODO shortcut update path for sliders
|
||||
|
||||
for (const [spell_id, spell] of new Map([...spell_map].sort((a, b) => a[0] - b[0])).entries()) {
|
||||
let spell_node = new SpellSelectNode(spell)
|
||||
.link_to(build_node, 'build');
|
||||
|
||||
let calc_node = new SpellDamageCalcNode(spell.base_spell)
|
||||
let calc_node = new SpellDamageCalcNode(spell)
|
||||
.link_to(build_node, 'build')
|
||||
.link_to(stat_agg_node, 'stats')
|
||||
.link_to(spell_node, 'spell-info');
|
||||
.link_to(stat_agg_node, 'stats');
|
||||
this.spelldmg_nodes.push(calc_node);
|
||||
|
||||
let display_elem = make_elem('div', ["col", "pe-0"]);
|
||||
|
@ -982,9 +1080,8 @@ class AbilityTreeEnsureNodesNode extends ComputeNode {
|
|||
|
||||
display_elem.append(spell_summary, spell_detail);
|
||||
|
||||
let display_node = new SpellDisplayNode(spell.base_spell)
|
||||
let display_node = new SpellDisplayNode(spell)
|
||||
.link_to(stat_agg_node, 'stats')
|
||||
.link_to(spell_node, 'spell-info')
|
||||
.link_to(calc_node, 'spell-damage');
|
||||
|
||||
this.spell_display_elem.appendChild(display_elem);
|
||||
|
|
File diff suppressed because it is too large
Load diff
File diff suppressed because one or more lines are too long
|
@ -10,7 +10,7 @@ const classDefenseMultipliers = new Map([ ["relik",0.60], ["bow",0.70], ["wand",
|
|||
/*
|
||||
* Class that represents a wynn player's build.
|
||||
*/
|
||||
class Build{
|
||||
class Build {
|
||||
|
||||
/**
|
||||
* @description Construct a build.
|
||||
|
@ -20,6 +20,7 @@ class Build{
|
|||
* @param {Item} weapon: Weapon that this build is using.
|
||||
*/
|
||||
constructor(level, items, weapon){
|
||||
|
||||
if (level < 1) { //Should these be constants?
|
||||
this.level = 1;
|
||||
} else if (level > 106) {
|
||||
|
@ -78,7 +79,8 @@ class Build{
|
|||
"aMdPct","aMdRaw","aSdPct","aSdRaw","aDamPct","aDamRaw","aDamAddMin","aDamAddMax",
|
||||
"nMdPct","nMdRaw","nSdPct","nSdRaw","nDamPct","nDamRaw","nDamAddMin","nDamAddMax", // neutral which is now an element
|
||||
"mdPct","mdRaw","sdPct","sdRaw","damPct","damRaw","damAddMin","damAddMax", // These are the old ids. Become proportional.
|
||||
"rMdPct","rMdRaw","rSdPct","rSdRaw","rDamPct","rDamRaw","rDamAddMin","rDamAddMax" // rainbow (the "element" of all minus neutral). rSdRaw is rainraw
|
||||
"rMdPct","rMdRaw","rSdPct","rSdRaw","rDamPct","rDamRaw","rDamAddMin","rDamAddMax", // rainbow (the "element" of all minus neutral). rSdRaw is rainraw
|
||||
"healPct",
|
||||
]
|
||||
|
||||
//Create a map of this build's stats
|
||||
|
@ -114,8 +116,8 @@ class Build{
|
|||
}
|
||||
statMap.set('damMult', new Map());
|
||||
statMap.set('defMult', new Map());
|
||||
statMap.get('damMult').set('tome', statMap.get('damMobs'))
|
||||
statMap.get('defMult').set('tome', statMap.get('defMobs'))
|
||||
statMap.get('damMult').set('tome', statMap.get('damMobs'));
|
||||
statMap.get('defMult').set('tome', statMap.get('defMobs'));
|
||||
statMap.set("activeMajorIDs", major_ids);
|
||||
for (const [setName, count] of this.activeSetCounts) {
|
||||
const bonus = sets.get(setName).bonuses[count-1];
|
||||
|
@ -130,7 +132,8 @@ class Build{
|
|||
}
|
||||
statMap.set("poisonPct", 0);
|
||||
statMap.set("critDamPct", 0);
|
||||
statMap.set("healPct", 0);
|
||||
statMap.set("healMult", new Map());
|
||||
statMap.get('healMult').set('item', statMap.get('healPct'));
|
||||
|
||||
// The stuff relevant for damage calculation!!! @ferricles
|
||||
statMap.set("atkSpd", this.weapon.statMap.get("atkSpd"));
|
||||
|
|
|
@ -29,27 +29,46 @@ function parsePowdering(powder_info) {
|
|||
let atree_data = null;
|
||||
const wynn_version_names = [
|
||||
'2.0.1.1',
|
||||
'2.0.1.2'
|
||||
'2.0.1.2',
|
||||
'2.0.2.1',
|
||||
'2.0.2.3',
|
||||
'2.0.3.1',
|
||||
'2.0.4.1',
|
||||
'2.0.4.3',
|
||||
'2.0.4.4',
|
||||
'2.1.0.0'
|
||||
];
|
||||
const WYNN_VERSION_LATEST = wynn_version_names.length - 1;
|
||||
// Default to the newest version.
|
||||
let wynn_version_id = WYNN_VERSION_LATEST;
|
||||
|
||||
let major_ids = null;
|
||||
let major_id_load_complete = false;
|
||||
async function load_major_id_data(version_str) {
|
||||
let getUrl = window.location;
|
||||
let baseUrl = `${getUrl.protocol}//${getUrl.host}/`;
|
||||
// No random string -- we want to use caching
|
||||
let url = `${baseUrl}/data/${version_str}/majid.json`;
|
||||
major_ids = await (await fetch(url)).json();
|
||||
major_id_load_complete = true;
|
||||
}
|
||||
|
||||
/*
|
||||
* Populate fields based on url, and calculate build.
|
||||
* TODO: THIS CODE IS GOD AWFUL result of being lazy
|
||||
* fix all the slice() and break into functions or do something about it... its inefficient, ugly and error prone
|
||||
*/
|
||||
async function parse_hash(url_tag) {
|
||||
const default_load_promises = [ load_atree_data(wynn_version_names[WYNN_VERSION_LATEST]),
|
||||
load_init(), load_ing_init(), load_tome_init() ];
|
||||
let latest_ver_name = wynn_version_names[WYNN_VERSION_LATEST];
|
||||
const default_load_promises = [ load_atree_data(latest_ver_name), load_major_id_data(latest_ver_name),
|
||||
load_init(), load_ing_init(), load_tome_init()];
|
||||
if (!url_tag) {
|
||||
await Promise.all(default_load_promises);
|
||||
return;
|
||||
}
|
||||
//default values
|
||||
let equipment = [null, null, null, null, null, null, null, null, null];
|
||||
let tomes = [null, null, null, null, null, null, null];
|
||||
let tomes = [null, null, null, null, null, null, null, null];
|
||||
let powdering = ["", "", "", "", ""];
|
||||
let info = url_tag.split("_");
|
||||
let version = info[0];
|
||||
|
@ -96,6 +115,7 @@ async function parse_hash(url_tag) {
|
|||
else {
|
||||
version_name = wynn_version_names[wynn_version_id];
|
||||
const load_promises = [ load_atree_data(version_name),
|
||||
load_major_id_data(version_name),
|
||||
load_old_version(version_name),
|
||||
load_ings_old_version(version_name),
|
||||
load_tome_old_version(version_name) ];
|
||||
|
@ -103,6 +123,7 @@ async function parse_hash(url_tag) {
|
|||
await Promise.all(load_promises);
|
||||
}
|
||||
}
|
||||
|
||||
if (wynn_version_id == WYNN_VERSION_LATEST) {
|
||||
await Promise.all(default_load_promises);
|
||||
}
|
||||
|
@ -133,7 +154,7 @@ async function parse_hash(url_tag) {
|
|||
}
|
||||
data_str = info_str.slice(start_idx);
|
||||
}
|
||||
else if (version_number <= 8) {
|
||||
else if (version_number <= 9) {
|
||||
let info_str = data_str;
|
||||
let start_idx = 0;
|
||||
for (let i = 0; i < 9; ++i ) {
|
||||
|
@ -174,7 +195,7 @@ async function parse_hash(url_tag) {
|
|||
let powder_info = data_str.slice(10);
|
||||
let res = parsePowdering(powder_info);
|
||||
powdering = res[0];
|
||||
} else if (version_number <= 8){
|
||||
} else if (version_number <= 9){
|
||||
level = Base64.toInt(data_str.slice(10,12));
|
||||
setValue("level-choice",level);
|
||||
save_skp = true;
|
||||
|
@ -193,7 +214,7 @@ async function parse_hash(url_tag) {
|
|||
if (version_number >= 6) {
|
||||
//tome values do not appear in anything before v6.
|
||||
if (version_number < 8) {
|
||||
for (let i in tomes) {
|
||||
for (let i = 0; i < 7; ++i) {
|
||||
let tome_str = data_str.charAt(i);
|
||||
let tome_name = getTomeNameFromID(Base64.toInt(tome_str));
|
||||
setValue(tomeInputs[i], tome_name);
|
||||
|
@ -202,12 +223,21 @@ async function parse_hash(url_tag) {
|
|||
}
|
||||
else {
|
||||
// 2chr tome encoding to allow for more tomes.
|
||||
for (let i in tomes) {
|
||||
|
||||
// Lootrun tome was added in v9.
|
||||
let num_tomes = 7;
|
||||
if (version_number <= 8) {
|
||||
num_tomes = 7;
|
||||
}
|
||||
else {
|
||||
num_tomes = 8;
|
||||
}
|
||||
for (let i = 0; i < num_tomes; ++i) {
|
||||
let tome_str = data_str.slice(2*i, 2*i+2);
|
||||
let tome_name = getTomeNameFromID(Base64.toInt(tome_str));
|
||||
setValue(tomeInputs[i], tome_name);
|
||||
}
|
||||
data_str = data_str.slice(14);
|
||||
data_str = data_str.slice(num_tomes*2);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -232,119 +262,80 @@ async function parse_hash(url_tag) {
|
|||
/* Stores the entire build in a string using B64 encoding and adds it to the URL.
|
||||
*/
|
||||
function encodeBuild(build, powders, skillpoints, atree, atree_state) {
|
||||
//currently on version 8 - a unified version for all build types using bit-level encoding
|
||||
|
||||
if (build) {
|
||||
//final link will be [build_vers]_[len_string]_[build_string]
|
||||
build_version = 8;
|
||||
let len_string = "";
|
||||
let build_string = "";
|
||||
let build_bits = new BitVector(0, 0);
|
||||
let build_string;
|
||||
|
||||
//V6 encoding - Tomes
|
||||
//V7 encoding - ATree
|
||||
//V8 encoding - wynn version
|
||||
//V9 encoding - lootrun tome
|
||||
build_version = 9;
|
||||
build_string = "";
|
||||
tome_string = "";
|
||||
|
||||
//ITEMS
|
||||
for (const item of build.items) {
|
||||
if (item.statMap.get("NONE") && item.statMap.get("NONE") === true) {
|
||||
build_bits.append(0, 2); //00
|
||||
} else if (item.statMap.get("custom")) {
|
||||
build_bits.append(3, 2); //11
|
||||
//BitVector CI encoding TODO
|
||||
|
||||
// let custom = "CI-"+encodeCustom(item, true);
|
||||
// build_string += Base64.fromIntN(custom.length, 3) + custom;
|
||||
// build_version = Math.max(build_version, 5);
|
||||
if (item.statMap.get("custom")) {
|
||||
let custom = "CI-"+encodeCustom(item, true);
|
||||
build_string += Base64.fromIntN(custom.length, 3) + custom;
|
||||
//build_version = Math.max(build_version, 5);
|
||||
} else if (item.statMap.get("crafted")) {
|
||||
build_bits.append(2, 2); //10
|
||||
//BitVector CR encoding TODO
|
||||
|
||||
// build_string += "CR-"+encodeCraft(item);
|
||||
build_string += "CR-"+encodeCraft(item);
|
||||
} else if (item.statMap.get("category") === "tome") {
|
||||
let tome_id = item.statMap.get("id");
|
||||
//if (tome_id <= 60) {
|
||||
// valid normal tome. ID 61-63 is for NONE tomes.
|
||||
//build_version = Math.max(build_version, 6);
|
||||
//}
|
||||
tome_string += Base64.fromIntN(tome_id, 2);
|
||||
} else {
|
||||
if (item.statMap.get("category") === "tome") {
|
||||
//we will encode tomes later
|
||||
continue;
|
||||
} else {
|
||||
build_bits.append(1, 2); //01
|
||||
build_bits.append(item.statMap.get("id"), 13);
|
||||
build_string += Base64.fromIntN(item.statMap.get("id"), 3);
|
||||
}
|
||||
}
|
||||
|
||||
//powderable
|
||||
if (powderable_keys.includes(item.statMap.get("type"))) {
|
||||
if (item.statMap.get("powders") && item.statMap.get("powders").length !== 0) {
|
||||
//has powders
|
||||
build_bits.append(1, 1);
|
||||
|
||||
//num of powders in 8 bits, then each powder (6 bits)
|
||||
//Having more than 256 powders on a vanilla item is NOT HANDLED.
|
||||
build_bits.append(item.statMap.get("powders").length, 8);
|
||||
for (const powder of item.statMap.get("powders")) {
|
||||
build_bits.append(powder, 6);
|
||||
}
|
||||
} else {
|
||||
//no powders
|
||||
build_bits.append(0, 1);
|
||||
}
|
||||
}
|
||||
for (const skp of skillpoints) {
|
||||
build_string += Base64.fromIntN(skp, 2); // Maximum skillpoints: 2048
|
||||
}
|
||||
build_string += Base64.fromIntN(build.level, 2);
|
||||
for (const _powderset of powders) {
|
||||
let n_bits = Math.ceil(_powderset.length / 6);
|
||||
build_string += Base64.fromIntN(n_bits, 1); // Hard cap of 378 powders.
|
||||
// Slice copy.
|
||||
let powderset = _powderset.slice();
|
||||
while (powderset.length != 0) {
|
||||
let firstSix = powderset.slice(0,6).reverse();
|
||||
let powder_hash = 0;
|
||||
for (const powder of firstSix) {
|
||||
powder_hash = (powder_hash << 5) + 1 + powder; // LSB will be extracted first.
|
||||
}
|
||||
build_string += Base64.fromIntN(powder_hash, 5);
|
||||
powderset = powderset.slice(6);
|
||||
}
|
||||
}
|
||||
build_string += tome_string;
|
||||
|
||||
//SKILL POINTS
|
||||
|
||||
//the original schema included a flag to indicate whether or not skill points are included.
|
||||
//any reason for having a flag isn't implemented yet, so for now every build will have the skill point flag set.
|
||||
build_bits.append(1, 1);
|
||||
|
||||
for (const skp of build.base_skillpoints) {
|
||||
build_bits.append(skp, 8); // Maximum skillpoints: 255 (allows for manual assign up to 150)
|
||||
}
|
||||
|
||||
//BUILD LEVEL
|
||||
|
||||
// [flag to indicate if level is not 106 (0/1)]
|
||||
// [else: level (7 bits, allows for lv 1->127)]
|
||||
if (player_build.level != 106) {
|
||||
build_bits.append(1, 1);
|
||||
build_bits.append(player_build.level, 7);
|
||||
} else {
|
||||
build_bits.append(0, 1);
|
||||
}
|
||||
|
||||
// TOMES
|
||||
|
||||
// [flag to indicate if tomes are included (0/1)]
|
||||
// [if set: 7 sequential tome IDs, each 6 bits unsigned]
|
||||
if (build.tomes.length > 0) {
|
||||
build_bits.append(1, 1);
|
||||
//decoding will assume that tomes has length of 7.
|
||||
for (const tome of build.tomes) {
|
||||
build_bits.append(tome.id, 6);
|
||||
}
|
||||
} else {
|
||||
build_bits.append(0, 1);
|
||||
}
|
||||
|
||||
// ATREE
|
||||
|
||||
// [flag to indicate if atree data is present]
|
||||
// [atree data: see existing encoding impl] //idk the impl
|
||||
if (atree.length > 0 && atree_state.get(atree[0].ability.id).active) {
|
||||
build_bits.append(1, 1);
|
||||
const atree_bitvec = encode_atree(atree, atree_state);
|
||||
build_bits.append(atree_bitvec);
|
||||
} else {
|
||||
build_bits.append(0, 1);
|
||||
//build_version = Math.max(build_version, 7);
|
||||
const bitvec = encode_atree(atree, atree_state);
|
||||
build_string += bitvec.toB64();
|
||||
}
|
||||
|
||||
//compute length and return final build hash
|
||||
return build_version.toString() + "_" + len_string + "_" + build_string;
|
||||
return build_version.toString() + "_" + build_string;
|
||||
}
|
||||
}
|
||||
|
||||
function get_full_url() {
|
||||
return `${url_base}?v=${wynn_version_id.toString()}${location.hash}`
|
||||
}
|
||||
|
||||
function copyBuild() {
|
||||
copyTextToClipboard(url_base+location.hash);
|
||||
copyTextToClipboard(get_full_url());
|
||||
document.getElementById("copy-button").textContent = "Copied!";
|
||||
}
|
||||
|
||||
function shareBuild(build) {
|
||||
if (build) {
|
||||
let text = url_base+location.hash+"\n"+
|
||||
let text = get_full_url()+"\n"+
|
||||
"WynnBuilder build:\n"+
|
||||
"> "+build.items[0].statMap.get("displayName")+"\n"+
|
||||
"> "+build.items[1].statMap.get("displayName")+"\n"+
|
||||
|
@ -354,7 +345,13 @@ function shareBuild(build) {
|
|||
"> "+build.items[5].statMap.get("displayName")+"\n"+
|
||||
"> "+build.items[6].statMap.get("displayName")+"\n"+
|
||||
"> "+build.items[7].statMap.get("displayName")+"\n"+
|
||||
"> "+build.items[15].statMap.get("displayName")+" ["+build_powders[4].map(x => powderNames.get(x)).join("")+"]";
|
||||
"> "+build.items[16].statMap.get("displayName")+" ["+build_powders[4].map(x => powderNames.get(x)).join("")+"]\n";
|
||||
for (let tomeslots = 8; tomeslots < 16; tomeslots++) {
|
||||
if (!build.items[tomeslots].statMap.has('NONE')) {
|
||||
text += ">"+' (Has Tomes)' ;
|
||||
break;
|
||||
}
|
||||
}
|
||||
copyTextToClipboard(text);
|
||||
document.getElementById("share-button").textContent = "Copied!";
|
||||
}
|
||||
|
|
|
@ -89,13 +89,12 @@ function resetFields(){
|
|||
}
|
||||
}
|
||||
for (const elem of skp_order) {
|
||||
console.log(document.getElementById(elem + "_boost_armor").value);
|
||||
document.getElementById(elem + "_boost_armor").value = 0;
|
||||
document.getElementById(elem + "_boost_armor").style.background = `linear-gradient(to right, #AAAAAA, #AAAAAA 0%, #AAAAAA 100%)`;
|
||||
document.getElementById(elem + "_boost_armor_label").textContent = `% ${damageClasses[skp_order.indexOf(elem)+1]} Damage Boost: 0`;
|
||||
}
|
||||
|
||||
const nodes_to_reset = item_nodes.concat(powder_nodes).concat(edit_input_nodes).concat([powder_special_input, boosts_node, armor_powder_node]);
|
||||
const nodes_to_reset = equip_inputs.concat(powder_nodes).concat(edit_input_nodes).concat([powder_special_input, boosts_node, armor_powder_node]);
|
||||
for (const node of nodes_to_reset) {
|
||||
node.mark_dirty();
|
||||
}
|
||||
|
@ -231,8 +230,10 @@ function init_autocomplete() {
|
|||
}
|
||||
let tome_alias = tome_obj['alias'];
|
||||
tome_arr.push(tome_name);
|
||||
tome_arr.push(tome_alias);
|
||||
tome_aliases.set(tome_alias, tome_name);
|
||||
if (tome_alias) {
|
||||
tome_arr.push(tome_alias);
|
||||
tome_aliases.set(tome_alias, tome_name);
|
||||
}
|
||||
}
|
||||
|
||||
// create dropdown
|
||||
|
@ -368,7 +369,7 @@ async function init() {
|
|||
console.log(e);
|
||||
}
|
||||
builder_graph_init(save_skp);
|
||||
for (const item_node of item_nodes) {
|
||||
for (const item_node of item_final_nodes) {
|
||||
if (item_node.get_value() === null) {
|
||||
// likely DB load failure...
|
||||
if (confirm('One or more items failed to load correctly. This could be due to a corrupted build link, or (more likely) a database load failure. Would you like to reload?')) {
|
||||
|
|
|
@ -12,7 +12,7 @@ const BUILD_VERSION = "7.0.19";
|
|||
let editable_item_fields = [ "sdPct", "sdRaw", "mdPct", "mdRaw", "poison",
|
||||
"fDamPct", "wDamPct", "aDamPct", "tDamPct", "eDamPct",
|
||||
"fDefPct", "wDefPct", "aDefPct", "tDefPct", "eDefPct",
|
||||
"hprRaw", "hprPct", "hpBonus", "atkTier",
|
||||
"hprRaw", "hprPct", "hpBonus", "atkTier", "ls",
|
||||
"spPct1", "spRaw1", "spPct2", "spRaw2",
|
||||
"spPct3", "spRaw3", "spPct4", "spRaw4" ];
|
||||
|
||||
|
@ -60,6 +60,7 @@ let tome_fields = [
|
|||
"armorTome3",
|
||||
"armorTome4",
|
||||
"guildTome1",
|
||||
"lootrunTome1"
|
||||
]
|
||||
let equipment_names = [
|
||||
"Helmet",
|
||||
|
@ -99,7 +100,7 @@ let armor_keys = ['helmet', 'chestplate', 'leggings', 'boots'];
|
|||
let accessory_keys= ['ring1', 'ring2', 'bracelet', 'necklace'];
|
||||
let powderable_keys = ['helmet', 'chestplate', 'leggings', 'boots', 'weapon'];
|
||||
let equipment_keys = ['helmet', 'chestplate', 'leggings', 'boots', 'ring1', 'ring2', 'bracelet', 'necklace', 'weapon'];
|
||||
let tome_keys = ['weaponTome1', 'weaponTome2', 'armorTome1', 'armorTome2', 'armorTome3', 'armorTome4', 'guildTome1'];
|
||||
let tome_keys = ['weaponTome1', 'weaponTome2', 'armorTome1', 'armorTome2', 'armorTome3', 'armorTome4', 'guildTome1', 'lootrunTome1'];
|
||||
|
||||
let spell_disp = ['build-melee-stats', 'spell0-info', 'spell1-info', 'spell2-info', 'spell3-info'];
|
||||
let other_disp = ['build-order', 'set-info', 'int-info'];
|
||||
|
|
|
@ -17,7 +17,7 @@ let armor_powder_node = new (class extends ComputeNode {
|
|||
}
|
||||
})();
|
||||
|
||||
const damageMultipliers = new Map([ ["totem", 0.2], ["warscream", 0.0], ["ragnarokkr", 0.30], ["fortitude", 0.60], ["radiance", 0.0] ]);
|
||||
const damageMultipliers = new Map([ ["totem", 0.2], ["warscream", 0.0], ["ragnarokkr", 0.20], ["fortitude", 0.60], ["radiance", 0.0] ]);
|
||||
|
||||
let boosts_node = new (class extends ComputeNode {
|
||||
constructor() { super('builder-boost-input'); }
|
||||
|
@ -117,7 +117,7 @@ class PowderSpecialDisplayNode extends ComputeNode {
|
|||
const powder_specials = input_map.get('powder-specials');
|
||||
const stats = input_map.get('stats');
|
||||
const weapon = input_map.get('build').weapon;
|
||||
displayPowderSpecials(document.getElementById("powder-special-stats"), powder_specials, stats, weapon.statMap, true);
|
||||
displayPowderSpecials(document.getElementById("powder-special-stats"), powder_specials, stats, weapon.statMap);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -183,7 +183,7 @@ class ItemInputNode extends InputNode {
|
|||
|
||||
for (const [i, x] of zip2(equipment_inputs, replace_items)) { setValue(i, x); }
|
||||
|
||||
for (const node of item_nodes) {
|
||||
for (const node of equip_inputs) {
|
||||
if (node !== this) {
|
||||
// save a tiny bit of compute
|
||||
calcSchedule(node, 10);
|
||||
|
@ -413,7 +413,8 @@ class BuildAssembleNode extends ComputeNode {
|
|||
input_map.get('armorTome2'),
|
||||
input_map.get('armorTome3'),
|
||||
input_map.get('armorTome4'),
|
||||
input_map.get('guildTome1')
|
||||
input_map.get('guildTome1'),
|
||||
input_map.get('lootrunTome1')
|
||||
];
|
||||
let weapon = input_map.get('weapon');
|
||||
let level = parseInt(input_map.get('level-input'));
|
||||
|
@ -428,7 +429,7 @@ class BuildAssembleNode extends ComputeNode {
|
|||
if (all_none && !location.hash) {
|
||||
return null;
|
||||
}
|
||||
return new Build(level, equipments, tomes, weapon);
|
||||
return new Build(level, equipments, weapon);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -500,28 +501,6 @@ class PowderInputNode extends InputNode {
|
|||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Select a spell+spell "variation" based on a build / spell idx.
|
||||
* Right now this isn't much logic and is only used to abstract away major id interactions
|
||||
* but will become significantly more complex in wynn2.
|
||||
*
|
||||
* Signature: SpellSelectNode<int>(build: Build) => [Spell, SpellParts]
|
||||
*/
|
||||
class SpellSelectNode extends ComputeNode {
|
||||
constructor(spell) {
|
||||
super("builder-spell"+spell.base_spell+"-select");
|
||||
this.spell = spell;
|
||||
}
|
||||
|
||||
compute_func(input_map) {
|
||||
const build = input_map.get('build');
|
||||
let stats = build.statMap;
|
||||
// TODO: apply major ids... DOOM.....
|
||||
|
||||
return [this.spell, this.spell.parts];
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Get all defensive stats for this build.
|
||||
*/
|
||||
|
@ -550,7 +529,8 @@ function getDefenseStats(stats) {
|
|||
defenseStats.push(totalHpr);
|
||||
//EHPR
|
||||
let ehpr = [totalHpr, totalHpr];
|
||||
ehpr[0] /= (1-def_pct)*(1-agi_pct)*defMult;
|
||||
ehpr[0] = ehpr[0] / (0.1*agi_pct + (1-agi_pct) * (1-def_pct));
|
||||
ehpr[0] /= defMult;
|
||||
ehpr[1] /= (1-def_pct)*defMult;
|
||||
defenseStats.push(ehpr);
|
||||
//skp stats
|
||||
|
@ -558,7 +538,7 @@ function getDefenseStats(stats) {
|
|||
//eledefs - TODO POWDERS
|
||||
let eledefs = [0, 0, 0, 0, 0];
|
||||
for(const i in skp_elements){ //kinda jank but ok
|
||||
eledefs[i] = rawToPct(stats.get(skp_elements[i] + "Def"), stats.get(skp_elements[i] + "DefPct")/100.);
|
||||
eledefs[i] = rawToPct(stats.get(skp_elements[i] + "Def"), (stats.get(skp_elements[i] + "DefPct") + stats.get("rDefPct"))/100.);
|
||||
}
|
||||
defenseStats.push(eledefs);
|
||||
|
||||
|
@ -575,15 +555,15 @@ function getDefenseStats(stats) {
|
|||
* spell-info: [Spell, SpellParts]) => List[SpellDamage]
|
||||
*/
|
||||
class SpellDamageCalcNode extends ComputeNode {
|
||||
constructor(spell_num) {
|
||||
super("builder-spell"+spell_num+"-calc");
|
||||
constructor(spell) {
|
||||
super("builder-spell"+spell.base_spell+"-calc");
|
||||
this.spell = spell;
|
||||
}
|
||||
|
||||
compute_func(input_map) {
|
||||
const weapon = input_map.get('build').weapon.statMap;
|
||||
const spell_info = input_map.get('spell-info');
|
||||
const spell = spell_info[0];
|
||||
const spell_parts = spell_info[1];
|
||||
const spell = this.spell;
|
||||
const spell_parts = spell.parts;
|
||||
const stats = input_map.get('stats');
|
||||
const skillpoints = [
|
||||
stats.get('str'),
|
||||
|
@ -592,13 +572,26 @@ class SpellDamageCalcNode extends ComputeNode {
|
|||
stats.get('def'),
|
||||
stats.get('agi')
|
||||
];
|
||||
let spell_results = []
|
||||
let display_spell_results = []
|
||||
let spell_result_map = new Map();
|
||||
const use_speed = (('use_atkspd' in spell) ? spell.use_atkspd : true);
|
||||
const use_spell = (('scaling' in spell) ? spell.scaling === 'spell' : true);
|
||||
|
||||
// TODO: move preprocessing to separate node/node chain
|
||||
for (const part of spell_parts) {
|
||||
const {name, display=true} = part;
|
||||
spell_result_map.set(name, {type: "need_eval", store_part: part});
|
||||
}
|
||||
|
||||
function eval_part(part_name) {
|
||||
let dat = spell_result_map.get(part_name);
|
||||
if (!dat) {
|
||||
return dat; // return null, or undefined, or whatever it is that this gives
|
||||
}
|
||||
if (dat.type !== "need_eval") {
|
||||
return dat; // Already evaluated. Return it
|
||||
}
|
||||
|
||||
let part = dat.store_part;
|
||||
let spell_result;
|
||||
const part_id = spell.base_spell + '.' + part.name
|
||||
if ('multipliers' in part) { // damage type spell
|
||||
|
@ -614,65 +607,70 @@ class SpellDamageCalcNode extends ComputeNode {
|
|||
}
|
||||
} else if ('power' in part) {
|
||||
// TODO: wynn2 formula
|
||||
let _heal_amount = (part.power * getDefenseStats(stats)[0] * (1+stats.get('healPct')/100));
|
||||
if (stats.has('healPct:'+part_id)) {
|
||||
_heal_amount *= 1+(stats.get('healPct:'+part_id)/100);
|
||||
const mult_map = stats.get("healMult");
|
||||
let heal_mult = 1;
|
||||
for (const [k, v] of mult_map.entries()) {
|
||||
if (k.includes(':')) {
|
||||
// TODO: fragile... checking for specific part multipliers.
|
||||
const spell_match = k.split(':')[1];
|
||||
if (spell_match !== part_id) {
|
||||
continue;
|
||||
}
|
||||
}
|
||||
heal_mult *= (1 + v/100);
|
||||
}
|
||||
let _heal_amount = part.power * getDefenseStats(stats)[0] * heal_mult;
|
||||
spell_result = {
|
||||
type: "heal",
|
||||
heal_amount: _heal_amount
|
||||
}
|
||||
}
|
||||
else {
|
||||
continue;
|
||||
}
|
||||
const {name, display = true} = part;
|
||||
spell_result.name = name;
|
||||
spell_result.display = display;
|
||||
spell_results.push(spell_result);
|
||||
spell_result_map.set(name, spell_result);
|
||||
}
|
||||
for (const part of spell_parts) {
|
||||
if (!('hits' in part)) { continue; }
|
||||
let spell_result = {
|
||||
normal_min: [0, 0, 0, 0, 0, 0],
|
||||
normal_max: [0, 0, 0, 0, 0, 0],
|
||||
normal_total: [0, 0],
|
||||
crit_min: [0, 0, 0, 0, 0, 0],
|
||||
crit_max: [0, 0, 0, 0, 0, 0],
|
||||
crit_total: [0, 0],
|
||||
heal_amount: 0
|
||||
}
|
||||
const dam_res_keys = ['normal_min', 'normal_max', 'normal_total', 'crit_min', 'crit_max', 'crit_total'];
|
||||
for (const [subpart_name, hits] of Object.entries(part.hits)) {
|
||||
const subpart = spell_result_map.get(subpart_name);
|
||||
if (!subpart) { continue; }
|
||||
if (spell_result.type) {
|
||||
if (subpart.type !== spell_result.type) {
|
||||
throw "SpellCalc total subpart type mismatch";
|
||||
}
|
||||
} else { // if 'hits' in part
|
||||
spell_result = {
|
||||
normal_min: [0, 0, 0, 0, 0, 0],
|
||||
normal_max: [0, 0, 0, 0, 0, 0],
|
||||
normal_total: [0, 0],
|
||||
crit_min: [0, 0, 0, 0, 0, 0],
|
||||
crit_max: [0, 0, 0, 0, 0, 0],
|
||||
crit_total: [0, 0],
|
||||
heal_amount: 0
|
||||
}
|
||||
else {
|
||||
spell_result.type = subpart.type;
|
||||
}
|
||||
if (spell_result.type === 'damage') {
|
||||
for (const key of dam_res_keys) {
|
||||
for (let i in spell_result.normal_min) {
|
||||
spell_result[key][i] += subpart[key][i] * hits;
|
||||
const dam_res_keys = ['normal_min', 'normal_max', 'normal_total', 'crit_min', 'crit_max', 'crit_total'];
|
||||
for (const [subpart_name, hits] of Object.entries(part.hits)) {
|
||||
const subpart = eval_part(subpart_name);
|
||||
if (!subpart) { continue; }
|
||||
if (spell_result.type) {
|
||||
if (subpart.type !== spell_result.type) {
|
||||
throw "SpellCalc total subpart type mismatch";
|
||||
}
|
||||
}
|
||||
}
|
||||
else {
|
||||
spell_result.heal_amount += subpart.heal_amount * hits;
|
||||
else {
|
||||
spell_result.type = subpart.type;
|
||||
}
|
||||
if (spell_result.type === 'damage') {
|
||||
for (const key of dam_res_keys) {
|
||||
for (let i in spell_result.normal_min) {
|
||||
spell_result[key][i] += subpart[key][i] * hits;
|
||||
}
|
||||
}
|
||||
}
|
||||
else {
|
||||
spell_result.heal_amount += subpart.heal_amount * hits;
|
||||
}
|
||||
}
|
||||
}
|
||||
const {name, display = true} = part;
|
||||
spell_result.name = name;
|
||||
spell_result.display = display;
|
||||
spell_results.push(spell_result);
|
||||
spell_result_map.set(name, spell_result);
|
||||
return spell_result;
|
||||
}
|
||||
return spell_results;
|
||||
|
||||
// TODO: move preprocessing to separate node/node chain
|
||||
for (const part of spell_parts) {
|
||||
let spell_result = eval_part(part.name);
|
||||
display_spell_results.push(spell_result);
|
||||
}
|
||||
return display_spell_results;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -686,18 +684,17 @@ class SpellDamageCalcNode extends ComputeNode {
|
|||
* spell-damage: List[SpellDamage]) => null
|
||||
*/
|
||||
class SpellDisplayNode extends ComputeNode {
|
||||
constructor(spell_num) {
|
||||
super("builder-spell"+spell_num+"-display");
|
||||
this.spell_idx = spell_num;
|
||||
constructor(spell) {
|
||||
super("builder-spell"+spell.base_spell+"-display");
|
||||
this.spell = spell;
|
||||
}
|
||||
|
||||
compute_func(input_map) {
|
||||
const stats = input_map.get('stats');
|
||||
const spell_info = input_map.get('spell-info');
|
||||
const damages = input_map.get('spell-damage');
|
||||
const spell = spell_info[0];
|
||||
const spell = this.spell;
|
||||
|
||||
const i = this.spell_idx;
|
||||
const i = this.spell.base_spell;
|
||||
let parent_elem = document.getElementById("spell"+i+"-info");
|
||||
let overallparent_elem = document.getElementById("spell"+i+"-infoAvg");
|
||||
displaySpellDamage(parent_elem, overallparent_elem, stats, spell, i, damages);
|
||||
|
@ -847,9 +844,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",
|
||||
|
@ -861,7 +862,8 @@ let radiance_affected = [ /*"hp"*/, "fDef", "wDef", "aDef", "tDef", "eDef", "hpr
|
|||
/*"mdPct","mdRaw","sdPct","sdRaw",*/"damPct","damRaw",//"damAddMin","damAddMax", // These are the old ids. Become proportional.
|
||||
"rMdPct","rMdRaw","rSdPct",/*"rSdRaw",*/"rDamPct","rDamRaw",//"rDamAddMin","rDamAddMax", // rainbow (the "element" of all minus neutral). rSdRaw is rainraw
|
||||
"critDamPct",
|
||||
//"spPct1Final", "spPct2Final", "spPct3Final", "spPct4Final"
|
||||
//"spPct1Final", "spPct2Final", "spPct3Final", "spPct4Final",
|
||||
"healPct", "kb", "weakenEnemy", "slowEnemy", "rDefPct"
|
||||
];
|
||||
/**
|
||||
* Scale stats if radiance is enabled.
|
||||
|
@ -887,12 +889,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 {
|
||||
|
@ -951,6 +953,7 @@ class EditableIDSetterNode extends ComputeNode {
|
|||
this.notify_nodes = notify_nodes.slice();
|
||||
for (const child of this.notify_nodes) {
|
||||
child.link_to(this);
|
||||
child.fail_cb = true;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -987,6 +990,9 @@ class SkillPointSetterNode extends ComputeNode {
|
|||
this.notify_nodes = notify_nodes.slice();
|
||||
for (const child of this.notify_nodes) {
|
||||
child.link_to(this);
|
||||
child.fail_cb = true;
|
||||
// This is needed because initially there is a value mismatch possibly... due to setting skillpoints manually
|
||||
child.mark_input_clean(this.name, null);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1029,8 +1035,7 @@ class SumNumberInputNode extends InputNode {
|
|||
}
|
||||
}
|
||||
|
||||
let item_nodes = [];
|
||||
let item_nodes_map = new Map();
|
||||
let item_final_nodes = [];
|
||||
let powder_nodes = [];
|
||||
let edit_input_nodes = [];
|
||||
let skp_inputs = [];
|
||||
|
@ -1052,9 +1057,9 @@ function builder_graph_init(save_skp) {
|
|||
|
||||
// "Build" now only refers to equipment and level (no powders). Powders are injected before damage calculation / stat display.
|
||||
build_node = new BuildAssembleNode();
|
||||
for (const input of item_nodes) {
|
||||
}
|
||||
build_node.link_to(level_input);
|
||||
atree_merge.link_to(build_node, "build");
|
||||
|
||||
|
||||
let build_encode_node = new BuildEncodeNode();
|
||||
build_encode_node.link_to(build_node, 'build');
|
||||
|
@ -1076,8 +1081,7 @@ function builder_graph_init(save_skp) {
|
|||
.link_to(powder_node, 'powdering').link_to(item_input, 'item');
|
||||
item_input = item_powdering;
|
||||
}
|
||||
item_nodes.push(item_input);
|
||||
item_nodes_map.set(eq, item_input);
|
||||
item_final_nodes.push(item_input);
|
||||
new ItemInputDisplayNode(eq+'-input-display', eq, item_image).link_to(item_input);
|
||||
new ItemDisplayNode(eq+'-item-display', display_elem).link_to(item_input);
|
||||
//new PrintNode(eq+'-debug').link_to(item_input);
|
||||
|
@ -1085,13 +1089,13 @@ function builder_graph_init(save_skp) {
|
|||
build_node.link_to(item_input, eq);
|
||||
}
|
||||
|
||||
for (const [eq, none_item] of zip2(tome_fields, [none_tomes[0], none_tomes[0], none_tomes[1], none_tomes[1], none_tomes[1], none_tomes[1], none_tomes[2]])) {
|
||||
for (const [eq, none_item] of zip2(tome_fields, [none_tomes[0], none_tomes[0], none_tomes[1], none_tomes[1], none_tomes[1], none_tomes[1], none_tomes[2], none_tomes[3]])) {
|
||||
let input_field = document.getElementById(eq+"-choice");
|
||||
let item_image = document.getElementById(eq+"-img");
|
||||
|
||||
let item_input = new ItemInputNode(eq+'-input', input_field, none_item);
|
||||
equip_inputs.push(item_input);
|
||||
item_nodes.push(item_input);
|
||||
item_final_nodes.push(item_input);
|
||||
new ItemInputDisplayNode(eq+'-input-display', eq, item_image).link_to(item_input);
|
||||
build_node.link_to(item_input, eq);
|
||||
}
|
||||
|
@ -1099,7 +1103,7 @@ function builder_graph_init(save_skp) {
|
|||
// weapon image changer node.
|
||||
let weapon_image = document.getElementById("weapon-img");
|
||||
let weapon_dps = document.getElementById("weapon-dps");
|
||||
new WeaponInputDisplayNode('weapon-type', weapon_image, weapon_dps).link_to(item_nodes[8]);
|
||||
new WeaponInputDisplayNode('weapon-type-display', weapon_image, weapon_dps).link_to(item_final_nodes[8]);
|
||||
|
||||
// linking to atree verification
|
||||
atree_validate.link_to(level_input, 'level');
|
||||
|
|
601
js/builder/major_ids_clean.json
Normal file
601
js/builder/major_ids_clean.json
Normal file
|
@ -0,0 +1,601 @@
|
|||
{
|
||||
"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",
|
||||
"abilities": []
|
||||
},
|
||||
"PLAGUE": {
|
||||
"displayName": "Plague",
|
||||
"description": "Poisoned mobs spread their poison to nearby mobs",
|
||||
"abilities": []
|
||||
},
|
||||
"HAWKEYE": {
|
||||
"displayName": "Hawkeye",
|
||||
"description": "Condense Arrow Storm into a tight beam. Arrows deal ✤10%, ✦1%, and ❋1%",
|
||||
"abilities": [{
|
||||
"class": "Archer",
|
||||
"base_abil": "Arrow Storm",
|
||||
"effects": [
|
||||
{
|
||||
"type": "add_spell_prop",
|
||||
"base_spell": 1,
|
||||
"target_part": "Single Stream",
|
||||
"behavior": "overwrite",
|
||||
"hits": { "Single Arrow": 5 }
|
||||
},
|
||||
{
|
||||
"type": "add_spell_prop",
|
||||
"base_spell": 1,
|
||||
"target_part": "Single Arrow",
|
||||
"behavior": "overwrite",
|
||||
"multipliers": [ 10, 0, 1, 0, 0, 1 ]
|
||||
},
|
||||
{
|
||||
"type": "add_spell_prop",
|
||||
"base_spell": 1,
|
||||
"target_part": "Total Damage",
|
||||
"behavior": "modify",
|
||||
"hits": { "Single Stream": 4 }
|
||||
}
|
||||
]
|
||||
}]
|
||||
},
|
||||
"GREED": {
|
||||
"displayName": "Greed",
|
||||
"description": "Picking up emeralds heals you and nearby players for 15% max health",
|
||||
"abilities": []
|
||||
},
|
||||
"CAVALRYMAN": {
|
||||
"displayName": "Cavalryman",
|
||||
"description": "You may cast spells and attack with a 70% damage penalty while on a horse",
|
||||
"abilities": []
|
||||
},
|
||||
"GUARDIAN": {
|
||||
"displayName": "Guardian",
|
||||
"description": "20% of the damage taken by nearby allies is redirected to you",
|
||||
"abilities": []
|
||||
},
|
||||
"HERO": {
|
||||
"displayName": "Saviour’s Sacrifice",
|
||||
"description": "While under 50% maximum health, nearby allies gain 20% bonus damage and defense",
|
||||
"abilities": []
|
||||
},
|
||||
"ALTRUISM": {
|
||||
"displayName": "Heart of the Pack",
|
||||
"description": "Nearby players gain 35% of the health you naturally regenerate",
|
||||
"abilities": []
|
||||
},
|
||||
"ARCANES": {
|
||||
"displayName": "Transcendence",
|
||||
"description": "30% chance for spells to cost no mana when casted",
|
||||
"abilities": []
|
||||
},
|
||||
"ENTROPY": {
|
||||
"displayName": "Entropy",
|
||||
"description": "Meteor falls three times faster",
|
||||
"abilities": []
|
||||
},
|
||||
"ROVINGASSASSIN": {
|
||||
"displayName": "Roving Assassin",
|
||||
"description": "Vanish no longer drains mana while invisible",
|
||||
"abilities": []
|
||||
},
|
||||
"MADNESS": {
|
||||
"displayName": "Madness",
|
||||
"description": "Cast a random ability every 3 seconds",
|
||||
"abilities": []
|
||||
},
|
||||
"LIGHTWEIGHT": {
|
||||
"displayName": "Lightweight",
|
||||
"description": "You no longer take fall damage",
|
||||
"abilities": []
|
||||
},
|
||||
"SORCERY": {
|
||||
"displayName": "Sorcery",
|
||||
"description": "30% chance for spells and attacks to cast a second time at no additional cost",
|
||||
"abilities": []
|
||||
},
|
||||
"TAUNT": {
|
||||
"displayName": "Taunt",
|
||||
"description": "Mobs within 12 blocks target you upon casting War Scream",
|
||||
"abilities": []
|
||||
},
|
||||
"RALLY": {
|
||||
"displayName": "Rally",
|
||||
"description": "Charge heals you by 10% and nearby allies by 15% on impact, but becomes harmless",
|
||||
"abilities": [{
|
||||
"class": "Warrior",
|
||||
"base_abil": "Charge",
|
||||
"effects": [
|
||||
{
|
||||
"type": "add_spell_prop",
|
||||
"base_spell": 2,
|
||||
"display": "Rally Self Heal",
|
||||
"target_part": "Rally Self Heal",
|
||||
"power": 0.1
|
||||
},
|
||||
{
|
||||
"type": "add_spell_prop",
|
||||
"base_spell": 2,
|
||||
"target_part": "Rally Ally Heal",
|
||||
"power": 0.15
|
||||
},
|
||||
{
|
||||
"type": "raw_stat",
|
||||
"bonuses": [
|
||||
{
|
||||
"type": "stat",
|
||||
"name": "damMult.Rally:2.Flying Kick",
|
||||
"value": -100
|
||||
},
|
||||
{
|
||||
"type": "stat",
|
||||
"name": "damMult.Rally:2.Collide",
|
||||
"value": -100
|
||||
},
|
||||
{
|
||||
"type": "stat",
|
||||
"name": "damMult.Rally:2.Heavy Impact",
|
||||
"value": -100
|
||||
},
|
||||
{
|
||||
"type": "stat",
|
||||
"name": "damMult.Rally:2.Flyby Jab",
|
||||
"value": -100
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}]
|
||||
},
|
||||
"CHERRY_BOMBS": {
|
||||
"displayName": "Cherry Bombs",
|
||||
"description": "Turn Smoke Bomb into three firecrackers that fly farther, tighter, and deal high damage instantly",
|
||||
"abilities": [{
|
||||
"class": "Assassin",
|
||||
"base_abil": "Smoke Bomb",
|
||||
"effects": [{
|
||||
"type": "replace_spell",
|
||||
"name": "Cherry Bomb",
|
||||
"cost": 35,
|
||||
"base_spell": 4,
|
||||
"display": "Total Damage",
|
||||
"parts": [
|
||||
{
|
||||
"name": "Single Bomb",
|
||||
"type": "damage",
|
||||
"multipliers": [95, 40, 0, 0, 0, 40]
|
||||
},
|
||||
{
|
||||
"name": "Total Damage",
|
||||
"type": "total",
|
||||
"hits": {
|
||||
"Single Bomb": 3
|
||||
}
|
||||
}
|
||||
]
|
||||
}]
|
||||
}]
|
||||
},
|
||||
"FREERUNNER": {
|
||||
"displayName": "Freerunner",
|
||||
"description": "Double your sprint speed when your sprint bar is under 30%",
|
||||
"abilities": []
|
||||
},
|
||||
"PEACEFUL_EFFIGY": {
|
||||
"displayName": "Peaceful Effigy",
|
||||
"description": "Your totem will last twice as long",
|
||||
"abilities": []
|
||||
},
|
||||
"FURIOUS_EFFIGY": {
|
||||
"displayName": "Furious Effigy",
|
||||
"description": "Totem effects are twice as fast, but duration is halved",
|
||||
"abilities": [{
|
||||
"class": "Shaman",
|
||||
"base_abil": "Totem",
|
||||
"properties": {
|
||||
"rate": -0.2,
|
||||
"totem_mul": 2.5
|
||||
},
|
||||
"effects": []
|
||||
}]
|
||||
},
|
||||
"FLASHFREEZE": {
|
||||
"displayName": "Flashfreeze",
|
||||
"description": "Ice Snake is instant but has a reduced range",
|
||||
"abilities": []
|
||||
},
|
||||
"GRAVITYWELL": {
|
||||
"displayName": "Gravity Well",
|
||||
"description": "Meteor has increased blast radius and pulls enemies instead",
|
||||
"abilities": []
|
||||
},
|
||||
"DESC_SNOWYSTEPS": {
|
||||
"displayName": "Snowy Steps",
|
||||
"description": "Leaves a trail of snow behind you",
|
||||
"abilities": []
|
||||
},
|
||||
"GEOCENTRISM": {
|
||||
"displayName": "Geocentrism",
|
||||
"description": "Aura radiates from you instead of your totem and can be cast anytime",
|
||||
"abilities": []
|
||||
},
|
||||
"DESC_FESTIVESPIRIT": {
|
||||
"displayName": "Festive Spirit",
|
||||
"description": "Plays wintery tunes",
|
||||
"abilities": []
|
||||
},
|
||||
"TEMBLOR": {
|
||||
"displayName": "Temblor",
|
||||
"description": "Bash gains +1 Area of Effect and is 25% faster.",
|
||||
"abilities": [{
|
||||
"class": "Warrior",
|
||||
"base_abil": "Bash",
|
||||
"properties": { "aoe": 1 },
|
||||
"effects": []
|
||||
}]
|
||||
},
|
||||
"RECKLESS_ABANDON": {
|
||||
"displayName": "Reckless Abandon",
|
||||
"description": "Sacrifice War Scream's defense bonus to give Tempest two extra hits, extra damage, and extra speed",
|
||||
"abilities": [{
|
||||
"class": "Warrior",
|
||||
"base_abil": "War Scream",
|
||||
"dependencies": [ "Tempest" ],
|
||||
"effects": [
|
||||
{
|
||||
"type": "add_spell_prop",
|
||||
"base_spell": 4,
|
||||
"target_part": "Tempest",
|
||||
"behavior": "modify",
|
||||
"multipliers": [0, 5, 0, 0, 15, 5]
|
||||
},
|
||||
{
|
||||
"type": "add_spell_prop",
|
||||
"base_spell": 4,
|
||||
"target_part": "Tempest Total Damage",
|
||||
"behavior": "modify",
|
||||
"hits": { "Tempest": 2 }
|
||||
}
|
||||
]
|
||||
}]
|
||||
},
|
||||
"ALTEREGO": {
|
||||
"displayName": "Alter Ego",
|
||||
"description": "Awakened can be activated after saving 40% less mana, but its duration is reduced by 25%.",
|
||||
"abilities": []
|
||||
},
|
||||
"FOREST_BLESSING": {
|
||||
"displayName": "Forest's Blessing",
|
||||
"description": "Your archer summons have increased movement speed, attack speed and vision. Arrow Bomb's damage is reduced by -30% Neutral damage.",
|
||||
"abilities": [{
|
||||
"class": "Archer",
|
||||
"base_abil": "Arrow Bomb",
|
||||
"effects": [
|
||||
{
|
||||
"type": "add_spell_prop",
|
||||
"base_spell": 3,
|
||||
"target_part": "Arrow Bomb",
|
||||
"behavior": "modify",
|
||||
"multipliers": [-30, 0, 0, 0, 0, 0]
|
||||
},
|
||||
{
|
||||
"type": "add_spell_prop",
|
||||
"base_spell": 8,
|
||||
"target_part": "DPS",
|
||||
"behavior": "modify",
|
||||
"hits": { "Single Hit": 1.666666666666667 }
|
||||
},
|
||||
{
|
||||
"type": "add_spell_prop",
|
||||
"base_spell": 10,
|
||||
"target_part": "Crow DPS",
|
||||
"behavior": "modify",
|
||||
"hits": { "Single Hit": 0.555555555555556 }
|
||||
}
|
||||
]
|
||||
}]
|
||||
},
|
||||
"SOUL_EATER": {
|
||||
"displayName": "Soul Eater",
|
||||
"description": "Devour and Harvester grant double mana, but your maximum Marks are decreased by 1.",
|
||||
"abilities": [{
|
||||
"class": "Assassin",
|
||||
"base_abil": "Marked",
|
||||
"effects": [{
|
||||
"type": "stat_scaling",
|
||||
"slider": true,
|
||||
"slider_name": "Marked",
|
||||
"slider_max": -1
|
||||
}]
|
||||
}]
|
||||
},
|
||||
"STRINGS_OF_FATE": {
|
||||
"displayName": "Strings of Fate",
|
||||
"description": "Your puppets have a lifetime of 3 seconds, but do double damage with attacks and explosions.",
|
||||
"abilities": [{
|
||||
"class": "Shaman",
|
||||
"base_abil": "Puppet Master",
|
||||
"effects": [
|
||||
{
|
||||
"type": "raw_stat",
|
||||
"bonuses": [
|
||||
{
|
||||
"type": "stat",
|
||||
"name": "damMult.FateString:6.Puppet Hit",
|
||||
"value": 100
|
||||
},
|
||||
{
|
||||
"type": "stat",
|
||||
"name": "damMult.FateString:6.Puppet Explosion",
|
||||
"value": 100
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}]
|
||||
},
|
||||
"ESCAPE_ROUTE": {
|
||||
"displayName": "Escape Route",
|
||||
"description": "Frenzy and Time Dilation charge twice as fast, but to a halved maximum.",
|
||||
"abilities": [
|
||||
{
|
||||
"class": "Archer",
|
||||
"base_abil": "Frenzy",
|
||||
"effects": [
|
||||
{
|
||||
"type": "stat_scaling",
|
||||
"slider": true,
|
||||
"slider_name": "Hits dealt",
|
||||
"slider_max": -18,
|
||||
"output": {
|
||||
"type": "stat",
|
||||
"name": "spd"
|
||||
},
|
||||
"scaling": [-3]
|
||||
},
|
||||
{
|
||||
"type": "stat_scaling",
|
||||
"slider": true,
|
||||
"slider_name": "Hits dealt",
|
||||
"output": {
|
||||
"type": "stat",
|
||||
"name": "spd"
|
||||
},
|
||||
"scaling": [6],
|
||||
"max": 35
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"class": "Mage",
|
||||
"base_abil": "Time Dilation",
|
||||
"effects": [
|
||||
{
|
||||
"type": "stat_scaling",
|
||||
"slider": true,
|
||||
"slider_name": "Time Dilated",
|
||||
"slider_max": -22,
|
||||
"output": {
|
||||
"type": "stat",
|
||||
"name": "spd"
|
||||
},
|
||||
"scaling": [-10]
|
||||
},
|
||||
{
|
||||
"type": "stat_scaling",
|
||||
"slider": true,
|
||||
"slider_name": "Time Dilated",
|
||||
"output": {
|
||||
"type": "stat",
|
||||
"name": "spd"
|
||||
},
|
||||
"scaling": [20],
|
||||
"max": 150
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
},
|
||||
"DIVINE_HONOR": {
|
||||
"displayName": "Divine Honor",
|
||||
"description": "Increase the bonus from Radiance by 5%. Decrease the Earth damage of Bash by -15%.",
|
||||
"abilities": [{
|
||||
"class": "Warrior",
|
||||
"base_abil": "Bash",
|
||||
"effects": [
|
||||
{
|
||||
"type": "add_spell_prop",
|
||||
"base_spell": 1,
|
||||
"target_part": "Single Hit",
|
||||
"behavior": "modify",
|
||||
"multipliers": [0, -15, 0, 0, 0, 0]
|
||||
}
|
||||
]
|
||||
}]
|
||||
},
|
||||
"GENTLE_GLOW": {
|
||||
"displayName": "Gentle Glow",
|
||||
"description": "Orphion's Pulse and Fluid Healing restore more health, especially to allies, but at a slower speed.",
|
||||
"abilities": []
|
||||
},
|
||||
"PERFECT_RECALL": {
|
||||
"displayName": "Perfect Recall",
|
||||
"description": "Memory Recollection casts an extra spell, but only activates at 150 banked mana.",
|
||||
"abilities": []
|
||||
},
|
||||
"OVERWHELM": {
|
||||
"displayName": "Overwhelm",
|
||||
"description": "Bash will hit +2 times.",
|
||||
"abilities": [{
|
||||
"class": "Warrior",
|
||||
"base_abil": "Bash",
|
||||
"properties": { "hits": 2 },
|
||||
"effects": []
|
||||
}]
|
||||
},
|
||||
"JUGGLE": {
|
||||
"displayName": "Juggle",
|
||||
"description": "Stronger Multihit adds an additional 12 hits. All hits are reduced by -10% Neutral damage.",
|
||||
"abilities": [{
|
||||
"class": "Assassin",
|
||||
"base_abil": "Multihit",
|
||||
"effects": [
|
||||
{
|
||||
"type": "add_spell_prop",
|
||||
"base_spell": 3,
|
||||
"target_part": "Total Damage",
|
||||
"behavior": "modify",
|
||||
"hits": { "Per Hit": 12 }
|
||||
},
|
||||
{
|
||||
"type": "add_spell_prop",
|
||||
"base_spell": 3,
|
||||
"target_part": "Per Hit",
|
||||
"behavior": "modify",
|
||||
"multipliers": [ -10, 0, 0, 0, 0, 0 ]
|
||||
}
|
||||
]
|
||||
}]
|
||||
},
|
||||
"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": []
|
||||
},
|
||||
"HELLFIRE": {
|
||||
"displayName": "Hellfire",
|
||||
"description":"Boiling Blood has no cooldown, is stronger, and does not slow. Cuts Bash's power and disables Discombobulate",
|
||||
"abilities": [{
|
||||
"class": "Warrior",
|
||||
"base_abil": "Bash",
|
||||
"dependencies": [ "Boiling Blood" ],
|
||||
"properties": {
|
||||
"rate": 0.8333333333333333333333333333,
|
||||
"num_bloods": 0
|
||||
},
|
||||
"effects": [
|
||||
{
|
||||
"type": "add_spell_prop",
|
||||
"base_spell": 1,
|
||||
"target_part": "Single Hit",
|
||||
"behavior": "modify",
|
||||
"multipliers": [ -85, -30, 0, 0, 0, 0 ]
|
||||
},
|
||||
{
|
||||
"type": "add_spell_prop",
|
||||
"base_spell": 1,
|
||||
"target_part": "Boiling Blood Tick",
|
||||
"behavior": "modify",
|
||||
"multipliers": [ -25, 0, 0, 0, 30, 0 ]
|
||||
},
|
||||
{
|
||||
"type": "add_spell_prop",
|
||||
"base_spell": 1,
|
||||
"target_part": "Boiling Blood DPS (Total)",
|
||||
"behavior": "merge",
|
||||
"display": "Boiling Blood DPS (Total)",
|
||||
"hits": { "Boiling Blood DPS": "Bash.num_bloods" }
|
||||
},
|
||||
{
|
||||
"type": "stat_scaling",
|
||||
"slider": true,
|
||||
"slider_name": "Boiling Blood Stacks",
|
||||
"slider_step": 1,
|
||||
"slider_max": 20,
|
||||
"slider_default": 4,
|
||||
"output": [
|
||||
{
|
||||
"type": "prop",
|
||||
"abil": "Bash",
|
||||
"name": "num_bloods"
|
||||
}
|
||||
],
|
||||
"scaling": [1]
|
||||
},
|
||||
{
|
||||
"type": "stat_scaling",
|
||||
"slider": true,
|
||||
"behavior": "modify",
|
||||
"slider_name": "Hits dealt",
|
||||
"output": [
|
||||
{ "type": "stat", "name": "nDamAddMin" }, { "type": "stat", "name": "nDamAddMax" },
|
||||
{ "type": "stat", "name": "eDamAddMin" }, { "type": "stat", "name": "eDamAddMax" },
|
||||
{ "type": "stat", "name": "tDamAddMin" }, { "type": "stat", "name": "tDamAddMax" },
|
||||
{ "type": "stat", "name": "wDamAddMin" }, { "type": "stat", "name": "wDamAddMax" },
|
||||
{ "type": "stat", "name": "fDamAddMin" }, { "type": "stat", "name": "fDamAddMax" },
|
||||
{ "type": "stat", "name": "aDamAddMin" }, { "type": "stat", "name": "aDamAddMax" }
|
||||
],
|
||||
"scaling": [-5]
|
||||
}
|
||||
]
|
||||
}]
|
||||
}
|
||||
}
|
|
@ -155,6 +155,7 @@ class ValueCheckComputeNode extends ComputeNode {
|
|||
if (this.dirty === 0) {
|
||||
return this;
|
||||
}
|
||||
if (COMPUTE_GRAPH_DEBUG) { node_debug_stack.push(this.name); }
|
||||
|
||||
let calc_inputs = new Map();
|
||||
for (const input of this.inputs) {
|
||||
|
@ -170,6 +171,7 @@ class ValueCheckComputeNode extends ComputeNode {
|
|||
for (const child of this.children) {
|
||||
child.mark_input_clean(this.name, this.value);
|
||||
}
|
||||
if (COMPUTE_GRAPH_DEBUG) { node_debug_stack.pop(this.name); }
|
||||
return this;
|
||||
}
|
||||
|
||||
|
@ -188,7 +190,6 @@ let graph_live_update = false;
|
|||
* @param node : ComputeNode to schedule an update for.
|
||||
*/
|
||||
function calcSchedule(node, timeout) {
|
||||
if (!graph_live_update) return;
|
||||
if (node.update_task !== null) {
|
||||
clearTimeout(node.update_task);
|
||||
}
|
||||
|
@ -225,8 +226,8 @@ class InputNode extends ValueCheckComputeNode {
|
|||
constructor(name, input_field) {
|
||||
super(name);
|
||||
this.input_field = input_field;
|
||||
this.input_field.addEventListener("input", () => calcSchedule(this, 500));
|
||||
this.input_field.addEventListener("change", () => calcSchedule(this, 5));
|
||||
this.input_field.addEventListener("input", () => { if (graph_live_update) calcSchedule(this, 500) } );
|
||||
this.input_field.addEventListener("change", () => { if (graph_live_update) calcSchedule(this, 5) } );
|
||||
//calcSchedule(this); Manually fire first update for better control
|
||||
}
|
||||
|
||||
|
|
|
@ -1,6 +1,5 @@
|
|||
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",]
|
||||
let ingFields = ["fDefPct", "wDefPct", "aDefPct", "tDefPct", "eDefPct", "hprPct", "mr", "sdPct", "mdPct", "ls", "ms", "xpb", "lb", "lq", "ref", "str", "dex", "int", "agi", "def", "thorns", "expd", "spd", "atkTier", "poison", "hpBonus", "spRegen", "eSteal", "hprRaw", "sdRaw", "mdRaw", "fDamPct", "wDamPct", "aDamPct", "tDamPct", "eDamPct", "spPct1", "spRaw1", "spPct2", "spRaw2", "spPct3", "spRaw3", "spPct4", "spRaw4", "jh", "sprint", "sprintReg", "gXp", "gSpd"];
|
||||
|
||||
function encodeCraft(craft) {
|
||||
if (craft) {
|
||||
|
@ -181,7 +180,6 @@ class Craft{
|
|||
/* Change certain IDs based on material tier.
|
||||
healthOrDamage changes.
|
||||
duration and durability change. (but not basicDuration)
|
||||
|
||||
*/
|
||||
let matmult = 1;
|
||||
let tierToMult = [0,1,1.25,1.4];
|
||||
|
|
|
@ -136,8 +136,6 @@ function calculateCraft() {
|
|||
}
|
||||
let ingreds = [];
|
||||
for (i = 1; i < 7; i++) {
|
||||
console.log("ing-choice-"+i);
|
||||
// console.log(getValue("ing-choice-"+i));
|
||||
getValue("ing-choice-" + i) === "" ? ingreds.push(expandIngredient(ingMap.get("No Ingredient"))) : ingreds.push(expandIngredient(ingMap.get(getValue("ing-choice-" + i))));
|
||||
}
|
||||
let atkSpd = "NORMAL"; //default attack speed will be normal.
|
||||
|
|
|
@ -76,7 +76,7 @@ function encodeCustom(custom, verbose) {
|
|||
hash += Base64.fromIntN(i, 2) + Base64.fromIntN(val.replaceAll(" ", "%20").length, 2) + val.replaceAll(" ", "%20"); //values cannot go above 4096 chars!!!! Is this ok?
|
||||
}
|
||||
} else if (typeof (val) === "number" && val != 0) {
|
||||
let len = Math.max(1, Math.ceil(log(64, Math.abs(val))));
|
||||
let len = Math.max(1, Math.ceil(log(64, Math.abs(val) + 1)));
|
||||
let sign = Boolean(val / Math.abs(val) < 0) | 0;
|
||||
//console.log(sign);
|
||||
//hash += Base64.fromIntN(i,2) + Base64.fromIntN(val,Math.max(1,Math.ceil(log(64,Math.abs(val))))) + "_";
|
||||
|
@ -246,7 +246,6 @@ class Custom {
|
|||
}
|
||||
}
|
||||
let type = this.statMap.get("type").toLowerCase();
|
||||
console.log(type);
|
||||
if (weaponTypes.includes(type)) {
|
||||
for (const n of ["nDam", "eDam", "tDam", "wDam", "fDam", "aDam"]) {
|
||||
if (!(this.statMap.has(n) && this.statMap.get(n))) {
|
||||
|
|
|
@ -478,30 +478,18 @@ function base_to_range(id) {
|
|||
let base = parseFloat(getValue(id+"-choice-base"));
|
||||
if(base) {
|
||||
//This version allows overriding of min and max.
|
||||
if (reversedIDs.includes(id)) {
|
||||
if (base < 0) {
|
||||
setValue(id+"-choice-min", Math.min(Math.round(neg_range[1]*base),-1));
|
||||
} else {
|
||||
setValue(id+"-choice-min", Math.max(Math.round(pos_range[1]*base),1));
|
||||
}
|
||||
if (base < 0) {
|
||||
setValue(id+"-choice-max", Math.min(Math.round(neg_range[0]*base),-1));
|
||||
} else {
|
||||
setValue(id+"-choice-max", Math.max(Math.round(pos_range[0]*base),1));
|
||||
}
|
||||
} else {
|
||||
if (base < 0) {
|
||||
setValue(id+"-choice-min", Math.min(Math.round(neg_range[0]*base),-1));
|
||||
} else {
|
||||
setValue(id+"-choice-min", Math.max(Math.round(pos_range[0]*base),1));
|
||||
}
|
||||
if (base < 0) {
|
||||
setValue(id+"-choice-max", Math.min(Math.round(neg_range[1]*base),-1));
|
||||
} else {
|
||||
setValue(id+"-choice-max", Math.max(Math.round(pos_range[1]*base),1));
|
||||
}
|
||||
if (base == 0) {
|
||||
// NOTE: DO NOT remove this case! idRound behavior does not round to 0!
|
||||
setValue(id+"-choice-max", 0);
|
||||
setValue(id+"-choice-min", 0);
|
||||
}
|
||||
else if ((base > 0) != (reversedIDs.includes(id))) { // logical XOR. positive rolled IDs
|
||||
setValue(id+"-choice-max", idRound(Math.round(pos_range[1]*base)));
|
||||
setValue(id+"-choice-min", idRound(Math.round(pos_range[0]*base)));
|
||||
} else { //negative rolled IDs
|
||||
setValue(id+"-choice-max", idRound(Math.round(neg_range[1]*base)));
|
||||
setValue(id+"-choice-min", idRound(Math.round(neg_range[0]*base)));
|
||||
}
|
||||
|
||||
|
||||
/* No overiding min/max version
|
||||
if (!getValue(id+"-choice-min")) {
|
||||
|
|
|
@ -67,6 +67,9 @@ function calculateSpellDamage(stats, weapon, _conversions, use_spell_damage, ign
|
|||
// 2.1. First, apply neutral conversion (scale weapon damage). Keep track of total weapon damage here.
|
||||
let damages = [];
|
||||
const neutral_convert = conversions[0] / 100;
|
||||
if (neutral_convert == 0) {
|
||||
present = [false, false, false, false, false, false]
|
||||
}
|
||||
let weapon_min = 0;
|
||||
let weapon_max = 0;
|
||||
for (const damage of weapon_damages) {
|
||||
|
@ -134,15 +137,15 @@ function calculateSpellDamage(stats, weapon, _conversions, use_spell_damage, ign
|
|||
let damageBoost = 1 + skill_boost[i] + static_boost
|
||||
+ ((stats.get(damage_specific) + stats.get(damage_elements[i]+'DamPct')) /100);
|
||||
if (i > 0) {
|
||||
damageBoost += stats.get('r'+specific_boost_str+'Pct') / 100;
|
||||
damageBoost += (stats.get('r'+specific_boost_str+'Pct') + stats.get('rDamPct')) / 100;
|
||||
}
|
||||
damages[i][0] *= Math.max(damageBoost, 0);
|
||||
damages[i][1] *= Math.max(damageBoost, 0);
|
||||
// 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');
|
||||
|
@ -337,17 +340,3 @@ const default_spells = {
|
|||
]
|
||||
}]
|
||||
};
|
||||
|
||||
const spell_table = {
|
||||
"powder": [ //This is how instant-damage powder specials are implemented.
|
||||
{ title: "Quake", cost: 0, parts:[
|
||||
{ subtitle: "Total Damage", type: "damage", multiplier: [155, 220, 285, 350, 415], conversion: [0,100,0,0,0,0], summary: true},
|
||||
] },
|
||||
{ title: "Chain Lightning", cost: 0, parts: [
|
||||
{ subtitle: "Total Damage", type: "damage", multiplier: [200, 225, 250, 275, 300], conversion: [0,0,100,0,0,0], summary: true},
|
||||
]},
|
||||
{ title: "Courage", cost: 0, parts: [
|
||||
{ subtitle: "Total Damage", type: "damage", multiplier: [75, 87.5, 100, 112.5, 125], conversion: [0,0,0,0,100,0], summary: true},
|
||||
]}, //[75, 87.5, 100, 112.5, 125]
|
||||
]
|
||||
};
|
||||
|
|
193
js/display.js
193
js/display.js
|
@ -214,14 +214,18 @@ function displayExpandedItem(item, parent_id){
|
|||
parent_div.appendChild(make_elem("div", ["col"], { textContent: "Set: " + item.get(id).toString() }));
|
||||
} else if (id === "majorIds") {
|
||||
//console.log(item.get(id));
|
||||
for (let majorID of item.get(id)) {
|
||||
for (let major_id_str of item.get(id)) {
|
||||
if (major_id_str in major_ids) {
|
||||
let major_id_info = major_ids[major_id_str];
|
||||
major_id_str = `+${major_id_info.displayName}: ${major_id_info.description}`;
|
||||
}
|
||||
let p_elem = make_elem("div", ['col']);
|
||||
|
||||
let title_elem = make_elem("b");
|
||||
let b_elem = make_elem("b");
|
||||
if (majorID.includes(":")) {
|
||||
let name = majorID.substring(0, majorID.indexOf(":")+1);
|
||||
let mid = majorID.substring(majorID.indexOf(":")+1);
|
||||
if (major_id_str.includes(":")) {
|
||||
let name = major_id_str.substring(0, major_id_str.indexOf(":")+1);
|
||||
let mid = major_id_str.substring(major_id_str.indexOf(":")+1);
|
||||
if (name.charAt(0) !== "+") {name = "+" + name}
|
||||
title_elem.classList.add("Legendary");
|
||||
title_elem.textContent = name;
|
||||
|
@ -230,10 +234,9 @@ function displayExpandedItem(item, parent_id){
|
|||
p_elem.appendChild(title_elem);
|
||||
p_elem.appendChild(b_elem);
|
||||
} else {
|
||||
let name = item.get(id).toString()
|
||||
if (name.charAt(0) !== "+") {name = "+" + name}
|
||||
if (major_id_str.charAt(0) !== "+") {major_id_str = "+" + major_id_str}
|
||||
b_elem.classList.add("Legendary");
|
||||
b_elem.textContent = name;
|
||||
b_elem.textContent = major_id_str;
|
||||
p_elem.appendChild(b_elem);
|
||||
}
|
||||
parent_div.appendChild(p_elem);
|
||||
|
@ -306,11 +309,11 @@ function displayExpandedItem(item, parent_id){
|
|||
// TODO: kinda jank but replacing lists with txt at this step
|
||||
let damages = item.get(id);
|
||||
if (item.get("tier") !== "Crafted") {
|
||||
damages = damages.map(x => Math.round(x));
|
||||
damages = damages.map(x => Math.floor(x));
|
||||
item.set(id, damages[0]+"-"+damages[1]);
|
||||
}
|
||||
else {
|
||||
damages = damages.map(x => x.map(y => Math.round(y)));
|
||||
damages = damages.map(x => x.map(y => Math.floor(y)));
|
||||
item.set(id, damages[0][0]+"-"+damages[0][1]+"\u279c"+damages[1][0]+"-"+damages[1][1]);
|
||||
}
|
||||
}
|
||||
|
@ -463,7 +466,6 @@ function displayExpandedItem(item, parent_id){
|
|||
if (item.get("tier") && item.get("tier") !== " ") {
|
||||
let item_desc_elem = make_elem("div", ["col", item.get("tier")]);
|
||||
if (tome_types.includes(item.get("type"))) {
|
||||
tome_type_map = new Map([["weaponTome", "Weapon Tome"],["armorTome", "Armor Tome"],["guildTome", "Guild Tome"]]);
|
||||
item_desc_elem.textContent = item.get("tier")+" "+tome_type_map.get(item.get("type"));
|
||||
} else {
|
||||
item_desc_elem.textContent = item.get("tier")+" "+item.get("type");
|
||||
|
@ -493,7 +495,7 @@ function displayExpandedItem(item, parent_id){
|
|||
base_dps_elem.textContent = "Base DPS: "+base_dps_min.toFixed(3)+"\u279c"+base_dps_max.toFixed(3);
|
||||
}
|
||||
else {
|
||||
base_dps_elem.textContent = "Base DPS: "+(total_damages);
|
||||
base_dps_elem.textContent = "Base DPS: "+(total_damages.toFixed(3));
|
||||
}
|
||||
parent_div.append(make_elem("p"), base_dps_elem);
|
||||
}
|
||||
|
@ -1178,14 +1180,6 @@ function displayDefenseStats(parent_elem, statMap, insertSummary){
|
|||
boost.classList.add(eledefs[i] >= 0 ? "positive" : "negative");
|
||||
boost.classList.add("col");
|
||||
boost.classList.add("text-end");
|
||||
|
||||
let defRaw = statMap.get(skp_elements[i]+"Def");
|
||||
let defPct = statMap.get(skp_elements[i]+"DefPct")/100;
|
||||
if (defRaw < 0) {
|
||||
defPct >= 0 ? defPct = "- " + defPct: defPct = "+ " + defPct;
|
||||
} else {
|
||||
defPct >= 0 ? defPct = "+ " + defPct: defPct = "- " + defPct;
|
||||
}
|
||||
eledefElemRow.appendChild(boost);
|
||||
|
||||
if (insertSummary) {
|
||||
|
@ -1231,7 +1225,7 @@ function displayDefenseStats(parent_elem, statMap, insertSummary){
|
|||
}
|
||||
}
|
||||
|
||||
function displayPowderSpecials(parent_elem, powderSpecials, stats, weapon, overall=false) {
|
||||
function displayPowderSpecials(parent_elem, powderSpecials, stats, weapon) {
|
||||
parent_elem.textContent = "";
|
||||
if (powderSpecials.length === 0) {
|
||||
parent_elem.style = "display: none";
|
||||
|
@ -1252,129 +1246,66 @@ function displayPowderSpecials(parent_elem, powderSpecials, stats, weapon, overa
|
|||
//each entry of powderSpecials is [ps, power]
|
||||
for (special of specials) {
|
||||
//iterate through the special and display its effects.
|
||||
let powder_special = make_elem("p", ["pt-3"]);
|
||||
let powder_special_elem = make_elem("p", ["pt-3"]);
|
||||
let specialSuffixes = new Map([ ["Duration", " sec"], ["Radius", " blocks"], ["Chains", ""], ["Damage", "%"], ["Damage Boost", "%"], ["Knockback", " blocks"] ]);
|
||||
let specialTitle = make_elem("p");
|
||||
let specialEffects = make_elem("p");
|
||||
specialTitle.classList.add(damageClasses[powderSpecialStats.indexOf(special[0]) + 1]);
|
||||
let effects = special[0]["weaponSpecialEffects"];
|
||||
// TODO janky and depends on the order of powder specials being ETWFA. This should be encoded in the powder special object.
|
||||
let element_num = powderSpecialStats.indexOf(special[0]) + 1;
|
||||
specialTitle.classList.add(damageClasses[element_num]);
|
||||
let powder_special = special[0];
|
||||
let power = special[1];
|
||||
specialTitle.textContent = special[0]["weaponSpecialName"] + " " + Math.floor((power-1)*0.5 + 4) + (power % 2 == 0 ? ".5" : "");
|
||||
specialTitle.textContent = powder_special.weaponSpecialName + " " + Math.floor((power-1)*0.5 + 4) + (power % 2 == 0 ? ".5" : "");
|
||||
|
||||
if (!overall || powderSpecialStats.indexOf(special[0]) == 2 || powderSpecialStats.indexOf(special[0]) == 3 || powderSpecialStats.indexOf(special[0]) == 4) {
|
||||
for (const [key,value] of effects) {
|
||||
for (const [key,value] of powder_special.weaponSpecialEffects) {
|
||||
if(key === "Damage"){
|
||||
//if this special is an instant-damage special (Quake, Chain Lightning, Courage Burst), display the damage.
|
||||
let specialDamage = document.createElement("p");
|
||||
// specialDamage.classList.add("item-margin");
|
||||
let conversions = [0, 0, 0, 0, 0, 0];
|
||||
conversions[element_num] = powder_special.weaponSpecialEffects.get("Damage")[power-1];
|
||||
let _results = calculateSpellDamage(stats, weapon, conversions, false, true, "0.Powder Special");
|
||||
|
||||
let critChance = skillPointsToPercentage(skillpoints[1]);
|
||||
let save_damages = [];
|
||||
|
||||
let totalDamNormal = _results[0];
|
||||
let totalDamCrit = _results[1];
|
||||
let results = _results[2];
|
||||
for (let i = 0; i < 6; ++i) {
|
||||
for (let j in results[i]) {
|
||||
results[i][j] = results[i][j].toFixed(2);
|
||||
}
|
||||
}
|
||||
let nonCritAverage = (totalDamNormal[0]+totalDamNormal[1])/2 || 0;
|
||||
let critAverage = (totalDamCrit[0]+totalDamCrit[1])/2 || 0;
|
||||
let averageDamage = (1-critChance)*nonCritAverage+critChance*critAverage || 0;
|
||||
|
||||
let averageWrap = document.createElement("p");
|
||||
let averageLabel = document.createElement("span");
|
||||
averageLabel.textContent = "Average: ";
|
||||
|
||||
let averageLabelDmg = document.createElement("span");
|
||||
averageLabelDmg.classList.add("Damage");
|
||||
averageLabelDmg.textContent = averageDamage.toFixed(2);
|
||||
|
||||
averageWrap.appendChild(averageLabel);
|
||||
averageWrap.appendChild(averageLabelDmg);
|
||||
specialDamage.appendChild(averageWrap);
|
||||
|
||||
specialEffects.append(specialDamage);
|
||||
}
|
||||
else {
|
||||
let effect = document.createElement("p");
|
||||
effect.textContent += key + ": " + value[power-1] + specialSuffixes.get(key);
|
||||
if(key === "Damage"){
|
||||
effect.textContent += elementIcons[powderSpecialStats.indexOf(special[0])];
|
||||
}
|
||||
if(special[0]["weaponSpecialName"] === "Wind Prison" && key === "Damage Boost") {
|
||||
effect.textContent += " (only 1st hit)";
|
||||
}
|
||||
specialEffects.appendChild(effect);
|
||||
}
|
||||
}
|
||||
powder_special.appendChild(specialTitle);
|
||||
powder_special.appendChild(specialEffects);
|
||||
|
||||
//if this special is an instant-damage special (Quake, Chain Lightning, Courage Burst), display the damage.
|
||||
let specialDamage = document.createElement("p");
|
||||
// specialDamage.classList.add("item-margin");
|
||||
let spells = spell_table["powder"];
|
||||
if (powderSpecialStats.indexOf(special[0]) == 0 || powderSpecialStats.indexOf(special[0]) == 1 || powderSpecialStats.indexOf(special[0]) == 3) { //Quake, Chain Lightning, or Courage
|
||||
let spell = (powderSpecialStats.indexOf(special[0]) == 3 ? spells[2] : spells[powderSpecialStats.indexOf(special[0])]);
|
||||
let part = spell["parts"][0];
|
||||
powder_special_elem.appendChild(specialTitle);
|
||||
powder_special_elem.appendChild(specialEffects);
|
||||
|
||||
let tmp_conv = [];
|
||||
for (let i in part.conversion) {
|
||||
tmp_conv.push(part.conversion[i] * part.multiplier[power-1] / 100);
|
||||
}
|
||||
console.log(tmp_conv);
|
||||
let _results = calculateSpellDamage(stats, weapon, tmp_conv, false, true);
|
||||
|
||||
let critChance = skillPointsToPercentage(skillpoints[1]);
|
||||
let save_damages = [];
|
||||
|
||||
let totalDamNormal = _results[0];
|
||||
let totalDamCrit = _results[1];
|
||||
let results = _results[2];
|
||||
for (let i = 0; i < 6; ++i) {
|
||||
for (let j in results[i]) {
|
||||
results[i][j] = results[i][j].toFixed(2);
|
||||
}
|
||||
}
|
||||
let nonCritAverage = (totalDamNormal[0]+totalDamNormal[1])/2 || 0;
|
||||
let critAverage = (totalDamCrit[0]+totalDamCrit[1])/2 || 0;
|
||||
let averageDamage = (1-critChance)*nonCritAverage+critChance*critAverage || 0;
|
||||
|
||||
let averageWrap = document.createElement("p");
|
||||
let averageLabel = document.createElement("span");
|
||||
averageLabel.textContent = "Average: ";
|
||||
|
||||
let averageLabelDmg = document.createElement("span");
|
||||
averageLabelDmg.classList.add("Damage");
|
||||
averageLabelDmg.textContent = averageDamage.toFixed(2);
|
||||
|
||||
averageWrap.appendChild(averageLabel);
|
||||
averageWrap.appendChild(averageLabelDmg);
|
||||
specialDamage.appendChild(averageWrap);
|
||||
|
||||
if (!overall) {
|
||||
let nonCritLabel = document.createElement("p");
|
||||
nonCritLabel.textContent = "Non-Crit Average: "+nonCritAverage.toFixed(2);
|
||||
nonCritLabel.classList.add("damageSubtitle");
|
||||
nonCritLabel.classList.add("item-margin");
|
||||
specialDamage.append(nonCritLabel);
|
||||
|
||||
for (let i = 0; i < 6; i++){
|
||||
if (results[i][1] > 0){
|
||||
let p = document.createElement("p");
|
||||
p.classList.add("damagep");
|
||||
p.classList.add(damageClasses[i]);
|
||||
p.textContent = results[i][0]+"-"+results[i][1];
|
||||
specialDamage.append(p);
|
||||
}
|
||||
}
|
||||
let normalDamage = document.createElement("p");
|
||||
normalDamage.textContent = "Total: " + totalDamNormal[0].toFixed(2) + "-" + totalDamNormal[1].toFixed(2);
|
||||
normalDamage.classList.add("itemp");
|
||||
specialDamage.append(normalDamage);
|
||||
|
||||
let nonCritChanceLabel = document.createElement("p");
|
||||
nonCritChanceLabel.textContent = "Non-Crit Chance: " + ((1-critChance)*100).toFixed(2) + "%";
|
||||
specialDamage.append(nonCritChanceLabel);
|
||||
|
||||
let critLabel = document.createElement("p");
|
||||
critLabel.textContent = "Crit Average: "+critAverage.toFixed(2);
|
||||
critLabel.classList.add("damageSubtitle");
|
||||
critLabel.classList.add("item-margin");
|
||||
|
||||
specialDamage.append(critLabel);
|
||||
for (let i = 0; i < 6; i++){
|
||||
if (results[i][1] > 0){
|
||||
let p = document.createElement("p");
|
||||
p.classList.add("damagep");
|
||||
p.classList.add(damageClasses[i]);
|
||||
p.textContent = results[i][2]+"-"+results[i][3];
|
||||
specialDamage.append(p);
|
||||
}
|
||||
}
|
||||
let critDamage = document.createElement("p");
|
||||
critDamage.textContent = "Total: " + totalDamCrit[0].toFixed(2) + "-" + totalDamCrit[1].toFixed(2);
|
||||
critDamage.classList.add("itemp");
|
||||
specialDamage.append(critDamage);
|
||||
|
||||
let critChanceLabel = document.createElement("p");
|
||||
critChanceLabel.textContent = "Crit Chance: " + (critChance*100).toFixed(2) + "%";
|
||||
specialDamage.append(critChanceLabel);
|
||||
|
||||
save_damages.push(averageDamage);
|
||||
}
|
||||
|
||||
powder_special.append(specialDamage);
|
||||
}
|
||||
|
||||
parent_elem.appendChild(powder_special);
|
||||
parent_elem.appendChild(powder_special_elem);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -35,42 +35,60 @@ let idPrefixes = {"displayName": "",
|
|||
"str":"Strength: ",
|
||||
"dex":"Dexterity: ",
|
||||
"int":"Intelligence: ",
|
||||
"def":"Defense: ","agi":"Agility: ",
|
||||
"def":"Defense: ",
|
||||
"agi":"Agility: ",
|
||||
"hpBonus":"Health Bonus: ",
|
||||
"hprRaw":"Health Regen Raw: ",
|
||||
"hprRaw":"Raw Health Regen: ",
|
||||
"hprPct":"Health Regen %: ",
|
||||
"sdRaw":"Raw Spell Damage: ",
|
||||
"healPct":"Healing Effectiveness %",
|
||||
"sdRaw":"Spell Damage Raw: ",
|
||||
"rSdRaw":"Elem. Spell Damage Raw: ",
|
||||
"nSdRaw":"Neut. Spell Damage Raw: ",
|
||||
"eSdRaw":"Raw Earth Spell Damage: ",
|
||||
"tSdRaw":"Raw Thunder Spell Damage: ",
|
||||
"wSdRaw":"Raw Water Spell Damage: ",
|
||||
"fSdRaw":"Raw Fire Spell Damage: ",
|
||||
"aSdRaw":"Raw Air Spell Damage: ",
|
||||
"eSdRaw":"Earth Spell Damage Raw: ",
|
||||
"tSdRaw":"Thunder Spell Damage Raw: ",
|
||||
"wSdRaw":"Water Spell Damage Raw: ",
|
||||
"fSdRaw":"Fire Spell Damage Raw: ",
|
||||
"aSdRaw":"Air Spell Damage Raw: ",
|
||||
"sdPct":"Spell Damage %: ",
|
||||
"rSdPct":"Elem. Spell Damage %: ",
|
||||
"nSdPct":"Neut. Spell Damage %: ",
|
||||
"eSdPct":"% Earth Spell Damage: ",
|
||||
"tSdPct":"% Thunder Spell Damage: ",
|
||||
"wSdPct":"% Water Spell Damage: ",
|
||||
"fSdPct":"% Fire Spell Damage: ",
|
||||
"aSdPct":"% Air Spell Damage: ",
|
||||
"mdRaw":"Raw Melee Damage: ",
|
||||
"eSdPct":"Earth Spell Damage %: ",
|
||||
"tSdPct":"Thunder Spell Damage %: ",
|
||||
"wSdPct":"Water Spell Damage %: ",
|
||||
"fSdPct":"Fire Spell Damage %: ",
|
||||
"aSdPct":"Air Spell Damage %: ",
|
||||
"mdRaw":"Melee Damage Raw: ",
|
||||
"rMdRaw":"Elem. Melee Damage Raw: ",
|
||||
"nMdRaw":"Neut. Melee Damage Raw: ",
|
||||
"eMdRaw":"Raw Earth Melee Damage: ",
|
||||
"tMdRaw":"Raw Thunder Melee Damage: ",
|
||||
"wMdRaw":"Raw Water Melee Damage: ",
|
||||
"fMdRaw":"Raw Fire Melee Damage: ",
|
||||
"aMdRaw":"Raw Air Melee Damage: ",
|
||||
"eMdRaw":"Earth Melee Damage Raw: ",
|
||||
"tMdRaw":"Thunder Melee Damage Raw: ",
|
||||
"wMdRaw":"Water Melee Damage Raw: ",
|
||||
"fMdRaw":"Fire Melee Damage Raw: ",
|
||||
"aMdRaw":"Air Melee Damage Raw: ",
|
||||
"mdPct":"Melee Damage %: ",
|
||||
"rMdPct":"Elem. Melee Damage %: ",
|
||||
"nMdPct":"Neut. Melee Damage %: ",
|
||||
"eMdPct":"% Earth Melee Damage: ",
|
||||
"tMdPct":"% Thunder Melee Damage: ",
|
||||
"wMdPct":"% Water Melee Damage: ",
|
||||
"fMdPct":"% Fire Melee Damage: ",
|
||||
"aMdPct":"% Air Melee Damage: ",
|
||||
"eMdPct":"Earth Melee Damage %: ",
|
||||
"tMdPct":"Thunder Melee Damage %: ",
|
||||
"wMdPct":"Water Melee Damage %: ",
|
||||
"fMdPct":"Fire Melee Damage %: ",
|
||||
"aMdPct":"Air Melee Damage %: ",
|
||||
"damRaw":"Damage Raw: ",
|
||||
"rDamRaw":"Elemental Damage Raw: ",
|
||||
"nDamRaw":"Neutral Damage Raw: ",
|
||||
"eDamRaw":"Earth Damage Raw: ",
|
||||
"tDamRaw":"Thunder Damage Raw: ",
|
||||
"wDamRaw":"Water Damage Raw: ",
|
||||
"fDamRaw":"Fire Damage Raw: ",
|
||||
"aDamRaw":"Air Damage Raw: ",
|
||||
"damPct":"Damage %: ",
|
||||
"rDamPct":"Elemental Damage %: ",
|
||||
"nDamPct":"Neutral Damage %: ",
|
||||
"eDamPct":"Earth Damage %: ",
|
||||
"tDamPct":"Thunder Damage %: ",
|
||||
"wDamPct":"Water Damage %: ",
|
||||
"fDamPct":"Fire Damage %: ",
|
||||
"aDamPct":"Air Damage %: ",
|
||||
"mr":"Mana Regen: ",
|
||||
"ms":"Mana Steal: ",
|
||||
"ref":"Reflection: ",
|
||||
|
@ -80,16 +98,12 @@ let idPrefixes = {"displayName": "",
|
|||
"expd":"Exploding: ",
|
||||
"spd":"Walk Speed Bonus: ",
|
||||
"atkTier":"Attack Speed Bonus: ",
|
||||
"eDamPct":"Earth Damage %: ",
|
||||
"tDamPct":"Thunder Damage %: ",
|
||||
"wDamPct":"Water Damage %: ",
|
||||
"fDamPct":"Fire Damage %: ",
|
||||
"aDamPct":"Air Damage %: ",
|
||||
"eDefPct":"Earth Defense %: ",
|
||||
"tDefPct":"Thunder Defense %: ",
|
||||
"wDefPct":"Water Defense %: ",
|
||||
"fDefPct":"Fire Defense %: ",
|
||||
"aDefPct":"Air Defense %: ",
|
||||
"rDefPct":"Elemental Defense %: ",
|
||||
"spPct1":"1st Spell Cost %: ",
|
||||
"spRaw1":"1st Spell Cost Raw: ",
|
||||
"spPct2":"2nd Spell Cost %: ",
|
||||
|
@ -108,6 +122,9 @@ let idPrefixes = {"displayName": "",
|
|||
"eSteal":"Stealing: ",
|
||||
"gXp":"Gathering XP Bonus: ",
|
||||
"gSpd":"Gathering Speed Bonus: ",
|
||||
"kb":"Knockback: ",
|
||||
"weakenEnemy":"Weaken Enemy: ",
|
||||
"slowEnemy":"Slow Enemy: ",
|
||||
"slots":"Powder Slots: ",
|
||||
"set":"Set: ",
|
||||
"quest":"Quest Req: ",
|
||||
|
@ -143,6 +160,7 @@ let idSuffixes = {"displayName": "",
|
|||
"hpBonus":"",
|
||||
"hprRaw":"",
|
||||
"hprPct":"%",
|
||||
"healPct":"%",
|
||||
"sdRaw":"",
|
||||
"rSdRaw":"",
|
||||
"nSdRaw":"",
|
||||
|
@ -175,6 +193,22 @@ let idSuffixes = {"displayName": "",
|
|||
"wMdPct":"%",
|
||||
"fMdPct":"%",
|
||||
"aMdPct":"%",
|
||||
"damRaw":"",
|
||||
"rDamRaw":"",
|
||||
"nDamRaw":"",
|
||||
"eDamRaw":"",
|
||||
"tDamRaw":"",
|
||||
"wDamRaw":"",
|
||||
"fDamRaw":"",
|
||||
"aDamRaw":"",
|
||||
"damPct":"%",
|
||||
"rDamPct":"%",
|
||||
"nDamPct":"%",
|
||||
"eDamPct":"%",
|
||||
"tDamPct":"%",
|
||||
"wDamPct":"%",
|
||||
"fDamPct":"%",
|
||||
"aDamPct":"%",
|
||||
"mr":"/5s",
|
||||
"ms":"/3s",
|
||||
"ref":"%",
|
||||
|
@ -184,16 +218,12 @@ let idSuffixes = {"displayName": "",
|
|||
"expd":"%",
|
||||
"spd":"%",
|
||||
"atkTier":" tier",
|
||||
"eDamPct":"%",
|
||||
"tDamPct":"%",
|
||||
"wDamPct":"%",
|
||||
"fDamPct":"%",
|
||||
"aDamPct":"%",
|
||||
"eDefPct":"%",
|
||||
"tDefPct":"%",
|
||||
"wDefPct":"%",
|
||||
"fDefPct":"%",
|
||||
"aDefPct":"%",
|
||||
"rDefPct":"%",
|
||||
"spPct1":"%",
|
||||
"spRaw1":"",
|
||||
"spPct2":"%",
|
||||
|
@ -212,11 +242,14 @@ let idSuffixes = {"displayName": "",
|
|||
"eSteal":"%",
|
||||
"gXp":"%",
|
||||
"gSpd":"%",
|
||||
"kb": "%",
|
||||
"weakenEnemy": "%",
|
||||
"slowEnemy": "%",
|
||||
"slots":"",
|
||||
"set":" set.",
|
||||
"quest":"",
|
||||
"restrict":"",
|
||||
"lore": ""
|
||||
"lore": "",
|
||||
};
|
||||
|
||||
//Used for item IDs and ingredient id field IDs
|
||||
|
@ -245,10 +278,10 @@ let itemIDPrefixes = {
|
|||
//Used for ingredient posMods IDs
|
||||
let posModPrefixes = {
|
||||
"left":"Effectiveness Left: ",
|
||||
"right":"EFfectiveness Right: ",
|
||||
"right":"Effectiveness Right: ",
|
||||
"above":"Effectiveness Above: ",
|
||||
"under":"Effectiveness Under: ",
|
||||
"touching":"EFfectiveness Touching: ",
|
||||
"touching":"Effectiveness Touching: ",
|
||||
"notTouching":"Effectiveness Not Touching: "
|
||||
}
|
||||
let posModSuffixes = {
|
||||
|
@ -279,6 +312,7 @@ let build_overall_display_commands = [
|
|||
"spRegen",
|
||||
"eSteal",
|
||||
"gXp", "gSpd",
|
||||
"kb", "weakenEnemy", "slowEnemy",
|
||||
];
|
||||
|
||||
let build_detailed_display_commands = [
|
||||
|
@ -286,19 +320,24 @@ let build_detailed_display_commands = [
|
|||
"str", "dex", "int", "def", "agi",
|
||||
"!spacer",
|
||||
"mr", "ms",
|
||||
"hprRaw", "hprPct",
|
||||
"hprRaw", "hprPct", "healPct",
|
||||
"ls",
|
||||
"sdRaw", "nSdRaw", "rSdRaw",
|
||||
"sdPct", "nSdPct", "rSdPct",
|
||||
"mdRaw", "nMdRaw", "rMdRaw",
|
||||
"mdPct", "nMdPct", "rMdPct",
|
||||
"damRaw", "nDamRaw", "rDamRaw",
|
||||
"damPct", "nDamPct", "rDamPct",
|
||||
"!elemental",
|
||||
"fSdRaw", "wSdRaw", "aSdRaw", "tSdRaw", "eSdRaw",
|
||||
"fSdPct", "wSdPct", "aSdPct", "tSdPct", "eSdPct",
|
||||
"fMdRaw", "wMdRaw", "aMdRaw", "tMdRaw", "eMdRaw",
|
||||
"fMdPct", "wMdPct", "aMdPct", "tMdPct", "eMdPct",
|
||||
"fDamRaw", "wDamRaw", "aDamRaw", "tDamRaw", "eDamRaw",
|
||||
"fDamPct", "wDamPct", "aDamPct", "tDamPct", "eDamPct",
|
||||
"fDefPct", "wDefPct", "aDefPct", "tDefPct", "eDefPct",
|
||||
"!elemental",
|
||||
"rDefPct",
|
||||
"spPct1", "spRaw1", "spPct2", "spRaw2", "spPct3", "spRaw3", "spPct4", "spRaw4",
|
||||
"atkTier",
|
||||
"poison",
|
||||
|
@ -312,6 +351,7 @@ let build_detailed_display_commands = [
|
|||
"spRegen",
|
||||
"eSteal",
|
||||
"gXp", "gSpd",
|
||||
"kb", "weakenEnemy", "slowEnemy",
|
||||
];
|
||||
|
||||
// full
|
||||
|
@ -368,11 +408,7 @@ let sq2_item_display_commands = [
|
|||
"!spacer",
|
||||
"str", "dex", "int", "def", "agi",
|
||||
"hpBonus",
|
||||
"hprRaw", "hprPct",
|
||||
"sdRaw", "nSdRaw", "eSdRaw", "tSdRaw", "wSdRaw", "fSdRaw", "aSdRaw", "rSdRaw",
|
||||
"sdPct", "nSdPct", "eSdPct", "tSdPct", "wSdPct", "fSdPct", "aSdPct", "rSdPct",
|
||||
"mdRaw", "nMdRaw", "eMdRaw", "tMdRaw", "wMdRaw", "fMdRaw", "aMdRaw", "rMdRaw",
|
||||
"mdPct", "nMdPct", "eMdPct", "tMdPct", "wMdPct", "fMdPct", "aMdPct", "rMdPct",
|
||||
"hprRaw", "hprPct", "healPct",
|
||||
"mr", "ms",
|
||||
"ref", "thorns",
|
||||
"ls",
|
||||
|
@ -380,10 +416,23 @@ let sq2_item_display_commands = [
|
|||
"expd",
|
||||
"spd",
|
||||
"atkTier",
|
||||
"sdRaw", "nSdRaw", "rSdRaw",
|
||||
"sdPct", "nSdPct", "rSdPct",
|
||||
"mdRaw", "nMdRaw", "rMdRaw",
|
||||
"mdPct", "nMdPct", "rMdPct",
|
||||
"damRaw", "nDamRaw", "rDamRaw",
|
||||
"damPct", "nDamPct", "rDamPct",
|
||||
"!elemental",
|
||||
"fSdRaw", "wSdRaw", "aSdRaw", "tSdRaw", "eSdRaw",
|
||||
"fSdPct", "wSdPct", "aSdPct", "tSdPct", "eSdPct",
|
||||
"fMdRaw", "wMdRaw", "aMdRaw", "tMdRaw", "eMdRaw",
|
||||
"fMdPct", "wMdPct", "aMdPct", "tMdPct", "eMdPct",
|
||||
"fDamRaw", "wDamRaw", "aDamRaw", "tDamRaw", "eDamRaw",
|
||||
"fDamPct", "wDamPct", "aDamPct", "tDamPct", "eDamPct",
|
||||
"fDefPct", "wDefPct", "aDefPct", "tDefPct", "eDefPct",
|
||||
"!elemental",
|
||||
"rDefPct",
|
||||
|
||||
"spPct1", "spRaw1", "spPct2", "spRaw2", "spPct3", "spRaw3", "spPct4", "spRaw4",
|
||||
"sprint", "sprintReg",
|
||||
"jh",
|
||||
|
@ -391,6 +440,7 @@ let sq2_item_display_commands = [
|
|||
"spRegen",
|
||||
"eSteal",
|
||||
"gXp", "gSpd",
|
||||
"kb", "weakenEnemy", "slowEnemy",
|
||||
"majorIds",
|
||||
"!spacer",
|
||||
"slots",
|
||||
|
@ -398,7 +448,7 @@ let sq2_item_display_commands = [
|
|||
"set",
|
||||
"lore",
|
||||
"quest",
|
||||
"restrict"
|
||||
"restrict",
|
||||
];
|
||||
|
||||
let sq2_ing_display_order = [
|
||||
|
|
|
@ -50,6 +50,14 @@ const ExprParser = (function() {
|
|||
case '=':
|
||||
pushSymbol(exprStr[col]);
|
||||
continue;
|
||||
case 'or':
|
||||
tokens.push({ type: '|' });
|
||||
col += 2;
|
||||
continue;
|
||||
case 'and':
|
||||
tokens.push({ type: '&' });
|
||||
col += 2;
|
||||
continue;
|
||||
case '>':
|
||||
pushSymbol(exprStr[col + 1] === '=' ? '>=' : '>');
|
||||
continue;
|
||||
|
|
209
js/ingredients.js
Normal file
209
js/ingredients.js
Normal file
|
@ -0,0 +1,209 @@
|
|||
// commented out filters
|
||||
// "Name": "name",
|
||||
// "Display Name": "displayName",
|
||||
// "Tier": "stars",
|
||||
// "Powder Slots": "slots",
|
||||
// "Health": "hp",
|
||||
// "Raw Fire Defense": "fDef",
|
||||
// "Raw Water Defense": "wDef",
|
||||
//"Raw Air Defense": "aDef",
|
||||
// "Raw Thunder Defense": "tDef",
|
||||
// "Raw Earth Defense": "eDef",
|
||||
|
||||
const translate_mappings = {
|
||||
"Durability": "durability",
|
||||
"Duration": "duration",
|
||||
"Charges": "charges",
|
||||
"Effectiveness Left": "left",
|
||||
"Effectiveness Right": "right",
|
||||
"Effectiveness Above": "above",
|
||||
"Effectiveness Under": "under",
|
||||
"Effectiveness Touching": "touching",
|
||||
"Effectiveness Not Touching": "nottouching",
|
||||
"Combat Level": "lvl",
|
||||
"Req Strength": "strReq",
|
||||
"Req Dexterity": "dexReq",
|
||||
"Req Intelligence": "intReq",
|
||||
"Req Agility": "agiReq",
|
||||
"Req Defense": "defReq",
|
||||
"% Health Regen": "hprPct",
|
||||
"Mana Regen": "mr",
|
||||
"Life Steal": "ls",
|
||||
"Mana Steal": "ms",
|
||||
"XP Bonus": "xpb",
|
||||
"Loot Bonus": "lb",
|
||||
"Reflection": "ref",
|
||||
"Strength": "str",
|
||||
"Dexterity": "dex",
|
||||
"Intelligence": "int",
|
||||
"Agility": "agi",
|
||||
"Defense": "def",
|
||||
"Thorns": "thorns",
|
||||
"Exploding": "expd",
|
||||
"Walk Speed": "spd",
|
||||
"Attack Speed Bonus": "atkTier",
|
||||
"Poison": "poison",
|
||||
"Health Bonus": "hpBonus",
|
||||
"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",
|
||||
|
||||
"% Fire Defense": "fDefPct",
|
||||
"% Water Defense": "wDefPct",
|
||||
"% Air Defense": "aDefPct",
|
||||
"% Thunder Defense": "tDefPct",
|
||||
"% Earth Defense": "eDefPct",
|
||||
"% Elemental Defense": "rDefPct",
|
||||
|
||||
"1st Spell Cost %": "-spPct1",
|
||||
"1st Spell Cost Raw": "-spRaw1",
|
||||
"2nd Spell Cost %": "-spPct2",
|
||||
"2nd Spell Cost Raw": "-spRaw2",
|
||||
"3rd Spell Cost %": "-spPct3",
|
||||
"3rd Spell Cost Raw": "-spRaw3",
|
||||
"4th Spell Cost %": "-spPct4",
|
||||
"4th Spell Cost Raw": "-spRaw4",
|
||||
"Rainbow Spell Damage Raw": "rainbowRaw",
|
||||
"Sprint": "sprint",
|
||||
"Sprint Regen": "sprintReg",
|
||||
"Jump Height": "jh",
|
||||
"Loot Quality": "lq",
|
||||
"Gather XP Bonus": "gXp",
|
||||
"Gather Speed Bonus": "gSpd",
|
||||
"Healing Efficiency": "healPct",
|
||||
"Knockback": "kb",
|
||||
"Weaken Enemy": "weakenEnemy",
|
||||
"Slow Enemy": "slowEnemy"
|
||||
};
|
||||
|
||||
const special_mappings = {
|
||||
"Sum (skill points)": "str+dex+int+def+agi",
|
||||
"Sum (Mana Sustain)": "mr+ms",
|
||||
"Sum (Life Sustain)": "hpr+ls",
|
||||
"Sum (Effectiveness)": "7/3 * touching + 8/3 * nottouching + 2/3 * (top + bottom) + 1/2 * (left + right)"
|
||||
};
|
||||
|
||||
for (let x in translate_mappings) {
|
||||
item_filters.push(x);
|
||||
}
|
||||
for (let x in special_mappings) {
|
||||
item_filters.push(x);
|
||||
}
|
||||
|
||||
|
||||
types = {armouring: false, tailoring: false, weaponsmithing: false, woodworking: false, jeweling: false, cooking: false, alchemism: false, scribing: false};
|
||||
search_tiers = {zero: true, one: true, two: true, three: true};
|
||||
|
||||
function display(ing_copy) {
|
||||
let ing_parent = document.getElementById("search-results");
|
||||
for (let i in ing_copy) {
|
||||
if (i > 200) {break;}
|
||||
let ing = ing_copy[i].itemExp;
|
||||
let box = make_elem('div', ['ing-stats', 'col-lg-3', 'p-2', 'col-sm-6'], {id: 'ing'+i});
|
||||
|
||||
let bckgrdbox = make_elem('div', ["rounded", "g-0", "dark-7", "border", "border-dark", "dark-shadow", "p-3", "col-auto"], {id: 'ing'+i+'b'});
|
||||
box.append(bckgrdbox);
|
||||
ing_parent.appendChild(box);
|
||||
|
||||
displayExpandedIngredient(ing, bckgrdbox.id, true);
|
||||
}
|
||||
}
|
||||
|
||||
function filter_types_tiers(queries) {
|
||||
// type
|
||||
let allTypes = true, noTypes = true;
|
||||
let typeQuery = "f:("
|
||||
for (const type of Object.keys(types)) {
|
||||
if (types[type]) {
|
||||
typeQuery += type + "|";
|
||||
noTypes = false;
|
||||
} else {
|
||||
allTypes = false;
|
||||
}
|
||||
}
|
||||
if (noTypes) {
|
||||
document.getElementById("summary").innerHTML = "Error: Cannot search without at least 1 type selected";
|
||||
return false;
|
||||
} else if (!allTypes) {
|
||||
queries.push(typeQuery.substring(0, typeQuery.length - 1) + ")");
|
||||
}
|
||||
|
||||
// stars
|
||||
let allStars = true, noStars = true;
|
||||
let starQuery = "f:("
|
||||
for (const star of Object.keys(search_tiers)) {
|
||||
if (search_tiers[star]) {
|
||||
starQuery += "starsname=\"" + star + "\"|";
|
||||
noStars = false;
|
||||
} else {
|
||||
allStars = false;
|
||||
}
|
||||
}
|
||||
if (noStars) {
|
||||
document.getElementById("summary").innerHTML = "Error: Cannot search without at least 1 star selected";
|
||||
return false;
|
||||
} else if (!allStars) {
|
||||
queries.push(starQuery.substring(0, starQuery.length - 1) + ")");
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
function init_values() {
|
||||
search_db = ings.filter( i => ! i.remapID ).map( i => [i, expandIngredient(i, [])] );
|
||||
expr_parser = new ExprParser(ingredientQueryProps, queryFuncs);
|
||||
}
|
||||
|
||||
(async function() {
|
||||
await Promise.resolve(load_ing_init());
|
||||
init_search();
|
||||
})();
|
||||
|
54
js/ingredients_adv.js
Normal file
54
js/ingredients_adv.js
Normal file
|
@ -0,0 +1,54 @@
|
|||
const getQueryIdentifiers = (function() {
|
||||
let identCache = null;
|
||||
return function() {
|
||||
if (identCache === null) {
|
||||
const idents = new Set();
|
||||
for (const ident of Object.keys(ingredientQueryProps)) {
|
||||
idents.add(ident);
|
||||
}
|
||||
for (const ident of Object.keys(queryFuncs)) {
|
||||
idents.add(ident);
|
||||
}
|
||||
identCache = [...idents].sort(); // might use a trie optimally, but the set is probably small enough...
|
||||
}
|
||||
return identCache;
|
||||
};
|
||||
})();
|
||||
|
||||
function generateEntries(size, itemList, itemEntries) {
|
||||
for (let i = 0; i < size; i++) {
|
||||
const itemElem = document.createElement('div');
|
||||
itemElem.classList.add('col-lg-3', 'col-sm-6', "p-2", "ing-stats");
|
||||
// itemElem.setAttribute('id', `item-entry-${i}`);
|
||||
itemList.append(itemElem);
|
||||
itemEntries.push(itemElem);
|
||||
|
||||
const itemElemContained = document.createElement("div");
|
||||
itemElemContained.classList.add("dark-7", "rounded", "p-3", "col-auto", "g-0", "border", "border-dark", "dark-shadow");
|
||||
|
||||
itemElemContained.setAttribute('id', `item-entry-${i}`);
|
||||
itemElem.appendChild(itemElemContained);
|
||||
|
||||
const sortKeyListContainer = document.createElement('div');
|
||||
sortKeyListContainer.classList.add('row');
|
||||
sortKeyListContainer.setAttribute('id', `item-sort-entry-${i}`);
|
||||
itemEntries[i].append(sortKeyListContainer);
|
||||
}
|
||||
}
|
||||
|
||||
function init_values() {
|
||||
// compile the search db from the item db
|
||||
searchDb = ings.filter(i => !i.remapID).map(i => [i, expandIngredient(i)]);
|
||||
|
||||
// create the expression parser
|
||||
exprParser = new ExprParser(ingredientQueryProps, queryFuncs);
|
||||
}
|
||||
|
||||
function display(itemExp, id) {
|
||||
displayExpandedIngredient(itemExp, id);
|
||||
}
|
||||
|
||||
(async function() {
|
||||
await Promise.resolve(load_ing_init());
|
||||
init_items_adv();
|
||||
})();
|
|
@ -60,7 +60,8 @@ function toggleAmps(button_id) {
|
|||
|
||||
|
||||
(async function() {
|
||||
let load_promises = [ load_init() ];
|
||||
let latest_ver_name = wynn_version_names[WYNN_VERSION_LATEST];
|
||||
let load_promises = [ load_init(), load_major_id_data(latest_ver_name) ];
|
||||
await Promise.all(load_promises);
|
||||
init_itempage();
|
||||
})();
|
||||
|
|
414
js/item_display.js
Normal file
414
js/item_display.js
Normal file
|
@ -0,0 +1,414 @@
|
|||
/*
|
||||
* File for display commands specific to the single item page.
|
||||
*/
|
||||
|
||||
/** Displays the ID costs of an item
|
||||
*
|
||||
* @param {String} elemID - the id of the parent element.
|
||||
* @param {Map} item - the statMap of an item.
|
||||
*/
|
||||
function displayIDCosts(elemID, item) {
|
||||
let parent_elem = document.getElementById(elemID);
|
||||
let tier = item.get("tier");
|
||||
if ( (item.has("fixID") && item.get("fixID")) || ["Normal","Crafted","Custom","none", " ",].includes(item.get("tier"))) {
|
||||
return;
|
||||
} else {
|
||||
/** Returns the number of inventory slots minimum an amount of emeralds would take up + the configuration of doing so.
|
||||
* Returns an array of [invSpace, E, EB, LE, Stx LE]
|
||||
*
|
||||
* @param {number} ems - the total numerical value of emeralds to compact.
|
||||
*/
|
||||
function emsToInvSpace(ems) {
|
||||
let stx = Math.floor(ems/262144);
|
||||
ems -= stx*4096*64;
|
||||
let LE = Math.floor(ems/4096);
|
||||
ems -= LE*4096;
|
||||
let EB = Math.floor(ems/64);
|
||||
ems -= EB*64;
|
||||
let e = ems;
|
||||
return [ stx + Math.ceil(LE/64) + Math.ceil(EB/64) + Math.ceil(e/64) , e, EB, LE, stx];
|
||||
}
|
||||
/**
|
||||
*
|
||||
* @param {String} tier - item tier
|
||||
* @param {Number} lvl - item level
|
||||
*/
|
||||
function getIDCost(tier, lvl) {
|
||||
switch (tier) {
|
||||
case "Unique":
|
||||
return Math.round(0.5*lvl + 3);
|
||||
case "Rare":
|
||||
return Math.round(1.2*lvl + 8);
|
||||
case "Legendary":
|
||||
return Math.round(4.5*lvl + 12);
|
||||
case "Fabled":
|
||||
return Math.round(12*lvl + 26);
|
||||
case "Mythic":
|
||||
return Math.round(18*lvl + 90);
|
||||
case "Set":
|
||||
return Math.round(1.5*lvl + 8)
|
||||
default:
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
parent_elem.style = "display: visible";
|
||||
let lvl = item.get("lvl");
|
||||
if (typeof(lvl) === "string") { lvl = parseFloat(lvl); }
|
||||
|
||||
let title_elem = document.createElement("p");
|
||||
title_elem.classList.add("smalltitle");
|
||||
title_elem.style.color = "white";
|
||||
title_elem.textContent = "Identification Costs";
|
||||
parent_elem.appendChild(title_elem);
|
||||
parent_elem.appendChild(document.createElement("br"));
|
||||
|
||||
let grid_item = document.createElement("div");
|
||||
grid_item.style.display = "flex";
|
||||
grid_item.style.flexDirection = "rows";
|
||||
grid_item.style.flexWrap = "wrap";
|
||||
grid_item.style.gap = "5px";
|
||||
parent_elem.appendChild(grid_item);
|
||||
|
||||
let IDcost = getIDCost(tier, lvl);
|
||||
let initIDcost = IDcost;
|
||||
let invSpace = emsToInvSpace(IDcost);
|
||||
let rerolls = 0;
|
||||
|
||||
while(invSpace[0] <= 28 && IDcost > 0) {
|
||||
let container = document.createElement("div");
|
||||
container.classList.add("container");
|
||||
container.style = "grid-item-" + (rerolls+1);
|
||||
container.style.maxWidth = "max(120px, 15%)";
|
||||
|
||||
let container_title = document.createElement("p");
|
||||
container_title.style.color = "white";
|
||||
if (rerolls == 0) {
|
||||
container_title.textContent = "Initial ID Cost: ";
|
||||
} else {
|
||||
container_title.textContent = "Reroll to [" + (rerolls+1) + "] Cost:";
|
||||
}
|
||||
container.appendChild(container_title);
|
||||
let total_cost_container = document.createElement("p");
|
||||
let total_cost_number = document.createElement("b");
|
||||
total_cost_number.classList.add("Set");
|
||||
total_cost_number.textContent = IDcost + " ";
|
||||
let total_cost_suffix = document.createElement("b");
|
||||
total_cost_suffix.textContent = "emeralds."
|
||||
total_cost_container.appendChild(total_cost_number);
|
||||
total_cost_container.appendChild(total_cost_suffix);
|
||||
container.appendChild(total_cost_container);
|
||||
|
||||
let OR = document.createElement("p");
|
||||
OR.classList.add("center");
|
||||
OR.textContent = "OR";
|
||||
container.appendChild(OR);
|
||||
|
||||
let esuffixes = ["", "emeralds.", "EB.", "LE.", "stacks of LE."];
|
||||
for (let i = 4; i > 0; i--) {
|
||||
let n_container = document.createElement("p");
|
||||
let n_number = document.createElement("b");
|
||||
n_number.classList.add("Set");
|
||||
n_number.textContent = invSpace[i] + " ";
|
||||
let n_suffix = document.createElement("b");
|
||||
n_suffix.textContent = esuffixes[i];
|
||||
n_container.appendChild(n_number);
|
||||
n_container.appendChild(n_suffix);
|
||||
container.appendChild(n_container);
|
||||
}
|
||||
grid_item.appendChild(container);
|
||||
|
||||
rerolls += 1;
|
||||
IDcost = Math.round(initIDcost * (5 ** rerolls));
|
||||
invSpace = emsToInvSpace(IDcost);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/** Displays Additional Info for
|
||||
*
|
||||
* @param {String} elemID - the parent element's id
|
||||
* @param {Map} item - the statMap of the item
|
||||
* @returns
|
||||
*/
|
||||
function displayAdditionalInfo(elemID, item) {
|
||||
let parent_elem = document.getElementById(elemID);
|
||||
parent_elem.classList.add("left");
|
||||
|
||||
let droptype_elem = document.createElement("div");
|
||||
droptype_elem.classList.add("container");
|
||||
droptype_elem.style.marginBottom = "5px";
|
||||
droptype_elem.textContent = "Drop type: " + (item.has("drop") ? item.get("drop"): "NEVER");
|
||||
parent_elem.appendChild(droptype_elem);
|
||||
|
||||
let warning_elem = document.createElement("div");
|
||||
warning_elem.classList.add("container");
|
||||
warning_elem.style.marginBottom ="5px";
|
||||
warning_elem.textContent = "This page is incomplete. Will work on it later.";
|
||||
parent_elem.appendChild(warning_elem);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
/** Displays the individual probabilities of each possible value of each rollable ID for this item.
|
||||
*
|
||||
* @param {String} parent_id the document id of the parent element
|
||||
* @param {String} item expandedItem object
|
||||
* @param {String} amp the level of corkian amplifier used. 0 means no amp, 1 means Corkian Amplifier I, etc. [0,3]
|
||||
*/
|
||||
function displayIDProbabilities(parent_id, item, amp) {
|
||||
if (item.has("fixID") && item.get("fixID")) {return}
|
||||
let parent_elem = document.getElementById(parent_id);
|
||||
parent_elem.style.display = "";
|
||||
parent_elem.innerHTML = "";
|
||||
let title_elem = document.createElement("p");
|
||||
title_elem.textContent = "Identification Probabilities";
|
||||
title_elem.id = "ID_PROB_TITLE";
|
||||
title_elem.classList.add("Legendary");
|
||||
title_elem.classList.add("title");
|
||||
parent_elem.appendChild(title_elem);
|
||||
|
||||
let disclaimer_elem = document.createElement("p");
|
||||
disclaimer_elem.textContent = "IDs are rolled on a uniform distribution. A chance of 0% means that either the minimum or maximum possible multiplier must be rolled to get this value."
|
||||
parent_elem.appendChild(disclaimer_elem);
|
||||
|
||||
let amp_row = document.createElement("p");
|
||||
amp_row.id = "amp_row";
|
||||
let amp_text = document.createElement("b");
|
||||
amp_text.textContent = "Corkian Amplifier Used: "
|
||||
amp_row.appendChild(amp_text);
|
||||
let amp_1 = document.createElement("button");
|
||||
amp_1.id = "cork_amp_1";
|
||||
amp_1.textContent = "I";
|
||||
amp_row.appendChild(amp_1);
|
||||
let amp_2 = document.createElement("button");
|
||||
amp_2.id = "cork_amp_2";
|
||||
amp_2.textContent = "II";
|
||||
amp_row.appendChild(amp_2);
|
||||
let amp_3 = document.createElement("button");
|
||||
amp_3.id = "cork_amp_3";
|
||||
amp_3.textContent = "III";
|
||||
amp_row.appendChild(amp_3);
|
||||
amp_1.addEventListener("click", (event) => {toggleAmps(1)});
|
||||
amp_2.addEventListener("click", (event) => {toggleAmps(2)});
|
||||
amp_3.addEventListener("click", (event) => {toggleAmps(3)});
|
||||
parent_elem.appendChild(amp_row);
|
||||
|
||||
if (amp != 0) {toggleButton("cork_amp_" + amp)}
|
||||
|
||||
let item_name = item.get("displayName");
|
||||
console.log(itemMap.get(item_name))
|
||||
|
||||
let table_elem = document.createElement("table");
|
||||
parent_elem.appendChild(table_elem);
|
||||
for (const [id,val] of Object.entries(itemMap.get(item_name))) {
|
||||
if (rolledIDs.includes(id)) {
|
||||
if (!item.get("maxRolls").get(id)) { continue; }
|
||||
let min = item.get("minRolls").get(id);
|
||||
let max = item.get("maxRolls").get(id);
|
||||
//Apply corkian amps
|
||||
if (val > 0) {
|
||||
let base = itemMap.get(item_name)[id];
|
||||
if (reversedIDs.includes(id)) {max = Math.max( Math.round((0.3 + 0.05*amp) * base), 1)}
|
||||
else {min = Math.max( Math.round((0.3 + 0.05*amp) * base), 1)}
|
||||
}
|
||||
|
||||
let row_title = document.createElement("tr");
|
||||
//row_title.style.textAlign = "left";
|
||||
let title_left = document.createElement("td");
|
||||
let left_elem = document.createElement("p");
|
||||
let left_val_title = document.createElement("b");
|
||||
let left_val_elem = document.createElement("b");
|
||||
title_left.style.textAlign = "left";
|
||||
left_val_title.textContent = idPrefixes[id] + "Base ";
|
||||
left_val_elem.textContent = val + idSuffixes[id];
|
||||
if (val > 0 == !reversedIDs.includes(id)) {
|
||||
left_val_elem.classList.add("positive");
|
||||
} else if (val > 0 == reversedIDs.includes(id)) {
|
||||
left_val_elem.classList.add("negative");
|
||||
}
|
||||
left_elem.appendChild(left_val_title);
|
||||
left_elem.appendChild(left_val_elem);
|
||||
title_left.appendChild(left_elem);
|
||||
row_title.appendChild(title_left);
|
||||
|
||||
let title_right = document.createElement("td");
|
||||
let title_right_text = document.createElement("b");
|
||||
title_right.style.textAlign = "left";
|
||||
title_right_text.textContent = "[ " + min + idSuffixes[id] + ", " + max + idSuffixes[id] + " ]";
|
||||
if ( (min > 0 && max > 0 && !reversedIDs.includes(id)) || (min < 0 && max < 0 && reversedIDs.includes(id)) ) {
|
||||
title_right_text.classList.add("positive");
|
||||
} else if ( (min < 0 && max < 0 && !reversedIDs.includes(id)) || (min > 0 && max > 0 && reversedIDs.includes(id)) ) {
|
||||
title_right_text.classList.add("negative");
|
||||
}
|
||||
title_right.appendChild(title_right_text);
|
||||
|
||||
let title_input = document.createElement("td");
|
||||
let title_input_slider = document.createElement("input");
|
||||
title_input_slider.type = "range";
|
||||
title_input_slider.id = id+"-slider";
|
||||
if (!reversedIDs.includes(id)) {
|
||||
title_input_slider.step = 1;
|
||||
title_input_slider.min = `${min}`;
|
||||
title_input_slider.max = `${max}`;
|
||||
title_input_slider.value = `${max}`;
|
||||
} else {
|
||||
title_input_slider.step = 1;
|
||||
title_input_slider.min = `${-1*min}`;
|
||||
title_input_slider.max = `${-1*max}`;
|
||||
title_input_slider.value = `${-1*max}`;
|
||||
}
|
||||
let title_input_textbox = document.createElement("input");
|
||||
title_input_textbox.type = "text";
|
||||
title_input_textbox.value = `${max}`;
|
||||
title_input_textbox.id = id+"-textbox";
|
||||
title_input_textbox.classList.add("small-input");
|
||||
title_input.appendChild(title_input_slider);
|
||||
title_input.appendChild(title_input_textbox);
|
||||
|
||||
row_title.appendChild(title_left);
|
||||
row_title.appendChild(title_right);
|
||||
row_title.appendChild(title_input);
|
||||
|
||||
let row_chances = document.createElement("tr");
|
||||
let chance_cdf = document.createElement("td");
|
||||
let chance_pdf = document.createElement("td");
|
||||
let cdf_p = document.createElement("p");
|
||||
cdf_p.id = id+"-cdf";
|
||||
let pdf_p = document.createElement("p");
|
||||
pdf_p.id = id+"-pdf";
|
||||
|
||||
chance_cdf.appendChild(cdf_p);
|
||||
chance_pdf.appendChild(pdf_p);
|
||||
row_chances.appendChild(chance_cdf);
|
||||
row_chances.appendChild(chance_pdf);
|
||||
|
||||
table_elem.appendChild(row_title);
|
||||
table_elem.appendChild(row_chances);
|
||||
|
||||
|
||||
|
||||
stringPDF(id, max, val, amp); //val is base roll
|
||||
stringCDF(id, max, val, amp); //val is base roll
|
||||
title_input_slider.addEventListener("change", (event) => {
|
||||
let id_name = event.target.id.split("-")[0];
|
||||
let textbox_elem = document.getElementById(id_name+"-textbox");
|
||||
|
||||
if (reversedIDs.includes(id_name)) {
|
||||
if (event.target.value < -1*min) { event.target.value = -1*min}
|
||||
if (event.target.value > -1*max) { event.target.value = -1*max}
|
||||
stringPDF(id_name, -1*event.target.value, val, amp); //val is base roll
|
||||
stringCDF(id_name, -1*event.target.value, val, amp); //val is base roll
|
||||
} else {
|
||||
if (event.target.value < min) { event.target.value = min}
|
||||
if (event.target.value > max) { event.target.value = max}
|
||||
stringPDF(id_name, 1*event.target.value, val, amp); //val is base roll
|
||||
stringCDF(id_name, 1*event.target.value, val, amp); //val is base roll
|
||||
}
|
||||
|
||||
if (textbox_elem && textbox_elem.value !== event.target.value) {
|
||||
if (reversedIDs.includes(id_name)) {
|
||||
textbox_elem.value = -event.target.value;
|
||||
} else {
|
||||
textbox_elem.value = event.target.value;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
});
|
||||
title_input_textbox.addEventListener("change", (event) => {
|
||||
let id_name = event.target.id.split("-")[0];
|
||||
if (reversedIDs.includes(id_name)) {
|
||||
if (event.target.value > min) { event.target.value = min}
|
||||
if (event.target.value < max) { event.target.value = max}
|
||||
} else {
|
||||
if (event.target.value < min) { event.target.value = min}
|
||||
if (event.target.value > max) { event.target.value = max}
|
||||
}
|
||||
let slider_elem = document.getElementById(id_name+"-slider");
|
||||
if (slider_elem.value !== event.target.value) {
|
||||
slider_elem.value = -event.target.value;
|
||||
}
|
||||
|
||||
stringPDF(id_name, 1*event.target.value, val, amp);
|
||||
stringCDF(id_name, 1*event.target.value, val, amp);
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//helper functions. id - the string of the id's name, val - the value of the id, base - the base value of the item for this id
|
||||
function stringPDF(id,val,base,amp) {
|
||||
/** [0.3b,1.3b] positive normal
|
||||
* [1.3b,0.3b] positive reversed
|
||||
* [1.3b,0.7b] negative normal
|
||||
* [0.7b,1.3b] negative reversed
|
||||
*
|
||||
* [0.3, 1.3] minr, maxr [0.3b, 1.3b] min, max
|
||||
* the minr/maxr decimal roll that corresponds to val -> minround, maxround
|
||||
*/
|
||||
let p; let min; let max; let minr; let maxr; let minround; let maxround;
|
||||
if (base > 0) {
|
||||
minr = 0.3 + 0.05*amp; maxr = 1.3;
|
||||
min = Math.max(1, Math.round(minr*base)); max = Math.max(1, Math.round(maxr*base));
|
||||
minround = (min == max) ? (minr) : ( Math.max(minr, (val-0.5) / base) );
|
||||
maxround = (min == max) ? (maxr) : ( Math.min(maxr, (val+0.5) / base) );
|
||||
} else {
|
||||
minr = 1.3; maxr = 0.7;
|
||||
min = Math.min(-1, Math.round(minr*base)); max = Math.min(-1, Math.round(maxr*base));
|
||||
minround = (min == max) ? (minr) : ( Math.min(minr, (val-0.5) / base) );
|
||||
maxround = (min == max) ? (maxr) : ( Math.max(maxr, (val+0.5) / base) );
|
||||
}
|
||||
|
||||
p = Math.abs(maxround-minround)/Math.abs(maxr-minr)*100;
|
||||
p = p.toFixed(3);
|
||||
|
||||
let b1 = document.createElement("b");
|
||||
b1.textContent = "Roll exactly ";
|
||||
let b2 = document.createElement("b");
|
||||
b2.textContent = val + idSuffixes[id];
|
||||
if (val > 0 == !reversedIDs.includes(id)) {b2.classList.add("positive")}
|
||||
if (val > 0 == reversedIDs.includes(id)) {b2.classList.add("negative")}
|
||||
let b3 = document.createElement("b");
|
||||
b3.textContent = ": " + p + "%";
|
||||
document.getElementById(id + "-pdf").innerHTML = "";
|
||||
document.getElementById(id + "-pdf").appendChild(b1);
|
||||
document.getElementById(id + "-pdf").appendChild(b2);
|
||||
document.getElementById(id + "-pdf").appendChild(b3);
|
||||
}
|
||||
|
||||
function stringCDF(id,val,base,amp) {
|
||||
let p; let min; let max; let minr; let maxr; let minround; let maxround;
|
||||
if (base > 0) {
|
||||
minr = 0.3 + 0.05*amp; maxr = 1.3;
|
||||
min = Math.max(1, Math.round(minr*base)); max = Math.max(1, Math.round(maxr*base));
|
||||
minround = (min == max) ? (minr) : ( Math.max(minr, (val-0.5) / base) );
|
||||
maxround = (min == max) ? (maxr) : ( Math.min(maxr, (val+0.5) / base) );
|
||||
} else {
|
||||
minr = 1.3; maxr = 0.7;
|
||||
min = Math.min(-1, Math.round(minr*base)); max = Math.min(-1, Math.round(maxr*base));
|
||||
minround = (min == max) ? (minr) : ( Math.min(minr, (val-0.5) / base) );
|
||||
maxround = (min == max) ? (maxr) : ( Math.max(maxr, (val+0.5) / base) );
|
||||
}
|
||||
|
||||
if (reversedIDs.includes(id)) {
|
||||
p = Math.abs(minr-maxround)/Math.abs(maxr-minr)*100;
|
||||
} else {
|
||||
p = Math.abs(maxr-minround)/Math.abs(maxr-minr)*100;
|
||||
}
|
||||
p = p.toFixed(3);
|
||||
|
||||
let b1 = document.createElement("b");
|
||||
b1.textContent = "Roll ";
|
||||
let b2 = document.createElement("b");
|
||||
b2.textContent = val + idSuffixes[id];
|
||||
if (val > 0 == !reversedIDs.includes(id)) {b2.classList.add("positive")}
|
||||
if (val > 0 == reversedIDs.includes(id)) {b2.classList.add("negative")}
|
||||
let b3 = document.createElement("b");
|
||||
b3.textContent= " or better: " + p + "%";
|
||||
document.getElementById(id + "-cdf").innerHTML = "";
|
||||
document.getElementById(id + "-cdf").appendChild(b1);
|
||||
document.getElementById(id + "-cdf").appendChild(b2);
|
||||
document.getElementById(id + "-cdf").appendChild(b3);
|
||||
}
|
444
js/items.js
444
js/items.js
|
@ -56,18 +56,62 @@ const translate_mappings = {
|
|||
"Soul Point Regen": "spRegen",
|
||||
"Stealing": "eSteal",
|
||||
"Raw Health Regen": "hprRaw",
|
||||
"Raw Spell": "sdRaw",
|
||||
"Raw Melee": "mdRaw",
|
||||
"% Fire Damage": "fDamPct",
|
||||
"% Water Damage": "wDamPct",
|
||||
"% Air Damage": "aDamPct",
|
||||
"% Thunder Damage": "tDamPct",
|
||||
"% Earth Damage": "eDamPct",
|
||||
"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",
|
||||
"% Air Defense": "aDefPct",
|
||||
"% Thunder Defense": "tDefPct",
|
||||
"% Earth Defense": "eDefPct",
|
||||
"% Elemental Defense": "rDefPct",
|
||||
|
||||
"1st Spell Cost %": "-spPct1",
|
||||
"1st Spell Cost Raw": "-spRaw1",
|
||||
"2nd Spell Cost %": "-spPct2",
|
||||
|
@ -76,13 +120,16 @@ const translate_mappings = {
|
|||
"3rd Spell Cost Raw": "-spRaw3",
|
||||
"4th Spell Cost %": "-spPct4",
|
||||
"4th Spell Cost Raw": "-spRaw4",
|
||||
"Rainbow Spell Damage Raw": "rainbowRaw",
|
||||
"Sprint": "sprint",
|
||||
"Sprint Regen": "sprintReg",
|
||||
"Jump Height": "jh",
|
||||
"Loot Quality": "lq",
|
||||
"Gather XP Bonus": "gXp",
|
||||
"Gather Speed Bonus": "gSpd"
|
||||
"Gather Speed Bonus": "gSpd",
|
||||
"Healing Efficiency": "healPct",
|
||||
"Knockback": "kb",
|
||||
"Weaken Enemy": "weakenEnemy",
|
||||
"Slow Enemy": "slowEnemy"
|
||||
};
|
||||
|
||||
const special_mappings = {
|
||||
|
@ -93,7 +140,6 @@ const special_mappings = {
|
|||
"Base DPS": "(nDam+fDam+wDam+aDam+tDam+eDam) * atkspdmod(atkspd)"
|
||||
};
|
||||
|
||||
let item_filters = [];
|
||||
for (let x in translate_mappings) {
|
||||
item_filters.push(x);
|
||||
}
|
||||
|
@ -101,18 +147,17 @@ for (let x in special_mappings) {
|
|||
item_filters.push(x);
|
||||
}
|
||||
|
||||
let item_categories = ["armor", "accessory", "weapon"];
|
||||
types = {bow: false, spear: false, wand: false, dagger: false, relik: false, helmet: false, chestplate: false, leggings: false, boots: false, ring: false, bracelet: false, necklace: false};
|
||||
search_tiers = {normal: true, unique: true, set: true, rare: true, legendary: true, fabled: true, mythic: true};
|
||||
|
||||
const types = {bow: false, spear: false, wand: false, dagger: false, relik: false, helmet: false, chestplate: false, leggings: false, boots: false, ring: false, bracelet: false, necklace: false};
|
||||
const rarities = {normal: true, unique: true, set: true, rare: true, legendary: true, fabled: true, mythic: true};
|
||||
const filters = [], excludes = [];
|
||||
let filter_id_counter = 0;
|
||||
|
||||
function displayItems(items_copy) {
|
||||
function display(items_copy) {
|
||||
let items_parent = document.getElementById("search-results");
|
||||
for (let i in items_copy) {
|
||||
if (i > 200) {break;}
|
||||
let item = items_copy[i].itemExp;
|
||||
|
||||
|
||||
|
||||
let box = make_elem('div', ['col-lg-3', 'col-sm-6', 'p-2'], {id: 'item'+i});
|
||||
|
||||
let bckgrdbox = make_elem("div", ["dark-7", "rounded", "px-2", "col-auto"], {id: 'item'+i+'b'});
|
||||
|
@ -126,19 +171,7 @@ function displayItems(items_copy) {
|
|||
}
|
||||
}
|
||||
|
||||
let search_db;
|
||||
let expr_parser;
|
||||
|
||||
function do_item_search() {
|
||||
document.getElementById("summary").style.color = "red"; // to display errors, changed to white if search successful
|
||||
window.scrollTo(0, 0);
|
||||
let queries = [];
|
||||
|
||||
// name
|
||||
if (document.getElementById("item-name-choice").value != "") {
|
||||
queries.push("f:name?=\"" + document.getElementById("item-name-choice").value.trim() + "\"");
|
||||
}
|
||||
|
||||
function filter_types_tiers(queries) {
|
||||
// types
|
||||
let allTypes = true, noTypes = true;
|
||||
let typeQuery = "f:("
|
||||
|
@ -152,7 +185,7 @@ function do_item_search() {
|
|||
}
|
||||
if (noTypes) {
|
||||
document.getElementById("summary").innerHTML = "Error: Cannot search without at least 1 type selected";
|
||||
return;
|
||||
return false;
|
||||
} else if (!allTypes) {
|
||||
queries.push(typeQuery.substring(0, typeQuery.length - 1) + ")");
|
||||
}
|
||||
|
@ -160,8 +193,8 @@ function do_item_search() {
|
|||
// rarities
|
||||
let allRarities = true, noRarities = true;
|
||||
let rarityQuery = "f:("
|
||||
for (const rarity of Object.keys(rarities)) {
|
||||
if (rarities[rarity]) {
|
||||
for (const rarity of Object.keys(search_tiers)) {
|
||||
if (search_tiers[rarity]) {
|
||||
rarityQuery += "tiername=\"" + rarity + "\"|";
|
||||
noRarities = false;
|
||||
} else {
|
||||
|
@ -170,353 +203,20 @@ function do_item_search() {
|
|||
}
|
||||
if (noRarities) {
|
||||
document.getElementById("summary").innerHTML = "Error: Cannot search without at least 1 rarity selected";
|
||||
return;
|
||||
return false;
|
||||
} else if (!allRarities) {
|
||||
queries.push(rarityQuery.substring(0, rarityQuery.length - 1) + ")");
|
||||
}
|
||||
|
||||
// filters
|
||||
for (const filter of filters) {
|
||||
let min = parseInt(filter.min_elem.value);
|
||||
let max = parseInt(filter.max_elem.value);
|
||||
if (min > max) {
|
||||
document.getElementById("summary").innerHTML = "Error: The minimum of filter " + filter.input_elem.value + " (" + min + ") is greater than its maximum (" + max + ")";
|
||||
return;
|
||||
}
|
||||
let zero_in_min_max = (isNaN(min) || min < 0) && (isNaN(max) || max > 0);
|
||||
|
||||
let raw_name = filter.input_elem.value;
|
||||
if (raw_name == "") {
|
||||
continue; // empty
|
||||
}
|
||||
let filter_name = translate_mappings[raw_name];
|
||||
if (filter_name === undefined) {
|
||||
filter_name = special_mappings[raw_name];
|
||||
if (filter_name === undefined) {
|
||||
document.getElementById("summary").innerHTML = "Error: The filter \"" + filter.input_elem.value + "\" is not recognized";
|
||||
return;
|
||||
}
|
||||
filter_name = "(" + filter_name + ")";
|
||||
}
|
||||
|
||||
if (!isNaN(min)) {
|
||||
queries.push("f:" + filter_name + ">=" + min);
|
||||
}
|
||||
if (!isNaN(max)) {
|
||||
queries.push("f:" + filter_name + "<=" + max);
|
||||
}
|
||||
if (zero_in_min_max) {
|
||||
queries.push("f:" + filter_name + "!=0");
|
||||
}
|
||||
queries.push("s:" + (filter.ascending ? "0-" : "") + filter_name);
|
||||
}
|
||||
|
||||
// excludes
|
||||
for (const exclude of excludes) {
|
||||
let raw_name = exclude.input_elem.value;
|
||||
if (raw_name == "") {
|
||||
continue; // empty
|
||||
}
|
||||
let filter_name = translate_mappings[raw_name];
|
||||
if (filter_name === undefined) {
|
||||
filter_name = special_mappings[raw_name];
|
||||
if (filter_name === undefined) {
|
||||
document.getElementById("summary").innerHTML = "Error: The excluded filter \"" + exclude.input_elem.value + "\" is not recognized";
|
||||
return;
|
||||
}
|
||||
filter_name = "(" + filter_name + ")";
|
||||
}
|
||||
queries.push("f:" + filter_name + "=0");
|
||||
}
|
||||
|
||||
let filter_query = "true";
|
||||
let sort_queries = [];
|
||||
console.log(queries);
|
||||
for (const query of queries) {
|
||||
if (query.startsWith("s:")) {
|
||||
sort_queries.push(query.slice(2));
|
||||
}
|
||||
else if (query.startsWith("f:")) {
|
||||
filter_query = filter_query + "&" + query.slice(2);
|
||||
}
|
||||
}
|
||||
document.getElementById("search-results").textContent = "";
|
||||
let results = [];
|
||||
try {
|
||||
const filter_expr = expr_parser.parse(filter_query);
|
||||
const sort_exprs = sort_queries.map(q => expr_parser.parse(q));
|
||||
for (let i = 0; i < search_db.length; ++i) {
|
||||
const item = search_db[i][0];
|
||||
const itemExp = search_db[i][1];
|
||||
if (checkBool(filter_expr.resolve(item, itemExp))) {
|
||||
results.push({ item, itemExp, sortKeys: sort_exprs.map(e => e.resolve(item, itemExp)) });
|
||||
}
|
||||
}
|
||||
results.sort((a, b) => {
|
||||
return compareLexico(a.item, a.sortKeys, b.item, b.sortKeys);
|
||||
});
|
||||
} catch (e) {
|
||||
document.getElementById("summary").textContent = e.message;
|
||||
return;
|
||||
}
|
||||
document.getElementById("summary").textContent = results.length + " results:";
|
||||
document.getElementById("summary").style.color = "white";
|
||||
displayItems(results);
|
||||
return true;
|
||||
}
|
||||
|
||||
function init_items() {
|
||||
function init_values() {
|
||||
search_db = items.filter( i => ! i.remapID ).map( i => [i, expandItem(i, [])] );
|
||||
expr_parser = new ExprParser(itemQueryProps, itemQueryFuncs);
|
||||
|
||||
// init type buttons
|
||||
for (const type of Object.keys(types)) {
|
||||
document.getElementById("type-" + type).addEventListener("click", function() {
|
||||
types[type] = !types[type];
|
||||
this.classList.toggle("type-selected");
|
||||
});
|
||||
}
|
||||
document.getElementById("all-types").addEventListener("click", function() {
|
||||
for (const type of Object.keys(types)) {
|
||||
types[type] = true;
|
||||
document.getElementById("type-" + type).classList.add("type-selected");
|
||||
}
|
||||
});
|
||||
document.getElementById("none-types").addEventListener("click", function() {
|
||||
for (const type of Object.keys(types)) {
|
||||
types[type] = false;
|
||||
document.getElementById("type-" + type).classList.remove("type-selected");
|
||||
}
|
||||
});
|
||||
|
||||
// init rarity buttons
|
||||
for (const rarity of Object.keys(rarities)) {
|
||||
document.getElementById("rarity-" + rarity).addEventListener("click", function() {
|
||||
rarities[rarity] = !rarities[rarity];
|
||||
this.classList.toggle("rarity-selected");
|
||||
});
|
||||
}
|
||||
document.getElementById("all-rarities").addEventListener("click", function() {
|
||||
for (const rarity of Object.keys(rarities)) {
|
||||
rarities[rarity] = true;
|
||||
document.getElementById("rarity-" + rarity).classList.add("rarity-selected");
|
||||
}
|
||||
});
|
||||
document.getElementById("none-rarities").addEventListener("click", function() {
|
||||
for (const rarity of Object.keys(rarities)) {
|
||||
rarities[rarity] = false;
|
||||
document.getElementById("rarity-" + rarity).classList.remove("rarity-selected");
|
||||
}
|
||||
});
|
||||
|
||||
// filters
|
||||
document.getElementById("add-filter").addEventListener("click", create_filter);
|
||||
document.getElementById("add-exclude").addEventListener("click", create_exclude);
|
||||
create_filter();
|
||||
filters[0].input_elem.value = "Combat Level";
|
||||
init_filter_drag();
|
||||
}
|
||||
|
||||
function reset_item_search() {
|
||||
document.getElementById("item-name-choice").value = "";
|
||||
document.getElementById("all-types").click();
|
||||
document.getElementById("all-rarities").click();
|
||||
}
|
||||
|
||||
function create_filter() {
|
||||
let data = {ascending: false};
|
||||
|
||||
let row = make_elem("div", ["row", "filter-row"], {});
|
||||
let col = make_elem("div", ["col"], {});
|
||||
row.appendChild(col);
|
||||
data.div = row;
|
||||
|
||||
let reorder_img = make_elem("img", ["reorder-filter"], {src: "../media/icons/3-lines.svg", draggable: "true"});
|
||||
col.appendChild(reorder_img);
|
||||
|
||||
let filter_input = make_elem("input",
|
||||
["col", "border-dark", "text-light", "dark-5", "rounded", "scaled-font", "form-control", "form-control-sm", "filter-input"],
|
||||
{id: "filter-input-" + filter_id_counter, type: "text", placeholder: "Filter"}
|
||||
);
|
||||
filter_id_counter++;
|
||||
col.appendChild(filter_input);
|
||||
data.input_elem = filter_input;
|
||||
|
||||
let asc_desc = make_elem("div", [], {style: "cursor: pointer; display: inline-block;"});
|
||||
asc_desc.appendChild(make_elem("img", ["desc-icon", "asc-sel"], {src: "../media/icons/triangle.svg"}));
|
||||
asc_desc.appendChild(make_elem("img", ["asc-icon"], {src: "../media/icons/triangle.svg"}));
|
||||
asc_desc.addEventListener("click", function() {
|
||||
data.ascending = !data.ascending;
|
||||
asc_desc.children[0].classList.toggle("asc-sel");
|
||||
asc_desc.children[1].classList.toggle("asc-sel");
|
||||
});
|
||||
col.appendChild(asc_desc);
|
||||
|
||||
let min = make_elem("input",
|
||||
["col", "border-dark", "text-light", "dark-5", "rounded", "scaled-font", "form-control", "form-control-sm", "min-max-input"],
|
||||
{type: "number", placeholder: "-\u221E"}
|
||||
);
|
||||
col.appendChild(min);
|
||||
data.min_elem = min;
|
||||
|
||||
let to = make_elem("span", [], {innerHTML: " to "});
|
||||
col.appendChild(to);
|
||||
|
||||
let max = make_elem("input",
|
||||
["col", "border-dark", "text-light", "dark-5", "rounded", "scaled-font", "form-control", "form-control-sm", "min-max-input"],
|
||||
{type: "number", placeholder: "\u221E"}
|
||||
);
|
||||
col.appendChild(max);
|
||||
data.max_elem = max;
|
||||
|
||||
let trash = make_elem("img", ["delete-filter"], {src: "../media/icons/trash.svg"});
|
||||
trash.addEventListener("click", function() {
|
||||
filters.splice(Array.from(row.parentElement.children).indexOf(row) - 1, 1);
|
||||
row.remove();
|
||||
});
|
||||
col.appendChild(trash);
|
||||
|
||||
document.getElementById("filter-container").insertBefore(row, document.getElementById("add-filter").parentElement);
|
||||
filters.push(data);
|
||||
init_filter_dropdown(data);
|
||||
}
|
||||
|
||||
let currently_dragging = null;
|
||||
function init_filter_drag() {
|
||||
let container = document.getElementById("filter-container");
|
||||
|
||||
container.addEventListener("dragstart", function(e) {
|
||||
if (e.path[0].classList.contains("reorder-filter")) {
|
||||
currently_dragging = filters[Array.from(e.path[3].children).indexOf(e.path[2]) - 1];
|
||||
} else {
|
||||
e.preventDefault();
|
||||
}
|
||||
});
|
||||
|
||||
container.addEventListener("dragenter", function(e) {
|
||||
e.preventDefault();
|
||||
});
|
||||
|
||||
container.addEventListener("dragleave", function(e) {
|
||||
e.preventDefault();
|
||||
});
|
||||
|
||||
container.addEventListener("dragend", function(e) {
|
||||
e.preventDefault();
|
||||
for (const el of document.getElementsByClassName("filter-dragged-over")) {
|
||||
el.classList.remove("filter-dragged-over");
|
||||
}
|
||||
currently_dragging = null;
|
||||
});
|
||||
|
||||
container.addEventListener("dragover", function(e) {
|
||||
e.preventDefault();
|
||||
for (const el of document.getElementsByClassName("filter-dragged-over")) {
|
||||
el.classList.remove("filter-dragged-over");
|
||||
}
|
||||
if (!e.path.includes(currently_dragging.div)) {
|
||||
for (let i = 0; i < e.path.length; i++) {
|
||||
if (e.path[i].classList.contains("filter-row")) {
|
||||
e.path[i].classList.add("filter-dragged-over");
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
container.addEventListener("drop", function(e) {
|
||||
e.preventDefault();
|
||||
for (const el of document.getElementsByClassName("filter-dragged-over")) {
|
||||
el.classList.remove("filter-dragged-over");
|
||||
}
|
||||
if (!e.path.includes(currently_dragging.div)) {
|
||||
for (let i = 0; i < e.path.length; i++) {
|
||||
if (e.path[i].classList.contains("filter-row")) {
|
||||
let old_index = filters.indexOf(currently_dragging);
|
||||
let new_index = Array.from(e.path[i + 1].children).indexOf(e.path[i]) - 1;
|
||||
filters.splice(old_index, 1);
|
||||
filters.splice(new_index, 0, currently_dragging);
|
||||
currently_dragging.div.remove();
|
||||
container.insertBefore(currently_dragging.div, container.children[new_index + 1]);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
currently_dragging = null;
|
||||
});
|
||||
}
|
||||
|
||||
function create_exclude() {
|
||||
let data = {};
|
||||
|
||||
let row = make_elem("div", ["row", "filter-row"], {});
|
||||
let col = make_elem("div", ["col"], {});
|
||||
row.appendChild(col);
|
||||
data.div = row;
|
||||
|
||||
let filter_input = make_elem("input",
|
||||
["col", "border-dark", "text-light", "dark-5", "rounded", "scaled-font", "form-control", "form-control-sm", "filter-input"],
|
||||
{id: "filter-input-" + filter_id_counter, type: "text", placeholder: "Excluded Filter"}
|
||||
);
|
||||
filter_id_counter++;
|
||||
col.appendChild(filter_input);
|
||||
data.input_elem = filter_input;
|
||||
|
||||
let trash = make_elem("img", ["delete-filter"], {src: "../media/icons/trash.svg"});
|
||||
trash.addEventListener("click", function() {
|
||||
excludes.splice(Array.from(row.parentElement.children).indexOf(row) - 1, 1);
|
||||
row.remove();
|
||||
});
|
||||
col.appendChild(trash);
|
||||
|
||||
document.getElementById("exclude-container").insertBefore(row, document.getElementById("add-exclude").parentElement);
|
||||
excludes.push(data);
|
||||
init_filter_dropdown(data);
|
||||
}
|
||||
|
||||
function init_filter_dropdown(filter) {
|
||||
let field_choice = filter.input_elem;
|
||||
field_choice.onclick = function() {field_choice.dispatchEvent(new Event('input', {bubbles:true}));};
|
||||
filter.autoComplete = new autoComplete({
|
||||
data: {
|
||||
src: item_filters,
|
||||
},
|
||||
threshold: 0,
|
||||
selector: "#" + field_choice.id,
|
||||
wrapper: false,
|
||||
resultsList: {
|
||||
maxResults: 100,
|
||||
tabSelect: true,
|
||||
noResults: true,
|
||||
class: "search-box dark-7 rounded-bottom px-2 fw-bold dark-shadow-sm",
|
||||
element: (list, data) => {
|
||||
let position = field_choice.getBoundingClientRect();
|
||||
list.style.top = position.bottom + window.scrollY +"px";
|
||||
list.style.left = position.x+"px";
|
||||
list.style.width = position.width+"px";
|
||||
list.style.maxHeight = position.height * 4 +"px";
|
||||
if (!data.results.length) {
|
||||
const message = make_elem('li', ['scaled-font'], {textContent: "No results found!"});
|
||||
list.prepend(message);
|
||||
};
|
||||
},
|
||||
},
|
||||
resultItem: {
|
||||
class: "scaled-font search-item",
|
||||
selected: "dark-5",
|
||||
},
|
||||
events: {
|
||||
input: {
|
||||
selection: (event) => {
|
||||
if (event.detail.selection.value) {
|
||||
event.target.value = event.detail.selection.value;
|
||||
};
|
||||
},
|
||||
},
|
||||
}
|
||||
});
|
||||
expr_parser = new ExprParser(itemQueryProps, queryFuncs);
|
||||
}
|
||||
|
||||
(async function() {
|
||||
await Promise.resolve(load_init());
|
||||
init_items();
|
||||
await Promise.resolve(load_init(), load_major_id_data(wynn_version_names[WYNN_VERSION_LATEST]));
|
||||
init_search();
|
||||
})();
|
||||
|
|
Some files were not shown because too many files have changed in this diff Show more
Loading…
Reference in a new issue