fix merge conflicts

This commit is contained in:
ferricles 2022-07-20 14:53:35 -07:00
commit 99d2b8273a
176 changed files with 13898 additions and 6637 deletions

19
LICENSE.txt Normal file
View file

@ -0,0 +1,19 @@
Copyright (c) 2022 Wynnbuilder team
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.

View file

@ -18,7 +18,7 @@
--> -->
<title>WynnBuilder</title> <title>WynnBuilder</title>
<link rel="icon" href="./media/memes/agony.png"> <link rel="icon" href="../media/icons/new/builder.png" type="image/icon type">
<meta name="viewport" content="width=device-width, initial-scale=.45, user-scalable=no"> <meta name="viewport" content="width=device-width, initial-scale=.45, user-scalable=no">
@ -45,12 +45,15 @@
<a href = "../custom/"><img src = "../media/icons/new/custom.png" alt = "WynnCustom" title = "WynnCustom"><b>WynnCustom</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 = "../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 href = "../wynnfo/"><img src = "../media/icons/new/book.png" alt = "Wynnfo" title = "Wynnfo"><b>Wynnfo</b></a>
<a onclick = "document.querySelector('#search-container').style.display = '';"><img src="../media/icons/new/searcher.png" alt="" title="Item Search"><b>WynnAtlas Mini</b></a>
<a onclick = "toggleIcons()"><img src = "../media/icons/new/reload.png" alt = "" title = "Swap items on page"><b>Swap Icon Style</b></a> <a onclick = "toggleIcons()"><img src = "../media/icons/new/reload.png" alt = "" title = "Swap items on page"><b>Swap Icon Style</b></a>
<hr/> <hr/>
<a href = "https://discord.gg/CGavnAnerv" target = "_blank"><img src = "../media/icons/discord.png" alt = "WB Discord" title = "WB Discord"><b>WB Discord</b></a> <a href = "https://discord.gg/CGavnAnerv" target = "_blank"><img src = "../media/icons/discord.png" alt = "WB Discord" title = "WB Discord"><b>WB Discord</b></a>
</div> </div>
<div class="container-fluid me-4" style="max-width: 95%; display: none"> <div class="container-fluid me-4" style="max-width: 95%; display: none">
<!-- 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>
<div class="row h-100 gx-lg-5 gy-3 mx-2 mx-lg-3 py-3"> <div class="row h-100 gx-lg-5 gy-3 mx-2 mx-lg-3 py-3">
<div class="col-xl-6"> <div class="col-xl-6">
<div class="row row-cols-1 mb-3 gy-4"> <div class="row row-cols-1 mb-3 gy-4">
@ -407,6 +410,8 @@
</div> </div>
<div class="col text-center"> <div class="col text-center">
<div id="summary-box"></div> <div id="summary-box"></div>
<div id="err-box"></div>
<div id="stack-box"></div>
<div id="str-warnings"></div> <div id="str-warnings"></div>
<div id="dex-warnings"></div> <div id="dex-warnings"></div>
<div id="int-warnings"></div> <div id="int-warnings"></div>
@ -428,7 +433,7 @@
</div> </div>
<div class = "col-3 py-2"> <div class = "col-3 py-2">
<button class = "col-auto button rounded scaled-font fw-bold text-light dark-5" id = "toggle-atree" onclick = "toggle_tab('atree-dropdown'); toggleButton('toggle-atree')"> <button class = "col-auto button rounded scaled-font fw-bold text-light dark-5" id = "toggle-atree" onclick = "toggle_tab('atree-dropdown'); toggleButton('toggle-atree')">
Show Ability Tree Edit Abilities
</button> </button>
</div> </div>
<div class = "col-3 py-2"> <div class = "col-3 py-2">
@ -617,10 +622,14 @@
</div> </div>
<div class = "col dark-6 rounded-bottom my-3 my-xl-1" id = "atree-dropdown" style = "display:none;"> <div class = "col dark-6 rounded-bottom my-3 my-xl-1" id = "atree-dropdown" style = "display:none;">
<div class="row row-cols-1 row-cols-xl-2"> <div class="row row-cols-1 row-cols-xl-2">
<div class="col border border-semi-light rounded dark-9 hide-scroll" id="atree-ui" style="height: 500px; overflow-y: auto;"> <div class="col border border-semi-light rounded dark-9 hide-scroll" id="atree-ui" style="height: 90vh; overflow-y: auto; overflow-x: hidden;">
</div> </div>
<div class="col mx-auto" id="atree-active"> <div class="col mx-auto" style="height: 90vh; overflow-y: auto;" id="atree-rhs">
<div class="col mx-auto" style="height: 2em; overflow-y: auto;" id="atree-header">
</div>
<div class="col mx-auto" style="overflow-y: auto;" id="atree-active">
</div>
</div> </div>
</div> </div>
</div> </div>
@ -965,7 +974,12 @@
</div> </div>
<div class="col-auto p-1"> <div class="col-auto p-1">
<button class="button-boost w-100 border-0 text-white dark-8u dark-shadow-sm" id="warscream-boost" onclick="update_boosts('warscream-boost')"> <button class="button-boost w-100 border-0 text-white dark-8u dark-shadow-sm" id="warscream-boost" onclick="update_boosts('warscream-boost')">
War Scream (+10%) War Scream
</button>
</div>
<div class="col-auto p-1">
<button class="button-boost w-100 border-0 text-white dark-8u dark-shadow-sm" id="ragnarokkr-boost" onclick="update_boosts('ragnarokkr-boost')">
Ragnarokkr (+30%)
</button> </button>
</div> </div>
<div class="col-auto p-1"> <div class="col-auto p-1">
@ -979,8 +993,8 @@
</button> </button>
</div> </div>
<div class="col-auto p-1"> <div class="col-auto p-1">
<button class="button-boost w-100 border-0 text-white dark-8u dark-shadow-sm" id="bash-boost" onclick="update_boosts('bash-boost')"> <button class="button-boost w-100 border-0 text-white dark-8u dark-shadow-sm" id="fortitude-boost" onclick="update_boosts('fortitude-boost')">
Bash (+50%) Fortitude (+60%)
</button> </button>
</div> </div>
</div> </div>
@ -1045,11 +1059,6 @@
<div class="col eDam"> <div class="col eDam">
Rage (Passive) Rage (Passive)
</div> </div>
<div class="col">
<input type = "range" class = "e_slider" id = "str_boost_armor" name = "str-boost-armor" autocomplete = "off" min = '0' max = '400' value = '0' step = '1' onchange = "update_armor_powder_specials('str_boost_armor')">
<input type="text" id="str_boost_armor_prev" autocomplete = "off" value="0" style = "display:none;">
<label id = "str_boost_armor_label" for="str-boost-armor">% Earth Dmg Boost: 0</label>
</div>
</div> </div>
</div> </div>
<div class="col" id="dex-boost" style="display: none;"> <div class="col" id="dex-boost" style="display: none;">
@ -1089,11 +1098,6 @@
<div class="col tDam"> <div class="col tDam">
Kill Streak (Passive) Kill Streak (Passive)
</div> </div>
<div class="col">
<input type = "range" class = "t_slider" id = "dex_boost_armor" name = "dex-boost-armor" autocomplete = "off" min = '0' max = '200' value = '0' step = '1' onchange = "update_armor_powder_specials('dex_boost_armor')">
<input type="text" id="dex_boost_armor_prev" autocomplete = "off" value="0" style = "display:none;">
<label id = "dex_boost_armor_label" for="dex-boost-armor">% Thunder Dmg Boost: 0</label>
</div>
</div> </div>
</div> </div>
<div class="col" id="int-boost"> <div class="col" id="int-boost">
@ -1133,11 +1137,6 @@
<div class="col wDam"> <div class="col wDam">
Concentration (Passive) Concentration (Passive)
</div> </div>
<div class="col">
<input type = "range" class = "w_slider" id = "int_boost_armor" name = "dex-boost-armor" autocomplete = "off" min = '0' max = '150' value = '0' step = '1' onchange = "update_armor_powder_specials('int_boost_armor')">
<input type="text" id="int_boost_armor_prev" autocomplete = "off" value="0" style = "display:none;">
<label id = "int_boost_armor_label" for="dex-boost-armor">% Water Dmg Boost: 0</label>
</div>
</div> </div>
</div> </div>
<div class="col" id="def-boost" style="display: none;"> <div class="col" id="def-boost" style="display: none;">
@ -1177,11 +1176,6 @@
<div class="col fDam"> <div class="col fDam">
Endurance (Passive) Endurance (Passive)
</div> </div>
<div class="col">
<input type = "range" class = "f_slider" id = "def_boost_armor" name = "def-boost-armor" autocomplete = "off" min = '0' max = '200' value = '0' step = '1' onchange = "update_armor_powder_specials('def_boost_armor')">
<input type="text" id="def_boost_armor_prev" autocomplete = "off" value="0" style = "display:none;">
<label id = "def_boost_armor_label" for="def-boost-armor">% Fire Dmg Boost: 0</label>
</div>
</div> </div>
</div> </div>
<div class="col" id="agi-boost" style="display: none;"> <div class="col" id="agi-boost" style="display: none;">
@ -1221,11 +1215,6 @@
<div class="col aDam"> <div class="col aDam">
Dodge (Passive) Dodge (Passive)
</div> </div>
<div class="col">
<input type = "range" class = "a_slider" id = "agi_boost_armor" name = "agi-boost-armor" autocomplete = "off" min = '0' max = '150' value = '0' step = '1' onchange = "update_armor_powder_specials('agi_boost_armor')">
<input type="text" id="agi_boost_armor_prev" autocomplete = "off" value="0" style = "display:none;">
<label id = "agi_boost_armor_label" for="agi-boost-armor">% Air Dmg Boost: 0</label>
</div>
</div> </div>
</div> </div>
</div> </div>
@ -1263,21 +1252,10 @@
<div class = "col"> <div class = "col">
<div class = "col spell-display dark-5 rounded dark-shadow py-2 border border-dark" id="build-poison-stats">poison</div> <div class = "col spell-display dark-5 rounded dark-shadow py-2 border border-dark" id="build-poison-stats">poison</div>
</div> </div>
<div class = "col"> <div id="all-spells-display" class="row row-cols-1 gy-3 text-center scaled-font pe-0">
<div class = "col spell-display spell-expand dark-5 rounded dark-shadow pt-2 border border-dark" id="spell0-infoAvg">spell1</div> <div class = "col pe-0">
<div class = "col spell-display dark-5 rounded dark-shadow py-2" id = "spell0-info" style="display: none;">Spell 1</div> <div class = "col spell-display spell-expand dark-5 rounded dark-shadow pt-2 border border-dark" id="spell0-infoAvg">Input a weapon to see abilities!</div>
</div> </div>
<div class = "col">
<div class = "col spell-display spell-expand dark-5 rounded dark-shadow pt-2 border border-dark" id="spell1-infoAvg">spell2</div>
<div class = "col spell-display dark-5 rounded dark-shadow py-2" id = "spell1-info" style="display: none;">Spell 2</div>
</div>
<div class = "col">
<div class = "col spell-display spell-expand dark-5 rounded dark-shadow pt-2 border border-dark" id="spell2-infoAvg">spell3</div>
<div class = "col spell-display dark-5 rounded dark-shadow py-2" id = "spell2-info" style="display: none;">Spell 3</div>
</div>
<div class = "col">
<div class = "col spell-display spell-expand dark-5 rounded dark-shadow pt-2 border border-dark" id="spell3-infoAvg">spell4</div>
<div class = "col spell-display dark-5 rounded dark-shadow py-2" id = "spell3-info" style="display: none;">Spell 4</div>
</div> </div>
<div class = "col"> <div class = "col">
<div class = "spell-display dark-5 rounded dark-shadow py-2 border border-dark" id = "powder-special-stats"></div> <div class = "spell-display dark-5 rounded dark-shadow py-2 border border-dark" id = "powder-special-stats"></div>
@ -1329,11 +1307,11 @@
<div class="col-12 dark-5 scaled-font"> <div class="col-12 dark-5 scaled-font">
<footer class="text-center"> <footer class="text-center">
<div id="header2"> <div id="header2">
<p>Made by <b class = "hppeng">hppeng</b> and <b class = "ferricles">ferricles</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>, 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>Hard refresh the page (Ctrl+Shift+R on windows/chrome) if it isn't updating correctly.</p> <p>Hard refresh the page (Ctrl+Shift+R on windows/chrome) if it isn't updating correctly.</p>
</div> </div>
<div id="credits"> <div id="credits">
<a href="credits.txt" class="link">Additional credits</a> <a href="../credits.txt" class="link">Additional credits</a>
</div> </div>
</footer> </footer>
</div> </div>
@ -1393,7 +1371,6 @@
</div> </div>
</div> </div>
<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/@tarekraafat/autocomplete.js@10.2.6/dist/autoComplete.min.js"></script>
<script src="https://cdn.jsdelivr.net/npm/macy@2"></script> <script src="https://cdn.jsdelivr.net/npm/macy@2"></script>
<script type="text/javascript" src="../js/utils.js"></script> <script type="text/javascript" src="../js/utils.js"></script>
@ -1404,15 +1381,9 @@
<script type="text/javascript" src="../js/powders.js"></script> <script type="text/javascript" src="../js/powders.js"></script>
<script type="text/javascript" src="../js/skillpoints.js"></script> <script type="text/javascript" src="../js/skillpoints.js"></script>
<script type="text/javascript" src="../js/damage_calc.js"></script> <script type="text/javascript" src="../js/damage_calc.js"></script>
<script type="text/javascript" src="../js/atree_constants_min.js"></script> <script type="text/javascript" src="../js/atree_constants_min.js"></script>
<script type="text/javascript" src="../js/display_constants.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/display.js"></script>
<script type="text/javascript" src="../js/query.js"></script>
<script type="text/javascript" src="../js/query_2.js"></script>
<script type="text/javascript" src="../js/load.js"></script> <script type="text/javascript" src="../js/load.js"></script>
<script type="text/javascript" src="../js/load_ing.js"></script> <script type="text/javascript" src="../js/load_ing.js"></script>
<script type="text/javascript" src="../js/load_tome.js"></script> <script type="text/javascript" src="../js/load_tome.js"></script>
@ -1424,9 +1395,6 @@
<script type="text/javascript" src="../js/atree.js"></script> <script type="text/javascript" src="../js/atree.js"></script>
<script type="text/javascript" src="../js/builder.js"></script> <script type="text/javascript" src="../js/builder.js"></script>
<script type="text/javascript" src="../js/builder_graph.js"></script> <script type="text/javascript" src="../js/builder_graph.js"></script>
<script type="text/javascript" src="../js/expr_parser.js"></script>
<script type="text/javascript" src="../js/items.js"></script>
<script type="text/javascript" src="../js/sq2items.js"></script>
<script type="text/javascript" src="../js/optimize.js"></script> <script type="text/javascript" src="../js/optimize.js"></script>
<div id="graph_body" style="max-width: 100%; height: 100vh"> <div id="graph_body" style="max-width: 100%; height: 100vh">
@ -1434,6 +1402,7 @@
<a id="saveLink">savelink</a> <a id="saveLink">savelink</a>
</div> </div>
<script src="https://d3js.org/d3.v7.js"></script> <script src="https://d3js.org/d3.v7.js"></script>
<script type="text/javascript" src="../js/render_compute_graph.js"></script> <script type="text/javascript" src="../js/debug/render_compute_graph.js"></script>
</body> </body>
</html> </html>

File diff suppressed because one or more lines are too long

1279
builder/index_full.html Normal file

File diff suppressed because it is too large Load diff

4293
clean.json

File diff suppressed because it is too large Load diff

File diff suppressed because one or more lines are too long

View file

@ -31,265 +31,252 @@
<hr/> <hr/>
<a href = "https://discord.gg/CGavnAnerv" target = "_blank"><img src = "../media/icons/discord.png" alt = "WB Discord" title = "WB Discord"><b>WB Discord</b></a> <a href = "https://discord.gg/CGavnAnerv" target = "_blank"><img src = "../media/icons/discord.png" alt = "WB Discord" title = "WB Discord"><b>WB Discord</b></a>
</div> </div>
<div class = "container py-5 vh-100 mx-0 mx-lg-auto"> <div class="container mt-5">
<div class = "col"> <div class="row row-cols-1 row-cols-lg-3 gy-5">
<div class = "row g-3"> <div class="col col-lg-5">
<div class = "col-lg-5 col-sm-12 text-center"> <!--crafter ui-->
<div class = "row gx-5 mb-2"> <div class="row row-cols-1 row-cols-lg-2 gx-5 gy-4 gy-lg-2">
<div class = "col-lg-6 col-sm-12"> <div class="col" id="recipe-dropdown">
<div id = "recipe-dropdown" class = "row h-100 dark-shadow dark-6 rounded"> <div class="row dark-shadow dark-5 rounded">
<div id = "recipe-img-loc" class = "col-auto px-lg-1 g-0 dark-7 rounded-end my-auto text-center scaled-item-icon"> <div id = "recipe-img-loc" class = "col-auto px-lg-1 g-0 dark-7 rounded-end my-auto text-center scaled-item-icon">
<img id = "recipe-img" class = "img-fluid rounded Crafted-shadow" src = "../media/items/new/generic-potion.png"> <img id = "recipe-img" class = "img-fluid rounded Crafted-shadow" src = "../media/items/new/generic-potion.png">
</div>
<div class = "col px-0">
<div class = "row align-items-center">
<div class = "col-4 px-0">
<p class = "text-right mb-0 scaled-font fw-bold">Type:</p>
</div>
<div class = "col-7 px-0">
<input class="recipeinput border-dark text-light dark-10 rounded scaled-font form-control form-control-sm" list="recipe-choices" id="recipe-choice" name="recipe-choice" placeholder="Potion"/>
<datalist id="recipe-choices">
</datalist>
</div>
</div>
<div class = "row align-items-center">
<div class = "col-4 px-0">
<p class = "text-right mb-0 scaled-font fw-bold">Lv:</p>
</div>
<div class = "col-7 px-0">
<input class="levelinput border-dark text-light dark-10 rounded scaled-font form-control form-control-sm" list="level-choices" id="level-choice" name="level-choice" placeholder="103-105" />
<datalist id="level-choices">
</datalist>
</div>
</div>
</div>
</div> </div>
</div> <div class = "col ps-3">
<div class = "col-lg-6 col-sm-12"> <div class = "row row-cols-2 align-items-center">
<div id = "atkSpdChoices" class = "row h-100 dark-shadow dark-6 rounded"> <div class = "col-4 px-0">
<div class = "col py-2"> <p class = "mb-0 scaled-font fw-bold">Type:</p>
<div class = "row h-50 align-items-center">
<p class = "text-right mb-0 scaled-font fw-bold">Attack Speed</p>
</div> </div>
<div class = "row h-50"> <div class = "col-8 px-0">
<div class = "col-4 pl-1"> <input class="recipeinput border-dark text-light dark-10 rounded scaled-font form-control form-control-sm" list="recipe-choices" id="recipe-choice" name="recipe-choice" placeholder="Potion"/>
<button class = "button rounded scaled-font fw-bold text-light dark-5" id = "slow-atk-button" onclick = "toggleAtkSpd('slow-atk-button')"> <datalist id="recipe-choices">
Slow </datalist>
</button> </div>
</div> <div class = "col-4 px-0">
<div class = "col-4 px-0"> <p class = "mb-0 scaled-font fw-bold">Lv:</p>
<button class = "button rounded scaled-font fw-bold text-light dark-5" id = "normal-atk-button" onclick = "toggleAtkSpd('normal-atk-button')"> </div>
Normal <div class = "col-8 px-0">
</button> <input class="levelinput border-dark text-light dark-10 rounded scaled-font form-control form-control-sm" list="level-choices" id="level-choice" name="level-choice" placeholder="103-105" />
</div> <datalist id="level-choices">
<div class = "col-4 pr-1"> </datalist>
<button class = "button rounded scaled-font fw-bold text-light dark-5" id = "fast-atk-button" onclick = "toggleAtkSpd('fast-atk-button')">
Fast
</button>
</div>
</div> </div>
</div> </div>
</div> </div>
</div> </div>
</div> </div>
<div class = "row gx-5 mb-2"> <div class="col">
<div class = "col-lg-6 col-sm-12 justify-content-center"> <div id = "atkSpdChoices" class = "row row-cols-1 dark-shadow dark-5 rounded">
<div class = "row dark-shadow dark-6 rounded py-1 align-items-center"> <div class="col pt-1">
<div class = "col-6 px-0"> <p class = "text-center scaled-font fw-bold mb-1">Attack Speed</p>
<p class = "mb-0 scaled-font fw-bold" id = "mat-1">Mat 1 Tier:</p>
</div>
<div class = "col px-0">
<button class = "button Star rounded scaled-font fw-bold text-light dark-5" id = "mat-1-1" onclick = "toggleMaterial('mat-1-1')">1</button>
</div>
<div class = "col px-0">
<button class = "button Star rounded scaled-font fw-bold text-light dark-5" id = "mat-1-2" onclick = "toggleMaterial('mat-1-2')">2</button>
</div>
<div class = "col px-0">
<button class = "button Star rounded scaled-font fw-bold text-light dark-5" id = "mat-1-3" onclick = "toggleMaterial('mat-1-3')">3</button>
</div>
</div>
</div>
<div class = "col-lg-6 col-sm-12 justify-content-center">
<div class = "row dark-shadow dark-6 rounded py-1 align-items-center">
<div class = "col-6 px-0">
<p class = "mb-0 scaled-font fw-bold" id = "mat-2">Mat 2 Tier:</p>
</div>
<div class = "col px-0">
<button class = "button Star rounded scaled-font fw-bold text-light dark-5" id = "mat-2-1" onclick = "toggleMaterial('mat-2-1')">1</button>
</div>
<div class = "col px-0">
<button class = "button Star rounded scaled-font fw-bold text-light dark-5" id = "mat-2-2" onclick = "toggleMaterial('mat-2-2')">2</button>
</div>
<div class = "col px-0">
<button class = "button Star rounded scaled-font fw-bold text-light dark-5" id = "mat-2-3" onclick = "toggleMaterial('mat-2-3')">3</button>
</div>
</div>
</div>
</div>
<div class = "row gx-5 mb-1">
<div class = "col">
<div class = "row h-100 dark-shadow dark-6 rounded align-items-center">
<div class = "col-3 px-0">
<p class = "mb-0 scaled-font fw-bold">Ing 1:</p>
</div>
<div class = "col-9 px-0">
<input class="inginput border-dark text-light dark-10 rounded scaled-font form-control form-control-sm" list="ing-choices-1" id="ing-choice-1" name="ing-choice-1" placeholder="No Ingredient" />
<datalist id="ing-choices-1">
</datalist>
</div>
</div> </div>
</div> <div class="col mb-2">
<div class = "col"> <div class="row justify-content-center">
<div class = "row h-100 dark-shadow dark-6 rounded align-items-center"> <div class="col-auto px-2">
<div class = "col-3 px-0"> <button class = "button rounded scaled-font fw-bold text-light dark-5" id = "slow-atk-button" onclick = "toggleAtkSpd('slow-atk-button')">
<p class = "mb-0 scaled-font fw-bold">Ing 2:</p> Slow
</button>
</div>
<div class="col-auto px-2">
<button class = "button rounded scaled-font fw-bold text-light dark-5" id = "normal-atk-button" onclick = "toggleAtkSpd('normal-atk-button')">
Normal
</button>
</div>
<div class="col-auto px-2">
<button class = "button rounded scaled-font fw-bold text-light dark-5" id = "fast-atk-button" onclick = "toggleAtkSpd('fast-atk-button')">
Fast
</button>
</div>
</div> </div>
<div class = "col-9 px-0">
<input class="inginput border-dark text-light dark-10 rounded scaled-font form-control form-control-sm" list="ing-choices-2" id="ing-choice-2" name="ing-choice-2" placeholder="No Ingredient" />
<datalist id="ing-choices-2">
</datalist>
</div>
</div> </div>
</div> </div>
</div> </div>
<div class = "row gx-5 mb-1"> <div class="col">
<div class = "col"> <div class = "row dark-shadow dark-6 rounded py-1 align-items-center">
<div class = "row h-100 dark-shadow dark-6 rounded align-items-center"> <div class = "col-6 px-0">
<div class = "col-3 px-0"> <p class = "mb-0 scaled-font fw-bold text-center" id = "mat-1">Mat 1 Tier:</p>
<p class = "mb-0 scaled-font fw-bold">Ing 3:</p>
</div>
<div class = "col-9 px-0">
<input class="inginput border-dark text-light dark-10 rounded scaled-font form-control form-control-sm" list="ing-choices-3" id="ing-choice-3" name="ing-choice-3" placeholder="No Ingredient" />
<datalist id="ing-choices-3">
</datalist>
</div>
</div> </div>
</div> <div class = "col px-0">
<div class = "col"> <button class = "button Star rounded scaled-font fw-bold text-light dark-5" id = "mat-1-1" onclick = "toggleMaterial('mat-1-1')">1</button>
<div class = "row h-100 dark-shadow dark-6 rounded align-items-center">
<div class = "col-3 px-0">
<p class = "mb-0 scaled-font fw-bold">Ing 4:</p>
</div>
<div class = "col-9 px-0">
<input class="inginput border-dark text-light dark-10 rounded scaled-font form-control form-control-sm" list="ing-choices-4" id="ing-choice-4" name="ing-choice-4" placeholder="No Ingredient" />
<datalist id="ing-choices-4">
</datalist>
</div>
</div> </div>
</div> <div class = "col px-0">
</div> <button class = "button Star rounded scaled-font fw-bold text-light dark-5" id = "mat-1-2" onclick = "toggleMaterial('mat-1-2')">2</button>
<div class = "row gx-5 mb-1">
<div class = "col">
<div class = "row h-100 dark-shadow dark-6 rounded align-items-center">
<div class = "col-3 px-0">
<p class = "mb-0 scaled-font fw-bold">Ing 5:</p>
</div>
<div class = "col-9 px-0">
<input class="inginput border-dark text-light dark-10 rounded scaled-font form-control form-control-sm" list="ing-choices-5" id="ing-choice-5" name="ing-choice-5" placeholder="No Ingredient" />
<datalist id="ing-choices-5">
</datalist>
</div>
</div> </div>
</div> <div class = "col px-0">
<div class = "col"> <button class = "button Star rounded scaled-font fw-bold text-light dark-5" id = "mat-1-3" onclick = "toggleMaterial('mat-1-3')">3</button>
<div class = "row h-100 dark-shadow dark-6 rounded align-items-center">
<div class = "col-3 px-0">
<p class = "mb-0 scaled-font fw-bold">Ing 6:</p>
</div>
<div class = "col-9 px-0">
<input class="inginput border-dark text-light dark-10 rounded scaled-font form-control form-control-sm" list="ing-choices-6" id="ing-choice-6" name="ing-choice-6" placeholder="No Ingredient" />
<datalist id="ing-choices-6">
</datalist>
</div>
</div> </div>
</div>
</div>
<div class="col">
<div class = "row dark-shadow dark-6 rounded py-1 align-items-center">
<div class = "col-6 px-0">
<p class = "mb-0 scaled-font fw-bold text-center" id = "mat-2">Mat 2 Tier:</p>
</div>
<div class = "col px-0">
<button class = "button Star rounded scaled-font fw-bold text-light dark-5" id = "mat-2-1" onclick = "toggleMaterial('mat-2-1')">1</button>
</div>
<div class = "col px-0">
<button class = "button Star rounded scaled-font fw-bold text-light dark-5" id = "mat-2-2" onclick = "toggleMaterial('mat-2-2')">2</button>
</div>
<div class = "col px-0">
<button class = "button Star rounded scaled-font fw-bold text-light dark-5" id = "mat-2-3" onclick = "toggleMaterial('mat-2-3')">3</button>
</div>
</div>
</div>
<div class="col">
<div class = "row dark-shadow dark-6 rounded align-items-center just">
<div class = "col-3 px-0 ps-2">
<p class = "mb-0 scaled-font fw-bold">Ing 1:</p>
</div>
<div class = "col-9 px-0">
<input class="inginput border-dark text-light dark-10 rounded scaled-font form-control form-control-sm" list="ing-choices-1" id="ing-choice-1" name="ing-choice-1" placeholder="No Ingredient" />
<datalist id="ing-choices-1">
</datalist>
</div>
</div> </div>
</div> </div>
<div class="col">
<div class = "row rounded dark-shadow dark-6 py-2 gy-3"> <div class = "row dark-shadow dark-6 rounded align-items-center">
<div class = "col-lg-2 col-sm-6"> <div class = "col-3 px-0 ps-2">
<button class = "button rounded scaled-font fw-bold text-light dark-5" id = "reset-button" onclick = "resetFields()"> <p class = "mb-0 scaled-font fw-bold">Ing 2:</p>
Reset </div>
</button> <div class = "col-9 px-0">
<input class="inginput border-dark text-light dark-10 rounded scaled-font form-control form-control-sm" list="ing-choices-2" id="ing-choice-2" name="ing-choice-2" placeholder="No Ingredient" />
<datalist id="ing-choices-2">
</datalist>
</div>
</div> </div>
<div class = "col-lg-3 col-sm-6"> </div>
<button class = "button rounded scaled-font fw-bold text-light dark-5" id = "copy-hash-button" onclick = "copyRecipeHash()"> <div class="col">
Copy Hash <div class = "row dark-shadow dark-6 rounded align-items-center">
</button> <div class = "col-3 px-0 ps-2">
<p class = "mb-0 scaled-font fw-bold">Ing 3:</p>
</div>
<div class = "col-9 px-0">
<input class="inginput border-dark text-light dark-10 rounded scaled-font form-control form-control-sm" list="ing-choices-3" id="ing-choice-3" name="ing-choice-3" placeholder="No Ingredient" />
<datalist id="ing-choices-3">
</datalist>
</div>
</div> </div>
<div class = "col-lg-4 col-sm-6"> </div>
<button class = "button rounded scaled-font fw-bold text-light dark-5" id = "copy-button" onclick = "copyRecipe()"> <div class="col">
Copy Short <div class = "row dark-shadow dark-6 rounded align-items-center">
</button> <div class = "col-3 px-0 ps-2">
<p class = "mb-0 scaled-font fw-bold">Ing 4:</p>
</div>
<div class = "col-9 px-0">
<input class="inginput border-dark text-light dark-10 rounded scaled-font form-control form-control-sm" list="ing-choices-4" id="ing-choice-4" name="ing-choice-4" placeholder="No Ingredient" />
<datalist id="ing-choices-4">
</datalist>
</div>
</div> </div>
<div class = "col-lg-3 col-sm-6"> </div>
<button class = "button rounded scaled-font fw-bold text-light dark-5" id = "share-button" onclick = "shareRecipe()"> <div class="col">
Copy Long <div class = "row dark-shadow dark-6 rounded align-items-center">
</button> <div class = "col-3 px-0 ps-2">
<p class = "mb-0 scaled-font fw-bold">Ing 5:</p>
</div>
<div class = "col-9 px-0">
<input class="inginput border-dark text-light dark-10 rounded scaled-font form-control form-control-sm" list="ing-choices-5" id="ing-choice-5" name="ing-choice-5" placeholder="No Ingredient" />
<datalist id="ing-choices-5">
</datalist>
</div>
</div>
</div>
<div class="col">
<div class = "row dark-shadow dark-6 rounded align-items-center">
<div class = "col-3 px-0 ps-2">
<p class = "mb-0 scaled-font fw-bold">Ing 6:</p>
</div>
<div class = "col-9 px-0">
<input class="inginput border-dark text-light dark-10 rounded scaled-font form-control form-control-sm" list="ing-choices-6" id="ing-choice-6" name="ing-choice-6" placeholder="No Ingredient" />
<datalist id="ing-choices-6">
</datalist>
</div>
</div> </div>
</div> </div>
</div> </div>
<div class = "col-lg-4"> <div class = "row rounded dark-shadow dark-6 mt-3 p-2 align-items-center justify-content-center">
<div class = "recipe hide-container-block px-3 col rounded dark-6 text-light scaled-font p-3 border-dark dark-shadow g-0" style = "display:none"> <div class = "col-auto mx-auto">
<div class = "row recipe-stats"> <button class = "button rounded scaled-font fw-bold text-light dark-5" id = "reset-button" onclick = "resetFields()">
<div class = "col" id = "recipe-stats"></div> Reset
</div> </button>
<div class = "row craft-warnings"> </div>
<div class = "" id = "craft-warnings"></div> <div class = "col-auto mx-auto">
</div> <button class = "button rounded scaled-font fw-bold text-light dark-5" id = "copy-hash-button" onclick = "copyRecipeHash()">
Copy Hash
</button>
</div>
<div class = "col-auto mx-auto">
<button class = "button rounded scaled-font fw-bold text-light dark-5" id = "copy-button" onclick = "copyRecipe()">
Copy Short
</button>
</div>
<div class = "col-auto mx-auto">
<button class = "button rounded scaled-font fw-bold text-light dark-5" id = "share-button" onclick = "shareRecipe()">
Copy Long
</button>
</div> </div>
</div> </div>
<div class = "col-lg-3"> </div>
<div class = "crafted row hide-container-block" style = "display:none"> <div class="col col-lg-4">
<div class = "craft-stats"> <div class = "recipe hide-container-block px-3 col rounded dark-6 text-light scaled-font p-3 border-dark dark-shadow g-0" style = "display:none">
<div class = "col rounded dark-6 text-light scaled-font p-3 border-dark dark-shadow g-0" id = "craft-stats"></div> <div class = "row row-cols-1 recipe-stats " id = "recipe-stats">
</div> </div>
<div class = "row craft-warnings">
<div class = "" id = "craft-warnings"></div>
</div> </div>
</div> </div>
</div> </div>
</div> <div class="col col-lg-3">
<div class="col ingredients-container hide-container-grid" id = "ingreds" style = "display:none"> <div class = "crafted row hide-container-block" style = "display:none">
<div class = "col-lg-6 col-sm-12 hide-container-grid" id = "ingreds"> <div class = "craft-stats">
<div class = "row mb-3"> <div class = "col rounded dark-6 text-light scaled-font p-3 border-dark dark-shadow g-0" id = "craft-stats"></div>
<p class="box-title hide-container-block">
Ingredients
</p>
</div>
<div class = "row mb-3">
<div class="ing-stats col-lg-6 col-sm scaled-font" id = "ing-1">
<div class = "rounded col g-0 dark-6 border border-3 border-dark dark-shadow p-3" id = "ing-1-stats"></div>
</div>
<div class="ing-stats col-lg-6 col-sm scaled-font" id = "ing-2">
<div class = "rounded col g-0 dark-6 border border-3 border-dark dark-shadow p-3" id = "ing-2-stats"></div>
</div> </div>
</div> </div>
<div class = "row mb-3">
<div class="ing-stats col-lg-6 col-sm scaled-font" id = "ing-3">
<div class = "rounded col g-0 dark-6 border border-3 border-dark dark-shadow p-3" id = "ing-3-stats"></div>
</div>
<div class="ing-stats col-lg-6 col-sm scaled-font" id = "ing-4">
<div class = "rounded col g-0 dark-6 border border-3 border-dark dark-shadow p-3" id = "ing-4-stats"></div>
</div>
</div>
<div class = "row mb-3">
<div class="ing-stats col-lg-6 col-sm scaled-font" id = "ing-5">
<div class = "rounded col g-0 dark-6 border border-3 border-dark dark-shadow p-3" id = "ing-5-stats"></div>
</div>
<div class="ing-stats col-lg-6 col-sm scaled-font" id = "ing-6">
<div class = "rounded col g-0 dark-6 border border-3 border-dark dark-shadow p-3" id = "ing-6-stats"></div>
</div>
</div>
</div> </div>
</div> </div>
<div class="col dark-5 scaled-font"> <div class="row my-3">
<footer class="text-center"> <div class="col col-lg-6 ingredients-container hide-container-grid" id = "ingreds" style = "display:none">
<div id="header2"> <div class = "row mb-3">
<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> <div class="col">
<p>Hard refresh the page (Ctrl+Shift+R on windows/chrome) if it isn't updating correctly.</p> <p class="box-title hide-container-block">
Ingredients
</p>
</div>
</div> </div>
<div id="credits"> <div class="row row-cols-1 row-cols-lg-2 g-3">
<a href="credits.txt" class="link">Additional credits</a> <div class="ing-stats col-lg-6 col scaled-font" id = "ing-1">
<div class = "rounded g-0 dark-6 border border-3 border-dark dark-shadow p-3" id = "ing-1-stats"></div>
</div>
<div class="ing-stats col-lg-6 col scaled-font" id = "ing-2">
<div class = "rounded g-0 dark-6 border border-3 border-dark dark-shadow p-3" id = "ing-2-stats"></div>
</div>
<div class="ing-stats col-lg-6 col scaled-font" id = "ing-3">
<div class = "rounded g-0 dark-6 border border-3 border-dark dark-shadow p-3" id = "ing-3-stats"></div>
</div>
<div class="ing-stats col-lg-6 col scaled-font" id = "ing-4">
<div class = "rounded g-0 dark-6 border border-3 border-dark dark-shadow p-3" id = "ing-4-stats"></div>
</div>
<div class="ing-stats col-lg-6 col scaled-font" id = "ing-5">
<div class = "rounded g-0 dark-6 border border-3 border-dark dark-shadow p-3" id = "ing-5-stats"></div>
</div>
<div class="ing-stats col-lg-6 col scaled-font" id = "ing-6">
<div class = "rounded g-0 dark-6 border border-3 border-dark dark-shadow p-3" id = "ing-6-stats"></div>
</div>
</div> </div>
</footer> </div>
</div>
<div class="row my-2">
<div class="col 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>Hard refresh the page (Ctrl+Shift+R on windows/chrome) if it isn't updating correctly.</p>
</div>
<div id="credits">
<a href="../credits.txt" class="link">Additional credits</a>
</div>
</footer>
</div>
</div> </div>
</div> </div>
<script type="text/javascript" src="../js/query.js"></script> <script type="text/javascript" src="../js/query.js"></script>
@ -307,7 +294,5 @@
<script type="text/javascript" src="../js/craft.js"></script> <script type="text/javascript" src="../js/craft.js"></script>
<script type="text/javascript" src="../js/crafter.js"></script> <script type="text/javascript" src="../js/crafter.js"></script>
<script type="text/javascript" src="../js/expr_parser.js"></script> <script type="text/javascript" src="../js/expr_parser.js"></script>
<script type="text/javascript" src="../js/items.js"></script>
<!-- <script type="text/javascript" src="../js/sq2items.js"></script> -->
</body> </body>
</html> </html>

View file

@ -7,14 +7,16 @@ The game, of course
Additional Contributors, in no particular order: Additional Contributors, in no particular order:
- Kiocifer (Icons!) - Kiocifer (Icons!)
- IncinerateMe (helping transition to 1.20.3 / CI helper) - IncinerateMe (helping transition to 1.20.3 / atree / CI helper)
- puppy (wynn2 ability tree help) - puppy (dog)
- SockMower (ability tree encode/decode optimization) - SockMower (ability tree encode/decode optimization)
- ITechnically (coding emotional support / misc) - ITechnically (coding emotional support / misc)
- touhoku (best IM) - touhoku (best IM)
- HeyZeer0 (huge help in getting our damage formulas right) - HeyZeer0 (huge help in getting our damage formulas right)
- blankman (fin444 github) (beautifying atree visuals)
- lemonalade (ability tree pdf for us to copy from :) )
- Lennon (Skill point formula reversing) - Lennon (Skill point formula reversing)
- Phanta (WynnAtlas custom expression parser / item search) - Phanta (WynnAtlas custom expression parser / item search)
- nbcss (Crafted Item mechanics reverse engineering) - nbcss (and WIM team) (Crafted Item mechanics reverse engineering, testing)
- dr_carlos (Hiding UI elements properly, fade animations, proper error handling) - dr_carlos (Hiding UI elements properly, fade animations, proper error handling)
- Atlas Inc discord (feedback, ideas, damage calc, etc) - Atlas Inc discord (feedback, ideas, damage calc, etc)

View file

@ -8,7 +8,7 @@
/* builder containers */ /* builder containers */
.e_slider, .t_slider, .w_slider, .f_slider, .a_slider { .slider {
-webkit-appearance: none; -webkit-appearance: none;
background: #AAAAAA; background: #AAAAAA;
border-radius: 30px; border-radius: 30px;
@ -16,15 +16,14 @@
} }
/***** Chrome, Safari, Opera, and Edge Chromium *****/ /***** Chrome, Safari, Opera, and Edge Chromium *****/
.e_slider::-webkit-slider-runnable-track, .t_slider::-webkit-slider-runnable-track, .w_slider::-webkit-slider-runnable-track, .f_slider::-webkit-slider-runnable-track, .a_slider::-webkit-slider-runnable-track { .slider::-webkit-slider-runnable-track{
-webkit-appeareance: none; -webkit-appeareance: none;
background:transparent; background:transparent;
height: 0.5rem; height: 0.5rem;
} }
/******** Firefox **** **/ /******** Firefox **** **/
.e_slider::-moz-range-track, .t_slider::-moz-range-track, .w_slider::-moz-range-track, .f_slider::-moz-range-track, .a_slider::-moz-range-track { .slider::-moz-range-track {
-webkit-appearance: none; -webkit-appearance: none;
background-color: transparent; background-color: transparent;
border-radius: 30px; border-radius: 30px;
@ -32,7 +31,7 @@
} }
.e_slider::-webkit-slider-thumb, .t_slider::-webkit-slider-thumb, .w_slider::-webkit-slider-thumb, .f_slider::-webkit-slider-thumb, .a_slider::-webkit-slider-thumb { .slider::-webkit-slider-thumb {
-webkit-appearance: none; -webkit-appearance: none;
appearance: none; appearance: none;
height: 0.75rem; height: 0.75rem;
@ -133,10 +132,6 @@ input.equipment-input {
font-weight: bold; font-weight: bold;
} }
.spell-expand {
cursor: pointer;
}
:root { :root {
--scaled-fontsize: 2.5rem; --scaled-fontsize: 2.5rem;
} }
@ -449,36 +444,6 @@ a:hover {
border-color: #fff; border-color: #fff;
} }
/* atree connector rotations */
.rotate-90 {
-webkit-transform: rotate(90deg);
-moz-transform: rotate(90deg);
-ms-transform: rotate(90deg);
-o-transform: rotate(90deg);
transform: rotate(90deg);
}
.rotate-180 {
-webkit-transform: rotate(180deg);
-moz-transform: rotate(180deg);
-ms-transform: rotate(180deg);
-o-transform: rotate(180deg);
transform: rotate(180deg);
}
.rotate-270 {
-webkit-transform: rotate(270deg);
-moz-transform: rotate(270deg);
-ms-transform: rotate(270deg);
-o-transform: rotate(270deg);
transform: rotate(270deg);
}
.rotate-flip {
-webkit-transform: scaleX(-1);
transform: scaleX(-1);
}
.hide-scroll { .hide-scroll {
@ -489,19 +454,9 @@ a:hover {
display: none; /* Safari and Chrome */ display: none; /* Safari and Chrome */
} }
.atree-selected {
outline: 5px solid rgba(95, 214, 223, 0.8);
}
.atree-circle {
border-radius:50%;
-moz-border-radius:50%;
-webkit-border-radius:50%;
}
.hppeng{ .hppeng{
color: #20c2b6; color: #20c2b6;
} }
.ferricles{ .ferricles{
color: #5be553; color: #5be553;
} }

View file

@ -181,4 +181,23 @@ Wynn-Related CSS
.restrict { .restrict {
color: #ff8180; color: #ff8180;
} }
/* Every text color in Minecraft */
.mc-black { color: #000000 !important; }
.mc-dark-blue { color: #0000AA !important; }
.mc-dark-green { color: #00AA00 !important; }
.mc-dark-aqua { color: #00AAAA !important; }
.mc-dark-red { color: #AA0000 !important; }
.mc-dark-purple { color: #AA00AA !important; }
.mc-gold { color: #FFAA00 !important; }
.mc-gray { color: #AAAAAA !important; }
.mc-dark-gray { color: #555555 !important; }
.mc-blue { color: #5555FF !important; }
.mc-green { color: #55FF55 !important; }
.mc-aqua { color: #55FFFF !important; }
.mc-red { color: #FF5555 !important; }
.mc-light-purple { color: #FF55FF !important; }
.mc-yellow { color: #FFFF55 !important; }
.mc-white { color: #FFFFFF !important; }

View file

@ -1889,7 +1889,7 @@
<p>Hard refresh the page (Ctrl+Shift+R on windows/chrome) if it isn't updating correctly.</p> <p>Hard refresh the page (Ctrl+Shift+R on windows/chrome) if it isn't updating correctly.</p>
</div> </div>
<div id="credits"> <div id="credits">
<a href="credits.txt" class="link">Additional credits</a> <a href="../credits.txt" class="link">Additional credits</a>
</div> </div>
</footer> </footer>
</div> </div>
@ -1906,8 +1906,6 @@
<script type="text/javascript" src="/js/craft.js"></script> <script type="text/javascript" src="/js/craft.js"></script>
<script type="text/javascript" src="/js/display_constants.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/display.js"></script>
<script type="text/javascript" src="/js/sq2display_constants.js"></script>
<script type="text/javascript" src="/js/sq2display.js"></script>
<script type="text/javascript" src="/js/custom.js"></script> <script type="text/javascript" src="/js/custom.js"></script>
<script type="text/javascript" src="/js/customizer.js"></script> <script type="text/javascript" src="/js/customizer.js"></script>
</body> </body>

View file

@ -67,6 +67,6 @@
<script type="text/javascript" src="/js/utils.js"></script> <script type="text/javascript" src="/js/utils.js"></script>
<script type="text/javascript" src="/js/loadheader.js"></script> <script type="text/javascript" src="/js/loadheader.js"></script>
<script type="text/javascript" src="/js/icons.js"></script> <script type="text/javascript" src="/js/icons.js"></script>
<script type="text/javascript" src="/js/dps_vis.js"></script> <script type="text/javascript" src="/js/debug/dps_vis.js"></script>
</body> </body>
</html> </html>

View file

@ -200,8 +200,8 @@
"lvl": 75, "lvl": 75,
"ids": { "ids": {
"mr": { "mr": {
"minimum": 1, "minimum": 5,
"maximum": 1 "maximum": 5
}, },
"sdPct": { "sdPct": {
"minimum": -22, "minimum": -22,
@ -9834,7 +9834,7 @@
"ids": { "ids": {
"mr": { "mr": {
"minimum": 0, "minimum": 0,
"maximum": 1 "maximum": 5
} }
}, },
"itemIDs": { "itemIDs": {
@ -10533,7 +10533,7 @@
"ids": { "ids": {
"ms": { "ms": {
"minimum": 0, "minimum": 0,
"maximum": 1 "maximum": 5
} }
}, },
"itemIDs": { "itemIDs": {
@ -10882,8 +10882,8 @@
"maximum": 15 "maximum": 15
}, },
"ms": { "ms": {
"minimum": 1, "minimum": 5,
"maximum": 1 "maximum": 5
} }
}, },
"itemIDs": { "itemIDs": {
@ -11906,8 +11906,8 @@
"maximum": -5 "maximum": -5
}, },
"ms": { "ms": {
"minimum": 1, "minimum": 5,
"maximum": 1 "maximum": 5
}, },
"gXp": { "gXp": {
"minimum": 4, "minimum": 4,
@ -14594,8 +14594,8 @@
"lvl": 76, "lvl": 76,
"ids": { "ids": {
"ms": { "ms": {
"minimum": 1, "minimum": 5,
"maximum": 1 "maximum": 5
}, },
"spd": { "spd": {
"minimum": -12, "minimum": -12,
@ -15404,8 +15404,8 @@
"lvl": 28, "lvl": 28,
"ids": { "ids": {
"mr": { "mr": {
"minimum": 1, "minimum": 5,
"maximum": 1 "maximum": 5
}, },
"xpb": { "xpb": {
"minimum": -10, "minimum": -10,
@ -15569,8 +15569,8 @@
"lvl": 102, "lvl": 102,
"ids": { "ids": {
"ms": { "ms": {
"minimum": 1, "minimum": 5,
"maximum": 1 "maximum": 5
}, },
"hpBonus": { "hpBonus": {
"minimum": -260, "minimum": -260,
@ -15684,8 +15684,8 @@
"lvl": 87, "lvl": 87,
"ids": { "ids": {
"mr": { "mr": {
"minimum": 1, "minimum": 5,
"maximum": 1 "maximum": 5
}, },
"sdRaw": { "sdRaw": {
"minimum": 65, "minimum": 65,
@ -15762,8 +15762,8 @@
"lvl": 65, "lvl": 65,
"ids": { "ids": {
"ms": { "ms": {
"minimum": 1, "minimum": 5,
"maximum": 1 "maximum": 5
} }
}, },
"itemIDs": { "itemIDs": {
@ -16037,8 +16037,8 @@
"lvl": 77, "lvl": 77,
"ids": { "ids": {
"mr": { "mr": {
"minimum": 1, "minimum": 5,
"maximum": 1 "maximum": 5
}, },
"hpBonus": { "hpBonus": {
"minimum": -775, "minimum": -775,
@ -16270,8 +16270,8 @@
"lvl": 50, "lvl": 50,
"ids": { "ids": {
"mr": { "mr": {
"minimum": -1, "minimum": -5,
"maximum": -1 "maximum": -5
}, },
"sdPct": { "sdPct": {
"minimum": 8, "minimum": 8,
@ -16355,8 +16355,8 @@
"lvl": 90, "lvl": 90,
"ids": { "ids": {
"mr": { "mr": {
"minimum": 1, "minimum": 5,
"maximum": 1 "maximum": 5
}, },
"sdPct": { "sdPct": {
"minimum": 6, "minimum": 6,
@ -16396,8 +16396,8 @@
"lvl": 90, "lvl": 90,
"ids": { "ids": {
"ms": { "ms": {
"minimum": 1, "minimum": 5,
"maximum": 1 "maximum": 5
}, },
"mdRaw": { "mdRaw": {
"minimum": 50, "minimum": 50,
@ -16734,8 +16734,8 @@
"maximum": 20 "maximum": 20
}, },
"ms": { "ms": {
"minimum": -1, "minimum": -5,
"maximum": -1 "maximum": -5
}, },
"fDamPct": { "fDamPct": {
"minimum": 10, "minimum": 10,
@ -16777,8 +16777,8 @@
"lvl": 99, "lvl": 99,
"ids": { "ids": {
"mr": { "mr": {
"minimum": 1, "minimum": 5,
"maximum": 1 "maximum": 5
}, },
"sdPct": { "sdPct": {
"minimum": 10, "minimum": 10,
@ -16944,8 +16944,8 @@
"maximum": 10 "maximum": 10
}, },
"mr": { "mr": {
"minimum": 1, "minimum": 5,
"maximum": 1 "maximum": 5
} }
}, },
"itemIDs": { "itemIDs": {
@ -17488,12 +17488,12 @@
"lvl": 23, "lvl": 23,
"ids": { "ids": {
"mr": { "mr": {
"minimum": 1, "minimum": 5,
"maximum": 1 "maximum": 5
}, },
"ms": { "ms": {
"minimum": 0, "minimum": 0,
"maximum": 1 "maximum": 5
} }
}, },
"itemIDs": { "itemIDs": {
@ -18623,8 +18623,8 @@
"maximum": -100 "maximum": -100
}, },
"ms": { "ms": {
"minimum": 1, "minimum": 5,
"maximum": 1 "maximum": 5
}, },
"wDamPct": { "wDamPct": {
"minimum": 10, "minimum": 10,
@ -18908,8 +18908,8 @@
"lvl": 29, "lvl": 29,
"ids": { "ids": {
"mr": { "mr": {
"minimum": 1, "minimum": 5,
"maximum": 1 "maximum": 5
}, },
"sdPct": { "sdPct": {
"minimum": -8, "minimum": -8,
@ -18947,8 +18947,8 @@
"lvl": 105, "lvl": 105,
"ids": { "ids": {
"ms": { "ms": {
"minimum": 1, "minimum": 5,
"maximum": 1 "maximum": 5
}, },
"agi": { "agi": {
"minimum": 8, "minimum": 8,
@ -19535,8 +19535,8 @@
"lvl": 104, "lvl": 104,
"ids": { "ids": {
"ms": { "ms": {
"minimum": 1, "minimum": 5,
"maximum": 1 "maximum": 5
}, },
"gXp": { "gXp": {
"minimum": 3, "minimum": 3,
@ -21060,8 +21060,8 @@
"lvl": 75, "lvl": 75,
"ids": { "ids": {
"ms": { "ms": {
"minimum": 1, "minimum": 5,
"maximum": 1 "maximum": 5
}, },
"int": { "int": {
"minimum": 3, "minimum": 3,
@ -21387,12 +21387,12 @@
"lvl": 78, "lvl": 78,
"ids": { "ids": {
"mr": { "mr": {
"minimum": 1, "minimum": 5,
"maximum": 1 "maximum": 5
}, },
"ms": { "ms": {
"minimum": -1, "minimum": -5,
"maximum": -1 "maximum": -5
}, },
"wDamPct": { "wDamPct": {
"minimum": 5, "minimum": 5,
@ -21550,8 +21550,8 @@
"lvl": 93, "lvl": 93,
"ids": { "ids": {
"ms": { "ms": {
"minimum": 1, "minimum": 5,
"maximum": 1 "maximum": 5
}, },
"sdRaw": { "sdRaw": {
"minimum": 45, "minimum": 45,
@ -21595,8 +21595,8 @@
"lvl": 20, "lvl": 20,
"ids": { "ids": {
"ms": { "ms": {
"minimum": 1, "minimum": 5,
"maximum": 1 "maximum": 5
}, },
"sdRaw": { "sdRaw": {
"minimum": 8, "minimum": 8,
@ -21958,8 +21958,8 @@
"lvl": 43, "lvl": 43,
"ids": { "ids": {
"mr": { "mr": {
"minimum": -1, "minimum": -5,
"maximum": -1 "maximum": -5
}, },
"sdPct": { "sdPct": {
"minimum": 11, "minimum": 11,
@ -22216,8 +22216,8 @@
"lvl": 75, "lvl": 75,
"ids": { "ids": {
"mr": { "mr": {
"minimum": -1, "minimum": -5,
"maximum": -1 "maximum": -5
}, },
"sdPct": { "sdPct": {
"minimum": 15, "minimum": 15,
@ -22714,8 +22714,8 @@
"lvl": 80, "lvl": 80,
"ids": { "ids": {
"mr": { "mr": {
"minimum": 1, "minimum": 5,
"maximum": 1 "maximum": 5
}, },
"sdPct": { "sdPct": {
"minimum": -20, "minimum": -20,
@ -22911,8 +22911,8 @@
"lvl": 8, "lvl": 8,
"ids": { "ids": {
"ms": { "ms": {
"minimum": 1, "minimum": 5,
"maximum": 1 "maximum": 5
}, },
"ref": { "ref": {
"minimum": 2, "minimum": 2,
@ -22988,8 +22988,8 @@
"lvl": 45, "lvl": 45,
"ids": { "ids": {
"mr": { "mr": {
"minimum": 2, "minimum": 10,
"maximum": 2 "maximum": 10
} }
}, },
"itemIDs": { "itemIDs": {
@ -23583,8 +23583,8 @@
"lvl": 42, "lvl": 42,
"ids": { "ids": {
"mr": { "mr": {
"minimum": 1, "minimum": 5,
"maximum": 1 "maximum": 5
} }
}, },
"itemIDs": { "itemIDs": {
@ -23878,8 +23878,8 @@
"lvl": 50, "lvl": 50,
"ids": { "ids": {
"mr": { "mr": {
"minimum": 1, "minimum": 5,
"maximum": 1 "maximum": 5
}, },
"sdPct": { "sdPct": {
"minimum": -12, "minimum": -12,
@ -23957,8 +23957,8 @@
"lvl": 55, "lvl": 55,
"ids": { "ids": {
"ms": { "ms": {
"minimum": 1, "minimum": 5,
"maximum": 1 "maximum": 5
}, },
"spd": { "spd": {
"minimum": 8, "minimum": 8,
@ -24035,8 +24035,8 @@
"lvl": 43, "lvl": 43,
"ids": { "ids": {
"mr": { "mr": {
"minimum": -2, "minimum": -10,
"maximum": -2 "maximum": -10
}, },
"sdPct": { "sdPct": {
"minimum": 24, "minimum": 24,
@ -24120,8 +24120,8 @@
"maximum": 14 "maximum": 14
}, },
"mr": { "mr": {
"minimum": 1, "minimum": 5,
"maximum": 1 "maximum": 5
}, },
"hprRaw": { "hprRaw": {
"minimum": 24, "minimum": 24,
@ -24160,8 +24160,8 @@
"lvl": 92, "lvl": 92,
"ids": { "ids": {
"mr": { "mr": {
"minimum": 1, "minimum": 5,
"maximum": 1 "maximum": 5
}, },
"sdRaw": { "sdRaw": {
"minimum": 110, "minimum": 110,
@ -24373,8 +24373,8 @@
"lvl": 90, "lvl": 90,
"ids": { "ids": {
"mr": { "mr": {
"minimum": 1, "minimum": 5,
"maximum": 1 "maximum": 5
}, },
"spd": { "spd": {
"minimum": 16, "minimum": 16,
@ -25193,8 +25193,8 @@
"maximum": 20 "maximum": 20
}, },
"mr": { "mr": {
"minimum": -1, "minimum": -5,
"maximum": -1 "maximum": -5
} }
}, },
"itemIDs": { "itemIDs": {
@ -25249,8 +25249,8 @@
"maximum": 20 "maximum": 20
}, },
"mr": { "mr": {
"minimum": -1, "minimum": -5,
"maximum": -1 "maximum": -5
} }
}, },
"itemIDs": { "itemIDs": {
@ -25285,8 +25285,8 @@
"lvl": 83, "lvl": 83,
"ids": { "ids": {
"mr": { "mr": {
"minimum": 2, "minimum": 10,
"maximum": 2 "maximum": 10
} }
}, },
"itemIDs": { "itemIDs": {
@ -25544,8 +25544,8 @@
"lvl": 10, "lvl": 10,
"ids": { "ids": {
"mr": { "mr": {
"minimum": 1, "minimum": 5,
"maximum": 1 "maximum": 5
} }
}, },
"itemIDs": { "itemIDs": {
@ -26028,8 +26028,8 @@
"lvl": 47, "lvl": 47,
"ids": { "ids": {
"ms": { "ms": {
"minimum": 1, "minimum": 5,
"maximum": 1 "maximum": 5
}, },
"tDamPct": { "tDamPct": {
"minimum": 6, "minimum": 6,
@ -26200,8 +26200,8 @@
"lvl": 87, "lvl": 87,
"ids": { "ids": {
"mr": { "mr": {
"minimum": 1, "minimum": 5,
"maximum": 1 "maximum": 5
}, },
"eDamPct": { "eDamPct": {
"minimum": 10, "minimum": 10,
@ -26769,8 +26769,8 @@
"maximum": 12 "maximum": 12
}, },
"ms": { "ms": {
"minimum": 2, "minimum": 10,
"maximum": 2 "maximum": 10
}, },
"atkTier": { "atkTier": {
"minimum": -1, "minimum": -1,
@ -26971,8 +26971,8 @@
"lvl": 68, "lvl": 68,
"ids": { "ids": {
"ms": { "ms": {
"minimum": 2, "minimum": 10,
"maximum": 2 "maximum": 10
} }
}, },
"itemIDs": { "itemIDs": {
@ -27344,8 +27344,8 @@
"lvl": 25, "lvl": 25,
"ids": { "ids": {
"ms": { "ms": {
"minimum": 1, "minimum": 5,
"maximum": 1 "maximum": 5
} }
}, },
"itemIDs": { "itemIDs": {

File diff suppressed because one or more lines are too long

View file

@ -58,6 +58,7 @@
<script type="text/javascript" src="/js/build_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/icons.js"></script>
<script type="text/javascript" src="/js/damage_calc.js"></script> <script type="text/javascript" src="/js/damage_calc.js"></script>
<script type="text/javascript" src="/js/powders.js"></script>
<!-- <script type="text/javascript" src="/js/powders.js"></script> --> <!-- <script type="text/javascript" src="/js/powders.js"></script> -->
<script type="text/javascript" src="/js/load.js"></script> <script type="text/javascript" src="/js/load.js"></script>
<script type="text/javascript" src="/js/load_ing.js"></script> <script type="text/javascript" src="/js/load_ing.js"></script>

View file

@ -140,13 +140,11 @@
<script type="text/javascript" src="../js/damage_calc.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_constants.js"></script>
<script type="text/javascript" src="../js/display.js"></script> <script type="text/javascript" src="../js/display.js"></script>
<script type="text/javascript" src="../js/sq2display_constants.js"></script>
<script type="text/javascript" src="../js/sq2display.js"></script>
<script type="text/javascript" src="../js/query.js"></script> <script type="text/javascript" src="../js/query.js"></script>
<script type="text/javascript" src="../js/query_2.js"></script> <script type="text/javascript" src="../js/query_2.js"></script>
<script type="text/javascript" src="../js/expr_parser.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/load.js"></script>
<script type="text/javascript" src="../js/items.js"></script>
<script type="text/javascript" src="../js/sq2items.js"></script> <script type="text/javascript" src="../js/sq2items.js"></script>
<script type="text/javascript" src="../js/powders.js"></script>
</body> </body>
</html> </html>

View file

@ -36,7 +36,7 @@
<div class = "col"> <div class = "col">
<div class = "row"> <div class = "row">
<div class = "col text-start" id = "credits"> <div class = "col text-start" id = "credits">
<a href="credits.txt" class="link">Additional credits</a> <a href="../credits.txt" class="link">Additional credits</a>
</div> </div>
<div class = "col text-center" id = "help"> <div class = "col text-center" id = "help">
<a href="items_2_help.html" class="link" target="_blank">Search Guide</a> <a href="items_2_help.html" class="link" target="_blank">Search Guide</a>

View file

@ -1,5 +1,6 @@
How to convert: How to convert:
0. start in the `js` directory
1. edit `atree_constants.js` 1. edit `atree_constants.js`
2. run `python3 ../py_script/atree-generateID.py 2. run `python3 ../py_script/atree-generateID.py
3. check that the site still works 3. check that the site still works

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

File diff suppressed because one or more lines are too long

View file

@ -1,146 +0,0 @@
{
"Archer": {
"Arrow Shield": 0,
"Escape": 1,
"Arrow Bomb": 2,
"Heart Shatter": 3,
"Fire Creep": 4,
"Bryophyte Roots": 5,
"Nimble String": 6,
"Arrow Storm": 7,
"Guardian Angels": 8,
"Windy Feet": 9,
"Basaltic Trap": 10,
"Windstorm": 11,
"Grappling Hook": 12,
"Implosion": 13,
"Twain's Arc": 14,
"Fierce Stomp": 15,
"Scorched Earth": 16,
"Leap": 17,
"Shocking Bomb": 18,
"Mana Trap": 19,
"Escape Artist": 20,
"Initiator": 21,
"Call of the Hound": 22,
"Arrow Hurricane": 23,
"Geyser Stomp": 24,
"Crepuscular Ray": 25,
"Grape Bomb": 26,
"Tangled Traps": 27,
"Snow Storm": 28,
"All-Seeing Panoptes": 29,
"Minefield": 30,
"Bow Proficiency I": 31,
"Cheaper Arrow Bomb": 32,
"Cheaper Arrow Storm": 33,
"Cheaper Escape": 34,
"Earth Mastery": 35,
"Thunder Mastery": 36,
"Water Mastery": 37,
"Air Mastery": 38,
"Fire Mastery": 39,
"More Shields": 40,
"Stormy Feet": 41,
"Refined Gunpowder": 42,
"More Traps": 43,
"Better Arrow Shield": 44,
"Better Leap": 45,
"Better Guardian Angels": 46,
"Cheaper Arrow Storm (2)": 47,
"Precise Shot": 48,
"Cheaper Arrow Shield": 49,
"Rocket Jump": 50,
"Cheaper Escape (2)": 51,
"Stronger Hook": 52,
"Cheaper Arrow Bomb (2)": 53,
"Bouncing Bomb": 54,
"Homing Shots": 55,
"Shrapnel Bomb": 56,
"Elusive": 57,
"Double Shots": 58,
"Triple Shots": 59,
"Power Shots": 60,
"Focus": 61,
"More Focus": 62,
"More Focus (2)": 63,
"Traveler": 64,
"Patient Hunter": 65,
"Stronger Patient Hunter": 66,
"Frenzy": 67,
"Phantom Ray": 68,
"Arrow Rain": 69,
"Decimator": 70
},
"Warrior": {
"Bash": 0,
"Spear Proficiency 1": 1,
"Cheaper Bash": 2,
"Double Bash": 3,
"Charge": 4,
"Heavy Impact": 5,
"Vehement": 6,
"Tougher Skin": 7,
"Uppercut": 8,
"Cheaper Charge": 9,
"War Scream": 10,
"Earth Mastery": 11,
"Thunder Mastery": 12,
"Water Mastery": 13,
"Air Mastery": 14,
"Fire Mastery": 15,
"Quadruple Bash": 16,
"Fireworks": 17,
"Half-Moon Swipe": 18,
"Flyby Jab": 19,
"Flaming Uppercut": 20,
"Iron Lungs": 21,
"Generalist": 22,
"Counter": 23,
"Mantle of the Bovemists": 24,
"Bak'al's Grasp": 25,
"Spear Proficiency 2": 26,
"Cheaper Uppercut": 27,
"Aerodynamics": 28,
"Provoke": 29,
"Precise Strikes": 30,
"Air Shout": 31,
"Enraged Blow": 32,
"Flying Kick": 33,
"Stronger Mantle": 34,
"Manachism": 35,
"Boiling Blood": 36,
"Ragnarokkr": 37,
"Ambidextrous": 38,
"Burning Heart": 39,
"Stronger Bash": 40,
"Intoxicating Blood": 41,
"Comet": 42,
"Collide": 43,
"Rejuvenating Skin": 44,
"Uncontainable Corruption": 45,
"Radiant Devotee": 46,
"Whirlwind Strike": 47,
"Mythril Skin": 48,
"Armour Breaker": 49,
"Shield Strike": 50,
"Sparkling Hope": 51,
"Massive Bash": 52,
"Tempest": 53,
"Spirit of the Rabbit": 54,
"Massacre": 55,
"Axe Kick": 56,
"Radiance": 57,
"Cheaper Bash 2": 58,
"Cheaper War Scream": 59,
"Discombobulate": 60,
"Thunderclap": 61,
"Cyclone": 62,
"Second Chance": 63,
"Blood Pact": 64,
"Haemorrhage": 65,
"Brink of Madness": 66,
"Cheaper Uppercut 2": 67,
"Martyr": 68
}
}

View file

@ -1,95 +1,10 @@
const classDefenseMultipliers = new Map([ ["relik",0.50], ["bow",0.60], ["wand", 0.80], ["dagger", 1.0], ["spear",1.20], ["sword", 1.10]]); const classDefenseMultipliers = new Map([ ["relik",0.50], ["bow",0.60], ["wand", 0.80], ["dagger", 1.0], ["spear",1.0], ["sword", 1.10]]);
/** /*
* @description Error to catch items that don't exist. * Class that represents a wynn player's build.
* @module ItemNotFound
*/ */
class ItemNotFound {
/**
* @class
* @param {String} item the item name entered
* @param {String} type the type of item
* @param {Boolean} genElement whether to generate an element from inputs
* @param {String} override override for item type
*/
constructor(item, type, genElement, override) {
/**
* @public
* @type {String}
*/
this.message = `Cannot find ${override||type} named ${item}`;
if (genElement)
/**
* @public
* @type {Element}
*/
this.element = document.getElementById(`${type}-choice`).parentElement.querySelectorAll("p.error")[0];
else
this.element = document.createElement("div");
}
}
/**
* @description Error to catch incorrect input.
* @module IncorrectInput
*/
class IncorrectInput {
/**
* @class
* @param {String} input the inputted text
* @param {String} format the correct format
* @param {String} sibling the id of the error node's sibling
*/
constructor(input, format, sibling) {
/**
* @public
* @type {String}
*/
this.message = `${input} is incorrect. Example: ${format}`;
/**
* @public
* @type {String}
*/
this.id = sibling;
}
}
/**
* @description Error that inputs an array of items to generate errors of.
* @module ListError
* @extends Error
*/
class ListError extends Error {
/**
* @class
* @param {Array} errors array of errors
*/
constructor(errors) {
let ret = [];
if (typeof errors[0] == "string") {
super(errors[0]);
} else {
super(errors[0].message);
}
for (let i of errors) {
if (typeof i == "string") {
ret.push(new Error(i));
} else {
ret.push(i);
}
}
/**
* @public
* @type {Object[]}
*/
this.errors = ret;
}
}
/*Class that represents a wynn player's build.
*/
class Build{ class Build{
/** /**
@ -115,7 +30,6 @@ class Build{
this.level = level; this.level = level;
} else if (typeof level === "string") { } else if (typeof level === "string") {
this.level = level; this.level = level;
errors.push(new IncorrectInput(level, "a number", "level-choice"));
} else { } else {
errors.push("Level is not a string or number."); errors.push("Level is not a string or number.");
} }
@ -168,7 +82,6 @@ class Build{
//Create a map of this build's stats //Create a map of this build's stats
let statMap = new Map(); let statMap = new Map();
statMap.set("defMultiplier", 1);
for (const staticID of staticIDs) { for (const staticID of staticIDs) {
statMap.set(staticID, 0); statMap.set(staticID, 0);
@ -198,8 +111,10 @@ class Build{
} }
} }
} }
statMap.set('damageMultiplier', 1 + (statMap.get('damMobs') / 100)); statMap.set('damMult', new Map());
statMap.set('defMultiplier', 1 - (statMap.get('defMobs') / 100)); statMap.set('defMult', new Map());
statMap.get('damMult').set('tome', statMap.get('damMobs'))
statMap.get('defMult').set('tome', statMap.get('defMobs'))
statMap.set("activeMajorIDs", major_ids); statMap.set("activeMajorIDs", major_ids);
for (const [setName, count] of this.activeSetCounts) { for (const [setName, count] of this.activeSetCounts) {
const bonus = sets.get(setName).bonuses[count-1]; const bonus = sets.get(setName).bonuses[count-1];
@ -213,6 +128,8 @@ class Build{
} }
} }
statMap.set("poisonPct", 100); statMap.set("poisonPct", 100);
statMap.set("critDamPct", 100);
statMap.set("healPct", 100);
// The stuff relevant for damage calculation!!! @ferricles // The stuff relevant for damage calculation!!! @ferricles
statMap.set("atkSpd", this.weapon.statMap.get("atkSpd")); statMap.set("atkSpd", this.weapon.statMap.get("atkSpd"));

View file

@ -7,8 +7,6 @@ const url_tag = location.hash.slice(1);
const BUILD_VERSION = "7.0.19"; const BUILD_VERSION = "7.0.19";
let player_build;
// THIS IS SUPER DANGEROUS, WE SHOULD NOT BE KEEPING THIS IN SO MANY PLACES // THIS IS SUPER DANGEROUS, WE SHOULD NOT BE KEEPING THIS IN SO MANY PLACES
let editable_item_fields = [ "sdPct", "sdRaw", "mdPct", "mdRaw", "poison", let editable_item_fields = [ "sdPct", "sdRaw", "mdPct", "mdRaw", "poison",

View file

@ -1,3 +1,9 @@
let player_build;
let build_powders;
function getItemNameFromID(id) { return idMap.get(id); }
function getTomeNameFromID(id) { return tomeIDMap.get(id); }
function parsePowdering(powder_info) { function parsePowdering(powder_info) {
// TODO: Make this run in linear instead of quadratic time... ew // TODO: Make this run in linear instead of quadratic time... ew
let powdering = []; let powdering = [];
@ -124,7 +130,6 @@ function decodeBuild(url_tag) {
for (let i in tomes) { for (let i in tomes) {
let tome_str = info[1].charAt(i); let tome_str = info[1].charAt(i);
let tome_name = getTomeNameFromID(Base64.toInt(tome_str)); let tome_name = getTomeNameFromID(Base64.toInt(tome_str));
console.log(tome_name);
setValue(tomeInputs[i], tome_name); setValue(tomeInputs[i], tome_name);
} }
info[1] = info[1].slice(7); info[1] = info[1].slice(7);
@ -200,7 +205,7 @@ function encodeBuild(build, powders, skillpoints, atree, atree_state) {
} }
build_string += tome_string; build_string += tome_string;
if (atree_state.get(atree[0].ability.id).active) { if (atree.length > 0 && atree_state.get(atree[0].ability.id).active) {
build_version = Math.max(build_version, 7); build_version = Math.max(build_version, 7);
const bitvec = encode_atree(atree, atree_state); const bitvec = encode_atree(atree, atree_state);
build_string += bitvec.toB64(); build_string += bitvec.toB64();

View file

@ -15,6 +15,11 @@ function skillPointsToPercentage(skp){
//return clamp((-0.0000000066695* Math.pow(Math.E, -0.00924033 * skp + 18.9) + 1.0771), 0.00, 0.808); //return clamp((-0.0000000066695* Math.pow(Math.E, -0.00924033 * skp + 18.9) + 1.0771), 0.00, 0.808);
} }
// WYNN2: Skillpoint max scaling. Intel is cost reduction
const skillpoint_final_mult = [1, 1, 0.5/skillPointsToPercentage(150), 0.867, 0.951];
// intel water%
const skillpoint_damage_mult = [1, 1, 1, 0.867, 0.951];
/*Turns the input amount of levels into skillpoints available. /*Turns the input amount of levels into skillpoints available.
* *
* @param level - the integer level count to be converted * @param level - the integer level count to be converted
@ -69,17 +74,17 @@ 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. // wynn2 damages.
"eMdPct","eMdRaw","eSdPct","eSdRaw",/*"eDamPct"*/,"eDamRaw","eDamAddMin","eDamAddMax", "eMdPct","eMdRaw","eSdPct","eSdRaw",/*"eDamPct,"*/"eDamRaw","eDamAddMin","eDamAddMax",
"tMdPct","tMdRaw","tSdPct","tSdRaw",/*"tDamPct"*/,"tDamRaw","tDamAddMin","tDamAddMax", "tMdPct","tMdRaw","tSdPct","tSdRaw",/*"tDamPct,"*/"tDamRaw","tDamAddMin","tDamAddMax",
"wMdPct","wMdRaw","wSdPct","wSdRaw",/*"wDamPct"*/,"wDamRaw","wDamAddMin","wDamAddMax", "wMdPct","wMdRaw","wSdPct","wSdRaw",/*"wDamPct,"*/"wDamRaw","wDamAddMin","wDamAddMax",
"fMdPct","fMdRaw","fSdPct","fSdRaw",/*"fDamPct"*/,"fDamRaw","fDamAddMin","fDamAddMax", "fMdPct","fMdRaw","fSdPct","fSdRaw",/*"fDamPct,"*/"fDamRaw","fDamAddMin","fDamAddMax",
"aMdPct","aMdRaw","aSdPct","aSdRaw",/*"aDamPct"*/,"aDamRaw","aDamAddMin","aDamAddMax", "aMdPct","aMdRaw","aSdPct","aSdRaw",/*"aDamPct,"*/"aDamRaw","aDamAddMin","aDamAddMax",
"nMdPct","nMdRaw","nSdPct","nSdRaw","nDamPct","nDamRaw","nDamAddMin","nDamAddMax", // neutral which is now an element "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. /*"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
"critDamPct" "critDamPct"
]; ];
// Extra fake IDs (reserved for use in spell damage calculation) : damageMultiplier, defMultiplier, poisonPct, activeMajorIDs // 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" ] 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 //File reading for ID translations for JSON purposes
@ -164,11 +169,11 @@ let rolledIDs = [
"gXp", "gXp",
"gSpd", "gSpd",
// wynn2 damages. // wynn2 damages.
"eMdPct","eMdRaw","eSdPct","eSdRaw",/*"eDamPct"*/,"eDamRaw","eDamAddMin","eDamAddMax", "eMdPct","eMdRaw","eSdPct","eSdRaw",/*"eDamPct,"*/"eDamRaw","eDamAddMin","eDamAddMax",
"tMdPct","tMdRaw","tSdPct","tSdRaw",/*"tDamPct"*/,"tDamRaw","tDamAddMin","tDamAddMax", "tMdPct","tMdRaw","tSdPct","tSdRaw",/*"tDamPct,"*/"tDamRaw","tDamAddMin","tDamAddMax",
"wMdPct","wMdRaw","wSdPct","wSdRaw",/*"wDamPct"*/,"wDamRaw","wDamAddMin","wDamAddMax", "wMdPct","wMdRaw","wSdPct","wSdRaw",/*"wDamPct,"*/"wDamRaw","wDamAddMin","wDamAddMax",
"fMdPct","fMdRaw","fSdPct","fSdRaw",/*"fDamPct"*/,"fDamRaw","fDamAddMin","fDamAddMax", "fMdPct","fMdRaw","fSdPct","fSdRaw",/*"fDamPct,"*/"fDamRaw","fDamAddMin","fDamAddMax",
"aMdPct","aMdRaw","aSdPct","aSdRaw",/*"aDamPct"*/,"aDamRaw","aDamAddMin","aDamAddMax", "aMdPct","aMdRaw","aSdPct","aSdRaw",/*"aDamPct,"*/"aDamRaw","aDamAddMin","aDamAddMax",
"nMdPct","nMdRaw","nSdPct","nSdRaw","nDamPct","nDamRaw","nDamAddMin","nDamAddMax", // neutral which is now an element "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. /*"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
@ -295,3 +300,28 @@ function idRound(id){
return rounded; return rounded;
} }
} }
/**
* stupid stupid multiplicative stats
*/
function merge_stat(stats, name, value) {
const start = name.slice(0, 7);
if (start === 'damMult' || start === 'defMult') {
if (!stats.has(start)) {
stats.set(start, new Map());
}
const map = stats.get(start);
if (value instanceof Map) {
for (const [k, v] of value.entries()) {
merge_stat(map, k, v);
}
return;
}
merge_stat(map, name.slice(8), value);
return;
}
if (stats.has(name)) {
stats.set(name, stats.get(name) + value);
}
else { stats.set(name, value); }
}

View file

@ -1,18 +1,3 @@
let build_powders;
function getItemNameFromID(id) {
if (redirectMap.has(id)) {
return getItemNameFromID(redirectMap.get(id));
}
return idMap.get(id);
}
function getTomeNameFromID(id) {
if (tomeRedirectMap.has(id)) {
return getTomeNameFromID(tomeRedirectMap.get(id));
}
return tomeIDMap.get(id);
}
function populateBuildList() { function populateBuildList() {
const buildList = document.getElementById("build-choice"); const buildList = document.getElementById("build-choice");
@ -98,7 +83,6 @@ function resetFields(){
for (const elem of skp_order) { for (const elem of skp_order) {
console.log(document.getElementById(elem + "_boost_armor").value); console.log(document.getElementById(elem + "_boost_armor").value);
document.getElementById(elem + "_boost_armor").value = 0; document.getElementById(elem + "_boost_armor").value = 0;
document.getElementById(elem + "_boost_armor_prev").value = 0;
document.getElementById(elem + "_boost_armor").style.background = `linear-gradient(to right, #AAAAAA, #AAAAAA 0%, #AAAAAA 100%)`; 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`; document.getElementById(elem + "_boost_armor_label").textContent = `% ${damageClasses[skp_order.indexOf(elem)+1]} Damage Boost: 0`;
} }
@ -149,7 +133,6 @@ function toggle_tab(tab) {
} }
} }
function toggle_boost_tab(tab) { function toggle_boost_tab(tab) {
for (const i of skp_order) { for (const i of skp_order) {
document.querySelector("#"+i+"-boost").style.display = "none"; document.querySelector("#"+i+"-boost").style.display = "none";
@ -157,13 +140,10 @@ function toggle_boost_tab(tab) {
} }
document.querySelector("#"+tab+"-boost").style.display = ""; document.querySelector("#"+tab+"-boost").style.display = "";
document.getElementById(tab + "-boost-tab").classList.add("selected-btn"); document.getElementById(tab + "-boost-tab").classList.add("selected-btn");
} }
let tabs = ['overall-stats', 'offensive-stats', 'defensive-stats']; let tabs = ['overall-stats', 'offensive-stats', 'defensive-stats'];
function show_tab(tab) { function show_tab(tab) {
//console.log(itemFilters)
//hide all tabs, then show the tab of the div clicked and highlight the correct button //hide all tabs, then show the tab of the div clicked and highlight the correct button
for (const i in tabs) { for (const i in tabs) {
document.querySelector("#" + tabs[i]).style.display = "none"; document.querySelector("#" + tabs[i]).style.display = "none";
@ -320,51 +300,6 @@ function init_autocomplete() {
})); }));
} }
let filter_loc = ["filter1", "filter2", "filter3", "filter4"];
for (const i of filter_loc) {
dropdowns.set(i+"-choice", new autoComplete({
data: {
src: sq2ItemFilters,
},
selector: "#"+i+"-choice",
wrapper: false,
resultsList: {
tabSelect: true,
noResults: true,
class: "search-box dark-7 rounded-bottom px-2 fw-bold dark-shadow-sm",
element: (list, data) => {
// dynamic result loc
console.log(i);
list.style.zIndex = "100";
let position = document.getElementById(i+"-dropdown").getBoundingClientRect();
window_pos = document.getElementById("search-container").getBoundingClientRect();
list.style.top = position.bottom - window_pos.top + 5 +"px";
list.style.left = position.x - window_pos.x +"px";
list.style.width = position.width+"px";
if (!data.results.length) {
message = document.createElement('li');
message.classList.add('scaled-font');
message.textContent = "No filters 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;
}
},
},
}
}));
}
} }
function collapse_element(elmnt) { function collapse_element(elmnt) {
@ -394,6 +329,19 @@ function init() {
for (const eq of equipment_keys) { for (const eq of equipment_keys) {
document.querySelector("#"+eq+"-tooltip").addEventListener("click", () => collapse_element('#'+eq+'-tooltip')); document.querySelector("#"+eq+"-tooltip").addEventListener("click", () => collapse_element('#'+eq+'-tooltip'));
} }
// Armor Specials
for (let i = 0; i < 5; ++i) {
const powder_special = powderSpecialStats[i];
const elem_name = damageClasses[i+1]; // skip neutral
const elem_char = skp_elements[i]; // TODO: merge?
const skp_name = skp_order[i]; // TODO: merge?
const boost_parent = document.getElementById(skp_name+'-boost');
const slider_id = skp_name+'_boost_armor';
const label_name = "% " + elem_name + " Dmg Boost";
const slider_container = gen_slider_labeled({label_name: label_name, max: powder_special.cap, id: slider_id, color: elem_colors[i]});
boost_parent.appendChild(slider_container);
document.getElementById(slider_id).addEventListener("change", (_) => armor_powder_node.mark_dirty().update() );
}
// Masonry setup // Masonry setup
let masonry = Macy({ let masonry = Macy({
@ -425,6 +373,15 @@ function init() {
}); });
decodeBuild(url_tag); decodeBuild(url_tag);
builder_graph_init(); builder_graph_init();
for (const item_node of item_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?')) {
hardReload();
}
break;
}
}
} }
window.onerror = function(message, source, lineno, colno, error) { window.onerror = function(message, source, lineno, colno, error) {

View file

@ -11,29 +11,7 @@ let armor_powder_node = new (class extends ComputeNode {
} }
return statMap; return statMap;
} }
})().update(); })();
/* Updates PASSIVE powder special boosts (armors)
*/
function update_armor_powder_specials(elem_id) {
//we only update the powder special + external stats if the player has a build
let wynn_elem = elem_id.split("_")[0]; //str, dex, int, def, agi
//update the label associated w/ the slider
let elem = document.getElementById(elem_id);
let label = document.getElementById(elem_id + "_label");
let value = elem.value;
label.textContent = label.textContent.split(":")[0] + ": " + value
//update the slider's graphics
let bg_color = elem_colors[skp_order.indexOf(wynn_elem)];
let pct = Math.round(100 * value / powderSpecialStats[skp_order.indexOf(wynn_elem)].cap);
elem.style.background = `linear-gradient(to right, ${bg_color}, ${bg_color} ${pct}%, #AAAAAA ${pct}%, #AAAAAA 100%)`;
armor_powder_node.mark_dirty().update();
}
let boosts_node = new (class extends ComputeNode { let boosts_node = new (class extends ComputeNode {
constructor() { super('builder-boost-input'); } constructor() { super('builder-boost-input'); }
@ -45,13 +23,13 @@ let boosts_node = new (class extends ComputeNode {
let elem = document.getElementById(key + "-boost") let elem = document.getElementById(key + "-boost")
if (elem.classList.contains("toggleOn")) { if (elem.classList.contains("toggleOn")) {
damage_boost += value; damage_boost += value;
if (key === "warscream") { def_boost += .20 } if (key === "warscream") { def_boost += .10 }
if (key === "vanish") { def_boost += .15 } if (key === "vanish") { def_boost += .15 }
} }
} }
let res = new Map(); let res = new Map();
res.set('damageMultiplier', 1+damage_boost); res.set('damMult.Potion', 100*damage_boost);
res.set('defMultiplier', 1-def_boost); res.set('defMult.Potion', 100*def_boost);
return res; return res;
} }
})().update(); })().update();
@ -181,7 +159,8 @@ class ItemInputNode extends InputNode {
if (item) { if (item) {
if (powdering !== undefined) { if (powdering !== undefined) {
item.statMap.set('powders', powdering); const max_slots = item.statMap.get('slots');
item.statMap.set('powders', powdering.slice(0, max_slots));
} }
let type_match; let type_match;
if (this.category == 'weapon') { if (this.category == 'weapon') {
@ -213,7 +192,13 @@ class ItemInputNode extends InputNode {
for (const [i, x] of zip2(equipment_inputs, replace_items)) { setValue(i, x); } for (const [i, x] of zip2(equipment_inputs, replace_items)) { setValue(i, x); }
for (const node of item_nodes) { calcSchedule(node, 10); } for (const node of item_nodes) {
if (node !== this) {
// save a tiny bit of compute
calcSchedule(node, 10);
}
}
// Needed to push the weapon node's updates forward
return this.compute_func(input_map); return this.compute_func(input_map);
} }
return null; return null;
@ -257,7 +242,7 @@ class ItemInputDisplayNode extends ComputeNode {
this.input_field.classList.add("is-invalid"); this.input_field.classList.add("is-invalid");
return null; return null;
} }
if (item.statMap.has('powders')) { if (this.powder_field && item.statMap.has('powders')) {
this.powder_field.placeholder = "powders"; this.powder_field.placeholder = "powders";
} }
@ -265,7 +250,7 @@ class ItemInputDisplayNode extends ComputeNode {
return null; return null;
} }
if (item.statMap.has('powders')) { if (this.powder_field && item.statMap.has('powders')) {
this.powder_field.placeholder = item.statMap.get('slots') + ' slots'; this.powder_field.placeholder = item.statMap.get('slots') + ' slots';
} }
@ -422,7 +407,10 @@ class BuildAssembleNode extends ComputeNode {
input_map.get('guildTome1-input') input_map.get('guildTome1-input')
]; ];
let weapon = input_map.get('weapon-input'); let weapon = input_map.get('weapon-input');
let level = input_map.get('level-input'); let level = parseInt(input_map.get('level-input'));
if (isNaN(level)) {
level = 106;
}
let all_none = weapon.statMap.has('NONE'); let all_none = weapon.statMap.has('NONE');
for (const item of equipments) { for (const item of equipments) {
@ -502,16 +490,22 @@ class SpellSelectNode extends ComputeNode {
*/ */
function getDefenseStats(stats) { function getDefenseStats(stats) {
let defenseStats = []; let defenseStats = [];
let def_pct = skillPointsToPercentage(stats.get('def')); let def_pct = skillPointsToPercentage(stats.get('def')) * skillpoint_final_mult[3];
let agi_pct = skillPointsToPercentage(stats.get('agi')); let agi_pct = skillPointsToPercentage(stats.get('agi')) * skillpoint_final_mult[4];
//total hp //total hp
let totalHp = stats.get("hp") + stats.get("hpBonus"); let totalHp = stats.get("hp") + stats.get("hpBonus");
if (totalHp < 5) totalHp = 5; if (totalHp < 5) totalHp = 5;
defenseStats.push(totalHp); defenseStats.push(totalHp);
//EHP //EHP
let ehp = [totalHp, totalHp]; let ehp = [totalHp, totalHp];
let defMult = (2 - stats.get("classDef")) * stats.get("defMultiplier"); let defMult = (2 - stats.get("classDef"));
ehp[0] /= (1-def_pct)*(1-agi_pct)*defMult; for (const [k, v] of stats.get("defMult").entries()) {
defMult *= (1 - v/100);
}
// newehp = oldehp / [0.1 * A(x) + (1 - A(x)) * (1 - D(x))]
ehp[0] = ehp[0] / (0.1*agi_pct + (1-agi_pct) * (1-def_pct));
ehp[0] /= defMult;
// ehp[0] /= (1-def_pct)*(1-agi_pct)*defMult;
ehp[1] /= (1-def_pct)*defMult; ehp[1] /= (1-def_pct)*defMult;
defenseStats.push(ehp); defenseStats.push(ehp);
//HPR //HPR
@ -554,7 +548,6 @@ class SpellDamageCalcNode extends ComputeNode {
const spell = spell_info[0]; const spell = spell_info[0];
const spell_parts = spell_info[1]; const spell_parts = spell_info[1];
const stats = input_map.get('stats'); const stats = input_map.get('stats');
const damage_mult = stats.get('damageMultiplier');
const skillpoints = [ const skillpoints = [
stats.get('str'), stats.get('str'),
stats.get('dex'), stats.get('dex'),
@ -571,7 +564,7 @@ class SpellDamageCalcNode extends ComputeNode {
for (const part of spell_parts) { for (const part of spell_parts) {
let spell_result; let spell_result;
if ('multipliers' in part) { // damage type spell if ('multipliers' in part) { // damage type spell
let results = calculateSpellDamage(stats, weapon, part.multipliers, use_spell, !use_speed); let results = calculateSpellDamage(stats, weapon, part.multipliers, use_spell, !use_speed, spell.base_spell + '.' + part.name);
spell_result = { spell_result = {
type: "damage", type: "damage",
normal_min: results[2].map(x => x[0]), normal_min: results[2].map(x => x[0]),
@ -583,7 +576,7 @@ class SpellDamageCalcNode extends ComputeNode {
} }
} else if ('power' in part) { } else if ('power' in part) {
// TODO: wynn2 formula // TODO: wynn2 formula
let _heal_amount = (part.power * getDefenseStats(stats)[0] * Math.max(0.5,Math.min(1.75, 1 + 0.5 * stats.get("wDamPct")/100))); let _heal_amount = (part.power * getDefenseStats(stats)[0] * (stats.get('healPct')/100));
spell_result = { spell_result = {
type: "heal", type: "heal",
heal_amount: _heal_amount heal_amount: _heal_amount
@ -663,59 +656,10 @@ class SpellDisplayNode extends ComputeNode {
const i = this.spell_idx; const i = this.spell_idx;
let parent_elem = document.getElementById("spell"+i+"-info"); let parent_elem = document.getElementById("spell"+i+"-info");
let overallparent_elem = document.getElementById("spell"+i+"-infoAvg"); let overallparent_elem = document.getElementById("spell"+i+"-infoAvg");
displaySpellDamage(parent_elem, overallparent_elem, stats, spell, i+1, damages); displaySpellDamage(parent_elem, overallparent_elem, stats, spell, i, damages);
} }
} }
/* Get melee stats for build.
Returns an array in the order:
*/
function getMeleeStats(stats, weapon) {
stats = new Map(stats); // Shallow copy
const weapon_stats = weapon.statMap;
const skillpoints = [
stats.get('str'),
stats.get('dex'),
stats.get('int'),
stats.get('def'),
stats.get('agi')
];
if (weapon_stats.get("tier") === "Crafted") {
stats.set("damageBases", [weapon_stats.get("nDamBaseHigh"),weapon_stats.get("eDamBaseHigh"),weapon_stats.get("tDamBaseHigh"),weapon_stats.get("wDamBaseHigh"),weapon_stats.get("fDamBaseHigh"),weapon_stats.get("aDamBaseHigh")]);
}
let adjAtkSpd = attackSpeeds.indexOf(stats.get("atkSpd")) + stats.get("atkTier");
if(adjAtkSpd > 6){
adjAtkSpd = 6;
}else if(adjAtkSpd < 0){
adjAtkSpd = 0;
}
if (weapon_stats.get("type") === "relik") {
stats.set('damageMultiplier', 0.99); // CURSE YOU WYNNCRAFT
//One day we will create WynnWynn and no longer have shaman 99% melee injustice.
//In all seriousness 99% is because wynn uses 0.33 to estimate dividing the damage by 3 to split damage between 3 beams.
}
let results = calculateSpellDamage(stats, weapon_stats, [100, 0, 0, 0, 0, 0], false, true);
let dex = skillpoints[1];
let totalDamNorm = results[0];
let totalDamCrit = results[1];
totalDamNorm.push(1-skillPointsToPercentage(dex));
totalDamCrit.push(skillPointsToPercentage(dex));
let damages_results = results[2];
let singleHitTotal = ((totalDamNorm[0]+totalDamNorm[1])*(totalDamNorm[2])
+(totalDamCrit[0]+totalDamCrit[1])*(totalDamCrit[2]))/2;
//Now do math
let normDPS = (totalDamNorm[0]+totalDamNorm[1])/2 * baseDamageMultiplier[adjAtkSpd];
let critDPS = (totalDamCrit[0]+totalDamCrit[1])/2 * baseDamageMultiplier[adjAtkSpd];
let avgDPS = (normDPS * (1 - skillPointsToPercentage(dex))) + (critDPS * (skillPointsToPercentage(dex)));
//[[n n n n] [e e e e] [t t t t] [w w w w] [f f f f] [a a a a] [lowtotal hightotal normalChance] [critlowtotal crithightotal critChance] normalDPS critCPS averageDPS adjAttackSpeed, singleHit]
return damages_results.concat([totalDamNorm,totalDamCrit,normDPS,critDPS,avgDPS,adjAtkSpd, singleHitTotal]).concat(results[3]);
}
/** /**
* Display build stats. * Display build stats.
* *
@ -730,10 +674,7 @@ class BuildDisplayNode extends ComputeNode {
displayBuildStats('overall-stats', build, build_all_display_commands, stats); displayBuildStats('overall-stats', build, build_all_display_commands, stats);
displayBuildStats("offensive-stats", build, build_offensive_display_commands, stats); displayBuildStats("offensive-stats", build, build_offensive_display_commands, stats);
displaySetBonuses("set-info", build); displaySetBonuses("set-info", build);
let meleeStats = getMeleeStats(stats, build.weapon);
// TODO: move weapon out? // TODO: move weapon out?
displayMeleeDamage(document.getElementById("build-melee-stats"), document.getElementById("build-melee-statsAvg"), meleeStats);
displayDefenseStats(document.getElementById("defensive-stats"), stats); displayDefenseStats(document.getElementById("defensive-stats"), stats);
displayPoisonDamage(document.getElementById("build-poison-stats"), build); displayPoisonDamage(document.getElementById("build-poison-stats"), build);
@ -770,7 +711,7 @@ class DisplayBuildWarningsNode extends ComputeNode {
setValue(skp_order[i] + "-skp", skillpoints[i]); setValue(skp_order[i] + "-skp", skillpoints[i]);
let linebreak = document.createElement("br"); let linebreak = document.createElement("br");
linebreak.classList.add("itemp"); linebreak.classList.add("itemp");
setText(skp_order[i] + "-skp-pct", (skillPointsToPercentage(skillpoints[i])*100).toFixed(1).concat(skp_effects[i])); setText(skp_order[i] + "-skp-pct", (skillPointsToPercentage(skillpoints[i])*100*skillpoint_final_mult[i]).toFixed(1).concat(skp_effects[i]));
document.getElementById(skp_order[i]+"-warnings").textContent = '' document.getElementById(skp_order[i]+"-warnings").textContent = ''
if (assigned > 100) { if (assigned > 100) {
let skp_warning = document.createElement("p"); let skp_warning = document.createElement("p");
@ -859,18 +800,7 @@ class AggregateStatsNode extends ComputeNode {
const output_stats = new Map(); const output_stats = new Map();
for (const [k, v] of input_map.entries()) { for (const [k, v] of input_map.entries()) {
for (const [k2, v2] of v.entries()) { for (const [k2, v2] of v.entries()) {
if (output_stats.has(k2)) { merge_stat(output_stats, k2, v2);
// TODO: ugly AF
if (k2 === 'damageMultiplier' || k2 === 'defMultiplier') {
output_stats.set(k2, v2 * output_stats.get(k2));
}
else {
output_stats.set(k2, v2 + output_stats.get(k2));
}
}
else {
output_stats.set(k2, v2);
}
} }
} }
return output_stats; return output_stats;
@ -972,7 +902,7 @@ class SkillPointSetterNode extends ComputeNode {
class SumNumberInputNode extends InputNode { class SumNumberInputNode extends InputNode {
compute_func(input_map) { compute_func(input_map) {
let value = this.input_field.value; let value = this.input_field.value;
if (value === "") { value = 0; } if (value === "") { value = "0"; }
let input_num = 0; let input_num = 0;
if (value.includes("+")) { if (value.includes("+")) {
@ -1034,6 +964,9 @@ function builder_graph_init() {
// Level input node. // Level input node.
let level_input = new InputNode('level-input', document.getElementById('level-choice')); let level_input = new InputNode('level-input', document.getElementById('level-choice'));
// linking to atree verification
atree_validate.link_to(level_input, 'level');
// "Build" now only refers to equipment and level (no powders). Powders are injected before damage calculation / stat display. // "Build" now only refers to equipment and level (no powders). Powders are injected before damage calculation / stat display.
build_node = new BuildAssembleNode(); build_node = new BuildAssembleNode();
@ -1063,9 +996,6 @@ function builder_graph_init() {
// Phase 2/3: Set up editable IDs, skill points; use decodeBuild() skill points, calculate damage // Phase 2/3: Set up editable IDs, skill points; use decodeBuild() skill points, calculate damage
let build_disp_node = new BuildDisplayNode()
build_disp_node.link_to(build_node, 'build');
// Create one node that will be the "aggregator node" (listen to all the editable id nodes, as well as the build_node (for non editable stats) and collect them into one statmap) // Create one node that will be the "aggregator node" (listen to all the editable id nodes, as well as the build_node (for non editable stats) and collect them into one statmap)
stat_agg_node = new AggregateStatsNode(); stat_agg_node = new AggregateStatsNode();
edit_agg_node = new AggregateEditableIDNode(); edit_agg_node = new AggregateEditableIDNode();
@ -1092,16 +1022,15 @@ function builder_graph_init() {
skp_inputs.push(node); skp_inputs.push(node);
} }
stat_agg_node.link_to(edit_agg_node); stat_agg_node.link_to(edit_agg_node);
build_disp_node.link_to(stat_agg_node, 'stats');
// Phase 3/3: Set up atree stuff. // Phase 3/3: Set up atree stuff.
let class_node = new PlayerClassNode('builder-class').link_to(build_node); let class_node = new PlayerClassNode('builder-class').link_to(build_node);
// These two are defined in `atree.js` // These two are defined in `atree.js`
atree_node.link_to(class_node, 'player-class'); atree_node.link_to(class_node, 'player-class');
atree_merge.link_to(build_node, 'build'); atree_merge.link_to(class_node, 'player-class');
atree_graph_creator = new AbilityTreeEnsureNodesNode(build_node, stat_agg_node) atree_stats.link_to(build_node, 'build');
.link_to(atree_collect_spells, 'spells'); stat_agg_node.link_to(atree_stats, 'atree-stats');
build_encode_node.link_to(atree_node, 'atree').link_to(atree_state_node, 'atree-state'); build_encode_node.link_to(atree_node, 'atree').link_to(atree_state_node, 'atree-state');
@ -1111,8 +1040,12 @@ function builder_graph_init() {
for (const input_node of item_nodes.concat(powder_nodes)) { for (const input_node of item_nodes.concat(powder_nodes)) {
input_node.update(); input_node.update();
} }
armor_powder_node.update();
level_input.update(); level_input.update();
atree_graph_creator = new AbilityTreeEnsureNodesNode(build_node, stat_agg_node)
.link_to(atree_collect_spells, 'spells');
// kinda janky, manually set atree and update. Some wasted compute here // kinda janky, manually set atree and update. Some wasted compute here
if (atree_data !== null && atree_node.value !== null) { // janky check if atree is valid if (atree_data !== null && atree_node.value !== null) { // janky check if atree is valid
const atree_state = atree_state_node.value; const atree_state = atree_state_node.value;
@ -1138,10 +1071,14 @@ function builder_graph_init() {
// Also do something similar for skill points // Also do something similar for skill points
let build_disp_node = new BuildDisplayNode()
build_disp_node.link_to(build_node, 'build');
build_disp_node.link_to(stat_agg_node, 'stats');
for (const node of edit_input_nodes) { for (const node of edit_input_nodes) {
node.update(); node.update();
} }
let skp_output = new SkillPointSetterNode(edit_input_nodes); let skp_output = new SkillPointSetterNode(edit_input_nodes);
skp_output.link_to(build_node); skp_output.link_to(build_node);
@ -1157,5 +1094,6 @@ function builder_graph_init() {
// this will propagate the update to the `stat_agg_node`, and then to damage calc // this will propagate the update to the `stat_agg_node`, and then to damage calc
console.log("Set up graph"); console.log("Set up graph");
graph_live_update = true;
} }

View file

@ -1,4 +1,5 @@
let all_nodes = []; let all_nodes = [];
let node_debug_stack = [];
class ComputeNode { class ComputeNode {
/** /**
* Make a generic compute node. * Make a generic compute node.
@ -33,6 +34,7 @@ class ComputeNode {
if (this.dirty === 0) { if (this.dirty === 0) {
return; return;
} }
node_debug_stack.push(this.name);
if (this.dirty == 2) { if (this.dirty == 2) {
let calc_inputs = new Map(); let calc_inputs = new Map();
for (const input of this.inputs) { for (const input of this.inputs) {
@ -44,6 +46,7 @@ class ComputeNode {
for (const child of this.children) { for (const child of this.children) {
child.mark_input_clean(this.name, this.value); child.mark_input_clean(this.name, this.value);
} }
node_debug_stack.pop();
return this; return this;
} }
@ -174,17 +177,20 @@ class ValueCheckComputeNode extends ComputeNode {
} }
let graph_live_update = false;
/** /**
* Schedule a ComputeNode to be updated. * Schedule a ComputeNode to be updated.
* *
* @param node : ComputeNode to schedule an update for. * @param node : ComputeNode to schedule an update for.
*/ */
function calcSchedule(node, timeout) { function calcSchedule(node, timeout) {
if (!graph_live_update) return;
if (node.update_task !== null) { if (node.update_task !== null) {
clearTimeout(node.update_task); clearTimeout(node.update_task);
} }
node.mark_dirty(); node.mark_dirty();
node.update_task = setTimeout(function() { node.update_task = setTimeout(function() {
node_debug_stack = [];
node.update(); node.update();
node.update_task = null; node.update_task = null;
}, timeout); }, timeout);

View file

@ -44,14 +44,16 @@ function init_crafter() {
try { try {
document.getElementById("recipe-choice").addEventListener("change", (event) => { document.getElementById("recipe-choice").addEventListener("change", (event) => {
updateMaterials(); updateMaterials();
updateCraftedImage();
calculateCraftSchedule(); calculateCraftSchedule();
}); });
document.getElementById("recipe-choice").addEventListener("oninput", (event) => {
updateCraftedImage();
});
document.getElementById("level-choice").addEventListener("change", (event) => { document.getElementById("level-choice").addEventListener("change", (event) => {
updateMaterials(); updateMaterials();
calculateCraftSchedule(); calculateCraftSchedule();
}); });
document.getElementById("recipe-choice").setAttribute("oninput", "updateCraftedImage()");
document.getElementById("recipe-choice").setAttribute("change", "updateCraftedImage()");
for (let i = 1; i < 4; ++i) { for (let i = 1; i < 4; ++i) {
document.getElementById("mat-1-"+i).setAttribute("onclick", document.getElementById("mat-1-"+i).getAttribute("onclick") + "; calculateCraftSchedule();"); document.getElementById("mat-1-"+i).setAttribute("onclick", document.getElementById("mat-1-"+i).getAttribute("onclick") + "; calculateCraftSchedule();");
@ -177,7 +179,7 @@ function calculateCraft() {
//Display Craft Stats //Display Craft Stats
// displayCraftStats(player_craft, "craft-stats"); // displayCraftStats(player_craft, "craft-stats");
let mock_item = player_craft.statMap; let mock_item = player_craft.statMap;
apply_weapon_powders(mock_item); if (mock_item.get('category') === 'weapon') { apply_weapon_powders(mock_item) };
displayExpandedItem(mock_item, "craft-stats"); displayExpandedItem(mock_item, "craft-stats");
//Display Ingredients' Stats //Display Ingredients' Stats

View file

@ -1,4 +1,4 @@
const damageMultipliers = new Map([ ["allytotem", .15], ["yourtotem", .35], ["vanish", 0.80], ["warscream", 0.10], ["bash", 0.50] ]); const damageMultipliers = new Map([ ["allytotem", .15], ["yourtotem", .35], ["vanish", 0.80], ["warscream", 0.00], ["ragnarokkr", 0.30], ["fortitude", 0.60] ]);
function get_base_dps(item) { function get_base_dps(item) {
const attack_speed_mult = baseDamageMultiplier[attackSpeeds.indexOf(item.get("atkSpd"))]; const attack_speed_mult = baseDamageMultiplier[attackSpeeds.indexOf(item.get("atkSpd"))];
@ -26,7 +26,7 @@ function get_base_dps(item) {
} }
function calculateSpellDamage(stats, weapon, conversions, use_spell_damage, ignore_speed=false) { function calculateSpellDamage(stats, weapon, _conversions, use_spell_damage, ignore_speed=false, part_filter=undefined) {
// TODO: Roll all the loops together maybe // TODO: Roll all the loops together maybe
// Array of neutral + ewtfa damages. Each entry is a pair (min, max). // Array of neutral + ewtfa damages. Each entry is a pair (min, max).
@ -38,9 +38,30 @@ function calculateSpellDamage(stats, weapon, conversions, use_spell_damage, igno
else { else {
weapon_damages = damage_keys.map(x => weapon.get(x)); weapon_damages = damage_keys.map(x => weapon.get(x));
} }
let present = weapon.get(damage_present_key); let present = deepcopy(weapon.get(damage_present_key));
// Also theres prop and rainbow!!
const damage_elements = ['n'].concat(skp_elements); // netwfa
// 2. Conversions. // 2. Conversions.
// 2.0: First, modify conversions.
let conversions = deepcopy(_conversions);
if (part_filter !== undefined) {
const conv_postfix = ':'+part_filter;
for (let i in damage_elements) {
const stat_name = damage_elements[i]+'ConvBase'+conv_postfix;
if (stats.has(stat_name)) {
conversions[i] += stats.get(stat_name);
}
}
}
for (let i in damage_elements) {
const stat_name = damage_elements[i]+'ConvBase';
if (stats.has(stat_name)) {
conversions[i] += stats.get(stat_name);
}
}
// 2.1. First, apply neutral conversion (scale weapon damage). Keep track of total weapon damage here. // 2.1. First, apply neutral conversion (scale weapon damage). Keep track of total weapon damage here.
let damages = []; let damages = [];
const neutral_convert = conversions[0] / 100; const neutral_convert = conversions[0] / 100;
@ -56,7 +77,7 @@ function calculateSpellDamage(stats, weapon, conversions, use_spell_damage, igno
// 2.2. Next, apply elemental conversions using damage computed in step 1.1. // 2.2. Next, apply elemental conversions using damage computed in step 1.1.
// Also, track which elements are present. (Add onto those present in the weapon itself.) // Also, track which elements are present. (Add onto those present in the weapon itself.)
let total_convert = 0; //TODO get confirmation that this is how raw works. let total_convert = 0;
for (let i = 1; i <= 5; ++i) { for (let i = 1; i <= 5; ++i) {
if (conversions[i] > 0) { if (conversions[i] > 0) {
const conv_frac = conversions[i]/100; const conv_frac = conversions[i]/100;
@ -66,9 +87,7 @@ function calculateSpellDamage(stats, weapon, conversions, use_spell_damage, igno
total_convert += conv_frac total_convert += conv_frac
} }
} }
total_convert += conversions[0]/100;
// Also theres prop and rainbow!!
const damage_elements = ['n'].concat(skp_elements); // netwfa
if (!ignore_speed) { if (!ignore_speed) {
// 3. Apply attack speed multiplier. Ignored for melee single hit // 3. Apply attack speed multiplier. Ignored for melee single hit
@ -80,7 +99,7 @@ function calculateSpellDamage(stats, weapon, conversions, use_spell_damage, igno
} }
// 4. Add additive damage. TODO: Is there separate additive damage? // 4. Add additive damage. TODO: Is there separate additive damage?
for (let i = 0; i < 6; ++i) { for (let i in damage_elements) {
if (present[i]) { if (present[i]) {
damages[i][0] += stats.get(damage_elements[i]+'DamAddMin'); damages[i][0] += stats.get(damage_elements[i]+'DamAddMin');
damages[i][1] += stats.get(damage_elements[i]+'DamAddMax'); damages[i][1] += stats.get(damage_elements[i]+'DamAddMax');
@ -94,18 +113,19 @@ function calculateSpellDamage(stats, weapon, conversions, use_spell_damage, igno
} }
// 5.1: %boost application // 5.1: %boost application
let skill_boost = [0]; // no neutral skillpoint booster let skill_boost = [0]; // no neutral skillpoint booster
for (const skp of skp_order) { for (let i in skp_order) {
skill_boost.push(skillPointsToPercentage(stats.get(skp))); const skp = skp_order[i];
skill_boost.push(skillPointsToPercentage(stats.get(skp)) * skillpoint_damage_mult[i]);
} }
let static_boost = (stats.get(specific_boost_str.toLowerCase()+'Pct') + stats.get('damPct')) / 100; let static_boost = (stats.get(specific_boost_str.toLowerCase()+'Pct') + stats.get('damPct')) / 100;
// These do not count raw damage. I think. Easy enough to change // These do not count raw damage. I think. Easy enough to change
let total_min = 0; let total_min = 0;
let total_max = 0; let total_max = 0;
for (let i in damages) { for (let i in damage_elements) {
let damage_prefix = damage_elements[i] + specific_boost_str; let damage_specific = damage_elements[i] + specific_boost_str + 'Pct';
let damageBoost = 1 + skill_boost[i] + static_boost let damageBoost = 1 + skill_boost[i] + static_boost
+ ((stats.get(damage_prefix+'Pct') + stats.get(damage_elements[i]+'DamPct')) /100); + ((stats.get(damage_specific) + stats.get(damage_elements[i]+'DamPct')) /100);
damages[i][0] *= Math.max(damageBoost, 0); damages[i][0] *= Math.max(damageBoost, 0);
damages[i][1] *= Math.max(damageBoost, 0); damages[i][1] *= Math.max(damageBoost, 0);
// Collect total damage post %boost // Collect total damage post %boost
@ -131,13 +151,21 @@ function calculateSpellDamage(stats, weapon, conversions, use_spell_damage, igno
let min_boost = raw_boost; let min_boost = raw_boost;
let max_boost = raw_boost; let max_boost = raw_boost;
if (total_max > 0) { // TODO: what about total negative all raw? if (total_max > 0) { // TODO: what about total negative all raw?
if (total_elem_min > 0) { // TODO: compute actual chance of 0 damage. For now we just copy max ratio
if (total_min === 0) {
min_boost += (damages_obj[1] / total_max) * prop_raw;
}
else {
min_boost += (damages_obj[0] / total_min) * prop_raw; min_boost += (damages_obj[0] / total_min) * prop_raw;
} }
max_boost += (damages_obj[1] / total_max) * prop_raw; max_boost += (damages_obj[1] / total_max) * prop_raw;
} }
if (i != 0 && total_elem_max > 0) { // rainraw TODO above if (i != 0 && total_elem_max > 0) { // rainraw TODO above
if (total_elem_min > 0) { // TODO: compute actual chance of 0 damage. For now we just copy max ratio
if (total_elem_min === 0) {
min_boost += (damages_obj[1] / total_elem_max) * rainbow_raw;
}
else {
min_boost += (damages_obj[0] / total_elem_min) * rainbow_raw; min_boost += (damages_obj[0] / total_elem_min) * rainbow_raw;
} }
max_boost += (damages_obj[1] / total_elem_max) * rainbow_raw; max_boost += (damages_obj[1] / total_elem_max) * rainbow_raw;
@ -152,14 +180,27 @@ function calculateSpellDamage(stats, weapon, conversions, use_spell_damage, igno
let total_dam_norm = [0, 0]; let total_dam_norm = [0, 0];
let total_dam_crit = [0, 0]; let total_dam_crit = [0, 0];
let damages_results = []; let damages_results = [];
const damage_mult = stats.get("damageMultiplier"); const mult_map = stats.get("damMult");
let damage_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_filter) {
continue;
}
}
damage_mult *= (1 + v/100);
}
const crit_mult = stats.get("critDamPct")/100;
for (const damage of damages) { for (const damage of damages) {
const res = [ const res = [
damage[0] * strBoost * damage_mult, // Normal min damage[0] * strBoost * damage_mult, // Normal min
damage[1] * strBoost * damage_mult, // Normal max damage[1] * strBoost * damage_mult, // Normal max
damage[0] * (strBoost + 1) * damage_mult, // Crit min damage[0] * (strBoost + crit_mult) * damage_mult, // Crit min
damage[1] * (strBoost + 1) * damage_mult, // Crit max damage[1] * (strBoost + crit_mult) * damage_mult, // Crit max
]; ];
damages_results.push(res); damages_results.push(res);
total_dam_norm[0] += res[0]; total_dam_norm[0] += res[0];
@ -245,15 +286,6 @@ const default_spells = {
scaling: "melee", use_atkspd: false, scaling: "melee", use_atkspd: false,
display: "Melee", display: "Melee",
parts: [{ name: "Melee", multipliers: [100, 0, 0, 0, 0, 0] }] parts: [{ name: "Melee", multipliers: [100, 0, 0, 0, 0, 0] }]
}, {
name: "Heal", // TODO: name for melee attacks? // JUST FOR TESTING...
base_spell: 1,
display: "Total Heal",
parts: [
{ name: "First Pulse", power: 0.12 },
{ name: "Second and Third Pulses", power: 0.06 },
{ name: "Total Heal", hits: { "First Pulse": 1, "Second and Third Pulses": 2 } }
]
}], }],
spear: [{ spear: [{
type: "replace_spell", // not needed but makes this usable as an "abil part" type: "replace_spell", // not needed but makes this usable as an "abil part"
@ -294,130 +326,6 @@ const default_spells = {
}; };
const spell_table = { const spell_table = {
"wand": [
{ title: "Heal", cost: 6, parts: [
{ subtitle: "First Pulse", type: "heal", strength: 0.12 },
{ subtitle: "Second and Third Pulses", type: "heal", strength: 0.06 },
{ subtitle: "Total Heal", type: "heal", strength: 0.24, summary: true },
{ subtitle: "First Pulse (Ally)", type: "heal", strength: 0.20 },
{ subtitle: "Second and Third Pulses (Ally)", type: "heal", strength: 0.1 },
{ subtitle: "Total Heal (Ally)", type: "heal", strength: 0.4 }
] },
{ title: "Teleport", cost: 4, parts: [
{ subtitle: "Total Damage", type: "damage", multiplier: 150, conversion: [60, 0, 40, 0, 0, 0], summary: true },
] },
{ title: "Meteor", cost: 8, parts: [
{ subtitle: "Blast Damage", type: "damage", multiplier: 500, conversion: [40, 30, 0, 0, 30, 0], summary: true },
{ subtitle: "Burn Damage", type: "damage", multiplier: 125, conversion: [100, 0, 0, 0, 0, 0] },
] },
{ title: "Ice Snake", cost: 4, parts: [
{ subtitle: "Total Damage", type: "damage", multiplier: 70, conversion: [50, 0, 0, 50, 0, 0], summary: true },
] },
],
"spear": [
{ title: "Bash", cost: 6, parts: [
{ subtitle: "First Damage", type: "damage", multiplier: 130, conversion: [60, 40, 0, 0, 0, 0]},
{ subtitle: "Explosion Damage", type: "damage", multiplier: 130, conversion: [100, 0, 0, 0, 0, 0]},
{ subtitle: "Total Damage", type: "total", factors: [1, 1], summary: true },
] },
{ title: "Charge", cost: 4, variants: {
DEFAULT: [
{ subtitle: "Total Damage", type: "damage", multiplier: 150, conversion: [60, 0, 0, 0, 40, 0], summary: true }
],
RALLY: [
{ subtitle: "Self Heal", type: "heal", strength: 0.07, summary: true },
{ subtitle: "Ally Heal", type: "heal", strength: 0.15 }
]
} },
{ title: "Uppercut", cost: 9, parts: [
{ subtitle: "First Damage", type: "damage", multiplier: 300, conversion: [70, 20, 10, 0, 0, 0] },
{ subtitle: "Fireworks Damage", type: "damage", multiplier: 50, conversion: [60, 0, 40, 0, 0, 0] },
{ subtitle: "Crash Damage", type: "damage", multiplier: 50, conversion: [80, 0, 20, 0, 0, 0] },
{ subtitle: "Total Damage", type: "total", factors: [1, 1, 1], summary: true },
] },
{ title: "War Scream", cost: 6, parts: [
{ subtitle: "Area Damage", type: "damage", multiplier: 50, conversion: [0, 0, 0, 0, 75, 25], summary: true },
{ subtitle: "Air Shout (Per Hit)", type: "damage", multiplier: 30, conversion: [0, 0, 0, 0, 75, 25] },
] },
],
"bow": [
{ title: "Arrow Storm", cost: 6, variants: {
DEFAULT: [
{ subtitle: "Total Damage", type: "damage", multiplier: 600, conversion: [60, 0, 25, 0, 15, 0], summary: true },
{ subtitle: "Per Arrow (60)", type: "damage", multiplier: 10, conversion: [60, 0, 25, 0, 15, 0]}
],
HAWKEYE: [
{ subtitle: "Total Damage (Hawkeye)", type: "damage", multiplier: 400, conversion: [60, 0, 25, 0, 15, 0], summary: true },
{ subtitle: "Per Arrow (5)", type: "damage", multiplier: 80, conversion: [60, 0, 25, 0, 15, 0]}
],
} },
{ title: "Escape", cost: 3, parts: [
{ subtitle: "Landing Damage", type: "damage", multiplier: 100, conversion: [50, 0, 0, 0, 0, 50], summary: true },
] },
{ title: "Bomb Arrow", cost: 8, parts: [
{ subtitle: "Total Damage", type: "damage", multiplier: 250, conversion: [60, 25, 0, 0, 15, 0], summary: true },
] },
{ title: "Arrow Shield", cost: 10, parts: [
{ subtitle: "Shield Damage", type: "damage", multiplier: 100, conversion: [70, 0, 0, 0, 0, 30], summary: true },
{ subtitle: "Arrow Rain Damage", type: "damage", multiplier: 200, conversion: [70, 0, 0, 0, 0, 30] },
] },
],
"dagger": [
{ title: "Spin Attack", cost: 6, parts: [
{ subtitle: "Total Damage", type: "damage", multiplier: 150, conversion: [70, 0, 30, 0, 0, 0], summary: true},
] },
{ title: "Vanish", cost: 2, parts: [
{ subtitle: "No Damage", type: "none", summary: true }
] },
{ title: "Multihit", cost: 8, parts: [
{ subtitle: "1st to 10th Hit", type: "damage", multiplier: 27, conversion: [100, 0, 0, 0, 0, 0] },
{ subtitle: "Fatality", type: "damage", multiplier: 120, conversion: [20, 0, 30, 50, 0, 0] },
{ subtitle: "Total Damage", type: "total", factors: [10, 1], summary: true },
] },
{ title: "Smoke Bomb", cost: 8, variants: {
DEFAULT: [
{ subtitle: "Tick Damage (10 max)", type: "damage", multiplier: 60, conversion: [50, 25, 0, 0, 0, 25] },
{ subtitle: "Total Damage", type: "damage", multiplier: 600, conversion: [50, 25, 0, 0, 0, 25], summary: true },
],
CHERRY_BOMBS: [
{ subtitle: "Total Damage (Cherry Bombs)", type: "damage", multiplier: 330, conversion: [50, 25, 0, 0, 0, 25], summary: true },
{ subtitle: "Per Bomb", type: "damage", multiplier: 110, conversion: [50, 25, 0, 0, 0, 25] }
]
} },
],
"relik": [
{ title: "Totem", cost: 4, parts: [
{ subtitle: "Smash Damage", type: "damage", multiplier: 100, conversion: [80, 0, 0, 0, 20, 0]},
{ subtitle: "Damage Tick", type: "damage", multiplier: 20, conversion: [80, 0, 0, 0, 0, 20]},
{ subtitle: "Heal Tick", type: "heal", strength: 0.03, summary: true },
] },
{ title: "Haul", cost: 1, parts: [
{ subtitle: "Total Damage", type: "damage", multiplier: 100, conversion: [80, 0, 20, 0, 0, 0], summary: true },
] },
{ title: "Aura", cost: 8, parts: [
{ subtitle: "One Wave", type: "damage", multiplier: 200, conversion: [70, 0, 0, 30, 0, 0], summary: true },
] },
{ title: "Uproot", cost: 6, parts: [
{ subtitle: "Total Damage", type: "damage", multiplier: 100, conversion: [70, 30, 0, 0, 0, 0], summary: true },
] },
],
"sword": [
{ title: "Successive Strikes", cost: 5, parts: [
{ subtitle: "Damage", type: "damage", multiplier: 65, conversion: [70, 0, 15, 0, 0, 15]},
{ subtitle: "Final Strike", type: "damage", multiplier: 120, conversion: [70, 0, 15, 0, 0, 15]},
{ subtitle: "Total Damage (Normal)", type: "total", factors: [2, 0], summary: true },
] },
{ title: "Dash", cost: 3, parts: [
{ subtitle: "Damage", type: "damage", multiplier: 120, conversion: [60, 0, 0, 0, 0, 40], summary: true },
] },
{ title: "Execute", cost: 8, parts: [
{ subtitle: "Minimum Damage", type: "damage", multiplier: 100, conversion: [60, 0, 20, 0, 20, 0]},
{ subtitle: "Maximum Damage", type: "damage", multiplier: 1200, conversion: [60, 0, 20, 0, 20, 0], summary: true },
] },
{ title: "Blade Echo", cost: 4, parts: [
{ subtitle: "Damage", type: "damage", multiplier: 125, conversion: [60, 0, 0, 20, 0, 20], summary: true },
] },
],
"powder": [ //This is how instant-damage powder specials are implemented. "powder": [ //This is how instant-damage powder specials are implemented.
{ title: "Quake", cost: 0, parts:[ { 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}, { subtitle: "Total Damage", type: "damage", multiplier: [155, 220, 285, 350, 415], conversion: [0,100,0,0,0,0], summary: true},

View file

@ -5,13 +5,10 @@ function apply_elemental_format(p_elem, id, suffix) {
let parts = idPrefixes[id].split(/ (.*)/); let parts = idPrefixes[id].split(/ (.*)/);
let element_prefix = parts[0]; let element_prefix = parts[0];
let desc = parts[1]; let desc = parts[1];
let i_elem = document.createElement('span'); let i_elem = make_elem('span', [element_prefix], {textContent: element_prefix});
i_elem.classList.add(element_prefix);
i_elem.textContent = element_prefix;
p_elem.appendChild(i_elem); p_elem.appendChild(i_elem);
let i_elem2 = document.createElement('span'); let i_elem2 = make_elem('span', [], {textContent: " "+desc+suffix});
i_elem2.textContent = " " + desc + suffix;
p_elem.appendChild(i_elem2); p_elem.appendChild(i_elem2);
} }
@ -19,17 +16,14 @@ function displaySetBonuses(parent_id,build) {
setHTML(parent_id, ""); setHTML(parent_id, "");
let parent_div = document.getElementById(parent_id); let parent_div = document.getElementById(parent_id);
let set_summary_elem = document.createElement('p'); let set_summary_elem = make_elem('p', ['text-center'], {textContent: "Set Bonuses"});
set_summary_elem.classList.add('text-center');
set_summary_elem.textContent = "Set Bonuses";
parent_div.append(set_summary_elem); parent_div.append(set_summary_elem);
for (const [setName, count] of build.activeSetCounts) { for (const [setName, count] of build.activeSetCounts) {
const active_set = sets.get(setName); const active_set = sets.get(setName);
if (active_set["hidden"]) { continue; } if (active_set["hidden"]) { continue; }
let set_elem = document.createElement('p'); let set_elem = make_elem('p', [], {id: "set-"+setName});
set_elem.id = "set-"+setName;
set_summary_elem.append(set_elem); set_summary_elem.append(set_elem);
const bonus = active_set.bonuses[count-1]; const bonus = active_set.bonuses[count-1];
@ -111,36 +105,28 @@ function displayBuildStats(parent_id,build,command_group,stats){
} }
displayFixedID(parent_div, id, id_val, elemental_format, style); displayFixedID(parent_div, id, id_val, elemental_format, style);
if (id === "poison" && id_val > 0) { if (id === "poison" && id_val > 0) {
let row = document.createElement('div'); let row = make_elem('div', ['row']);
row.classList.add("row") let value_elem = make_elem('div', ['col', 'text-end']);
let value_elem = document.createElement('div');
value_elem.classList.add('col');
value_elem.classList.add('text-end');
let prefix_elem = document.createElement('b'); let prefix_elem = make_elem('b', [], {textContent: "\u279C With Strength: "});
prefix_elem.textContent = "\u279C With Strength: "; let number_elem = make_elem('b', [style], {
let number_elem = document.createElement('b'); textContent: (id_val * (1+skillPointsToPercentage(stats.get('str'))) ).toFixed(0) + idSuffixes[id]
number_elem.classList.add(style); });
number_elem.textContent = (id_val * (1+skillPointsToPercentage(stats.get('str'))) ).toFixed(0) + idSuffixes[id];
value_elem.append(prefix_elem); value_elem.append(prefix_elem);
value_elem.append(number_elem); value_elem.append(number_elem);
row.appendChild(value_elem); row.appendChild(value_elem);
parent_div.appendChild(row); parent_div.appendChild(row);
} }
else if (id === "ls" && id_val != 0) { else if (id === "ls" && id_val != 0) {
let row = document.createElement('div'); let row = make_elem('div', ['row']);
row.classList.add("row") let value_elem = make_elem('div', ['col', 'text-end']);
let value_elem = document.createElement('div');
value_elem.classList.add('col');
value_elem.classList.add('text-end');
let prefix_elem = document.createElement('b'); let prefix_elem = make_elem('b', [], {textContent: "\u279C Effective LS: "});
prefix_elem.textContent = "\u279C Effective LS: ";
let defStats = getDefenseStats(stats); let defStats = getDefenseStats(stats);
let number_elem = document.createElement('b'); let number_elem = make_elem('b', [style], {
number_elem.classList.add(style); textContent: Math.round(defStats[1][0]*id_val/defStats[0]) + "/3s"
number_elem.textContent = Math.round(defStats[1][0]*id_val/defStats[0]) + "/3s"; });
value_elem.append(prefix_elem); value_elem.append(prefix_elem);
value_elem.append(number_elem); value_elem.append(number_elem);
row.appendChild(value_elem); row.appendChild(value_elem);
@ -195,8 +181,7 @@ function displayExpandedItem(item, parent_id){
elemental_format = !elemental_format; elemental_format = !elemental_format;
} }
else if (command === "!spacer") { else if (command === "!spacer") {
let spacer = document.createElement('div'); let spacer = make_elem('div', ["row", "my-2"], {});
spacer.classList.add("row", "my-2");
parent_div.appendChild(spacer); parent_div.appendChild(spacer);
continue; continue;
} }
@ -205,49 +190,41 @@ function displayExpandedItem(item, parent_id){
let id = command; let id = command;
if(nonRolledIDs.includes(id)){//nonRolledID & non-0/non-null/non-und ID if(nonRolledIDs.includes(id)){//nonRolledID & non-0/non-null/non-und ID
if (!item.get(id)) { if (!item.get(id)) {
if (! (item.get("crafted") && skp_order.includes(id) && if (!(item.get("crafted") && skp_order.includes(id) &&
(item.get("maxRolls").get(id) || item.get("minRolls").get(id)))) { (item.get("maxRolls").get(id) || item.get("minRolls").get(id)))) {
continue; continue;
} }
} }
if (id === "slots") { if (id === "slots") {
let p_elem = document.createElement("div"); let p_elem = make_elem("div", ["col"]);
p_elem.classList.add("col");
// PROPER POWDER DISPLAYING // PROPER POWDER DISPLAYING
let numerals = new Map([[1, "I"], [2, "II"], [3, "III"], [4, "IV"], [5, "V"], [6, "VI"]]); let numerals = new Map([[1, "I"], [2, "II"], [3, "III"], [4, "IV"], [5, "V"], [6, "VI"]]);
let powderPrefix = document.createElement("b"); p_elem.appendChild(make_elem("b", [], {
powderPrefix.textContent = "Powder Slots: " + item.get(id) + " ["; textContent: "Powder Slots: " + item.get(id) + " ["
p_elem.appendChild(powderPrefix); }));
let powders = item.get("powders"); let powders = item.get("powders");
for (let i = 0; i < powders.length; i++) { for (let i = 0; i < powders.length; i++) {
let powder = document.createElement("b"); p_elem.appendChild(make_elem("b", [damageClasses[Math.floor(powders[i]/6)+1]+"_powder"], {
powder.textContent = numerals.get((powders[i]%6)+1)+" "; textContent: numerals.get((powders[i]%6)+1)+" "
powder.classList.add(damageClasses[Math.floor(powders[i]/6)+1]+"_powder"); }));
p_elem.appendChild(powder);
} }
let powderSuffix = document.createElement("b"); p_elem.appendChild(make_elem("b", [], { textContent: "]" }));
powderSuffix.textContent = "]";
p_elem.appendChild(powderSuffix);
parent_div.appendChild(p_elem); parent_div.appendChild(p_elem);
} else if (id === "set") { } else if (id === "set") {
if (item.get("hideSet")) { continue; } if (item.get("hideSet")) { continue; }
let p_elem = document.createElement("div"); parent_div.appendChild(make_elem("div", ["col"], { textContent: "Set: " + item.get(id).toString() }));
p_elem.classList.add("col");
p_elem.textContent = "Set: " + item.get(id).toString();
parent_div.appendChild(p_elem);
} else if (id === "majorIds") { } else if (id === "majorIds") {
//console.log(item.get(id)); //console.log(item.get(id));
for (let majorID of item.get(id)) { for (let majorID of item.get(id)) {
let p_elem = document.createElement("div"); let p_elem = make_elem("div", ['col']);
p_elem.classList.add("col");
let title_elem = document.createElement("b"); let title_elem = make_elem("b");
let b_elem = document.createElement("b"); let b_elem = make_elem("b");
if (majorID.includes(":")) { if (majorID.includes(":")) {
let name = majorID.substring(0, majorID.indexOf(":")+1); let name = majorID.substring(0, majorID.indexOf(":")+1);
let mid = majorID.substring(majorID.indexOf(":")+1); let mid = majorID.substring(majorID.indexOf(":")+1);
@ -268,20 +245,30 @@ function displayExpandedItem(item, parent_id){
parent_div.appendChild(p_elem); parent_div.appendChild(p_elem);
} }
} else if (id === "lvl" && item.get("tier") === "Crafted") { } else if (id === "lvl" && item.get("tier") === "Crafted") {
let p_elem = document.createElement("div"); parent_div.appendChild(make_elem("div", ["col"], {
p_elem.classList.add("col"); textContent: "Combat Level Min: " + item.get("lvlLow") + "-" + item.get(id)
p_elem.textContent = "Combat Level Min: " + item.get("lvlLow") + "-" + item.get(id); }));
parent_div.appendChild(p_elem);
} else if (id === "displayName") { } else if (id === "displayName") {
let row = document.createElement("div"); let row = make_elem("div", ["row", "justify-content-center"]);
let a_elem = document.createElement("a"); let nolink_row = make_elem("div", ["row", "justify-content-center"]);
row.classList.add("row", "justify-content-center"); nolink_row.style.display = "none";
a_elem.classList.add("col-auto", "text-center", "item-title", "p-0");
a_elem.classList.add(item.has("tier") ? item.get("tier").replace(" ","") : "Normal"); const tier_class = item.has("tier") ? item.get("tier").replace(" ","") : "Normal";
// a_elem.style.textGrow = 1; let item_link;
if (item.get("custom")) {
row.appendChild(a_elem); item_link = "../custom/#" + item.get("hash");
} else if (item.get("crafted")) {
a_item_link = "../crafter/#" + item.get("hash");
} else {
item_link = "../item/#" + item.get("displayName");
}
const item_name_elem = make_elem("a", ["col-auto", "text-center", "item-title", "p-0", tier_class], {
textContent: item.get('displayName')
});
nolink_row.appendChild(item_name_elem.cloneNode(true));
item_name_elem.href = item_link;
row.appendChild(item_name_elem);
/* /*
FUNCTIONALITY FOR THIS FEATURE HAS SINCE BEEN REMOVED (WITH SQ2). FUNCTIONALITY FOR THIS FEATURE HAS SINCE BEEN REMOVED (WITH SQ2).
@ -295,50 +282,23 @@ function displayExpandedItem(item, parent_id){
//plusminus.style.flexGrow = 0; //plusminus.style.flexGrow = 0;
//plusminus.textContent = "\u2795"; //plusminus.textContent = "\u2795";
//row.appendChild(plusminus); //row.appendChild(plusminus);
if (item.get("custom")) {
a_elem.href = "../custom/#" + item.get("hash");
a_elem.textContent = item.get("displayName");
} else if (item.get("crafted")) {
a_elem.href = "../crafter/#" + item.get("hash");
a_elem.textContent = item.get(id);
} else {
a_elem.href = "../item/#" + item.get("displayName");
a_elem.textContent = item.get("displayName");
}
parent_div.appendChild(row); parent_div.appendChild(row);
let nolink_row = document.createElement("div");
let p_elem = document.createElement("p");
nolink_row.classList.add("row", "justify-content-center");
nolink_row.style.display = "none";
p_elem.classList.add("col-auto", "text-center", "item-title", "p-0");
p_elem.classList.add(item.has("tier") ? item.get("tier").replace(" ","") : "Normal");
if (item.get("custom")) {
p_elem.textContent = item.get("displayName");
} else if (item.get("crafted")) {
p_elem.textContent = item.get(id);
} else {
p_elem.textContent = item.get("displayName");
}
nolink_row.appendChild(p_elem);
parent_div.appendChild(nolink_row); parent_div.appendChild(nolink_row);
let img = document.createElement("img"); if (item.has("type")) {
if (item && item.has("type")) { let img = make_elem("img", [], {
img.src = "../media/items/" + (newIcons ? "new/":"old/") + "generic-" + item.get("type") + ".png"; src: "../media/items/" + (newIcons ? "new/":"old/") + "generic-" + item.get("type") + ".png",
img.alt = item.get("type"); alt: item.get("type"),
img.style = " z=index: 1; position: relative;"; style: " z=index: 1; position: relative;"
let container = document.createElement("div"); });
let container = make_elem("div");
let bckgrd = document.createElement("div"); let bckgrd = make_elem("div", ["col", "px-0", "d-flex", "align-items-center", "justify-content-center", 'scaled-bckgrd'], { // , "no-collapse"
bckgrd.classList.add("col", "px-0", "d-flex", "align-items-center", "justify-content-center");// , "no-collapse"); style: "border-radius: 50%;background-image: radial-gradient(closest-side, " + colorMap.get(item.get("tier")) + " 20%," + "hsl(0, 0%, 16%) 80%); margin-left: auto; margin-right: auto;"
bckgrd.style = "border-radius: 50%;background-image: radial-gradient(closest-side, " + colorMap.get(item.get("tier")) + " 20%," + "hsl(0, 0%, 16%) 80%); margin-left: auto; margin-right: auto;" });
bckgrd.classList.add("scaled-bckgrd");
parent_div.appendChild(container);
container.appendChild(bckgrd);
bckgrd.appendChild(img); bckgrd.appendChild(img);
container.appendChild(bckgrd);
parent_div.appendChild(container);
} }
} else { } else {
if (id.endsWith('Dam_')) { if (id.endsWith('Dam_')) {
@ -365,8 +325,7 @@ function displayExpandedItem(item, parent_id){
p_elem.style = "font-style: italic"; p_elem.style = "font-style: italic";
} else if (skp_order.includes(id)) { //id = str, dex, int, def, or agi } else if (skp_order.includes(id)) { //id = str, dex, int, def, or agi
if ( item.get("tier") !== "Crafted") { if ( item.get("tier") !== "Crafted") {
row = document.createElement("div"); row = make_elem("div", ["col"]);
row.classList.add("col");
let title = document.createElement("b"); let title = document.createElement("b");
title.textContent = idPrefixes[id] + " "; title.textContent = idPrefixes[id] + " ";
@ -550,9 +509,6 @@ function displayExpandedItem(item, parent_id){
*/ */
function displayRecipeStats(craft, parent_id) { function displayRecipeStats(craft, parent_id) {
let elem = document.getElementById(parent_id); let elem = document.getElementById(parent_id);
if (!elem.classList.contains("col")) {
elem.classList.add("col");
}
//local vars //local vars
elem.textContent = ""; elem.textContent = "";
@ -565,91 +521,85 @@ function displayRecipeStats(craft, parent_id) {
let effectiveness = craft["statMap"].get("ingredEffectiveness"); let effectiveness = craft["statMap"].get("ingredEffectiveness");
let title = document.createElement("div"); let title = document.createElement("div");
title.classList.add("row", "box-title", "fw-bold", "justify-content-center"); title.classList.add("col", "box-title", "fw-bold", "justify-content-center", "scaled-font");
title.textContent = "Recipe Stats"; title.textContent = "Recipe Stats";
elem.appendChild(title); elem.appendChild(title);
let mats = document.createElement("div"); let mats = document.createElement("div");
mats.classList.add("row"); mats.classList.add("col");
mats.textContent = "Crafting Materials: "; mats.textContent = "Crafting Materials: ";
elem.appendChild(mats); elem.appendChild(mats);
for (let i = 0; i < 2; i++) { for (let i = 0; i < 2; i++) {
let tier = mat_tiers[i]; let tier = mat_tiers[i];
let row = document.createElement("div"); let col = document.createElement("div");
row.classList.add("row", "px-0", "mx-0"); col.classList.add("col", "ps-4");
let b = document.createElement("div"); let b = document.createElement("span");
let mat = recipe.get("materials")[i]; let mat = recipe.get("materials")[i];
b.textContent = "- " + mat.get("amount") + "x " + mat.get("item").split(" ").slice(1).join(" "); b.textContent = "- " + mat.get("amount") + "x " + mat.get("item").split(" ").slice(1).join(" ");
b.classList.add("col"); b.classList.add("col");
row.appendChild(b); col.appendChild(b);
let starsB = document.createElement("div"); let starsContainer = document.createElement("span");
starsB.classList.add("T1-bracket", "col-auto", "px-0"); let starsB = document.createElement("span");
starsB.classList.add("T1-bracket", "px-0");
starsB.textContent = "["; starsB.textContent = "[";
row.appendChild(starsB); starsContainer.appendChild(starsB);
for(let j = 0; j < 3; j ++) { for(let j = 0; j < 3; j ++) {
let star = document.createElement("div"); let star = document.createElement("span");
star.classList.add("col-auto", "px-0"); star.classList.add("px-0");
star.textContent = "\u272B"; star.textContent = "\u272B";
if(j < tier) { if(j < tier) {
star.classList.add("T1"); star.classList.add("T1");
} else { } else {
star.classList.add("T0"); star.classList.add("T0");
} }
row.append(star); starsContainer.append(star);
} }
let starsE = document.createElement("div"); let starsE = document.createElement("span");
starsE.classList.add("T1-bracket", "col-auto", "px-0"); starsE.classList.add("T1-bracket", "px-0");
starsE.textContent = "]"; starsE.textContent = "]";
row.appendChild(starsE); starsContainer.appendChild(starsE);
elem.appendChild(row); col.appendChild(starsContainer);
elem.appendChild(col);
} }
let ingredTable = document.createElement("div"); let ingredTable = document.createElement("div");
ingredTable.classList.add("row"); ingredTable.classList.add("col", "mt-2");
for (let i = 0; i < 3; i++) { let ingredContainer = document.createElement("div");
let row = document.createElement("div"); ingredContainer.classList.add("row", "row-cols-2", "g-3");
row.classList.add("row", "g-1", "justify-content-center"); for (let i = 0; i < 6; i++) {
let ingredCell = document.createElement("div");
ingredCell.classList.add("col");
let ingredTextContainer = document.createElement("div");
for (let j = 0; j < 2; j++) { ingredTextContainer.classList.add("border", "border-3", "rounded")
if (j == 1) {
let spacer = document.createElement("div");
spacer.classList.add("col-1");
row.appendChild(spacer);
}
let ingredName = ingreds[2 * i + j];
let col = document.createElement("div");
col.classList.add("col-5", "rounded", "dark-6", "border", "border-3", "dark-shadow");
let temp_row = document.createElement("div"); let ingredName = ingreds[i];
temp_row.classList.add("row"); let ingred_text = document.createElement("p");
col.appendChild(temp_row); ingred_text.classList.add("mb-2", "ps-2");
ingred_text.textContent = ingredName;
ingredTextContainer.appendChild(ingred_text);
let ingred_div = document.createElement("div"); let eff_div = document.createElement("p");
ingred_div.classList.add("col"); eff_div.classList.add("mb-2", "ps-2");
ingred_div.textContent = ingredName; let e = effectiveness[i];
temp_row.appendChild(ingred_div); if (e > 0) {
eff_div.classList.add("positive");
let eff_div = document.createElement("div"); } else if (e < 0) {
eff_div.classList.add("col-auto"); eff_div.classList.add("negative");
let e = effectiveness[2 * i + j];
if (e > 0) {
eff_div.classList.add("positive");
} else if (e < 0) {
eff_div.classList.add("negative");
}
eff_div.textContent = "[" + e + "%]";
temp_row.appendChild(eff_div);
row.appendChild(col);
} }
ingredTable.appendChild(row); eff_div.textContent = "[" + e + "%]";
ingredTextContainer.appendChild(eff_div);
ingredCell.appendChild(ingredTextContainer);
ingredContainer.appendChild(ingredCell);
} }
ingredTable.appendChild(ingredContainer);
elem.appendChild(ingredTable); elem.appendChild(ingredTable);
} }
@ -877,7 +827,7 @@ function displayExpandedIngredient(ingred, parent_id) {
row.appendChild(title); row.appendChild(title);
for(const skill of ingred.get("skills")) { for(const skill of ingred.get("skills")) {
let skill_div = document.createElement("div"); let skill_div = document.createElement("div");
skill_div.classList.add("row"); skill_div.classList.add("row", "ps-4");
skill_div.textContent = skill.charAt(0) + skill.substring(1).toLowerCase(); skill_div.textContent = skill.charAt(0) + skill.substring(1).toLowerCase();
row.appendChild(skill_div); row.appendChild(skill_div);
} }
@ -1039,23 +989,30 @@ function displayFixedID(active, id, value, elemental_format, style) {
function displayPoisonDamage(overallparent_elem, build) { function displayPoisonDamage(overallparent_elem, build) {
overallparent_elem.textContent = ""; overallparent_elem.textContent = "";
if (build.statMap.get('poison') <= 0) {
overallparent_elem.style = "display: none";
return;
}
overallparent_elem.style = "";
let container = make_elem('div', ['col', 'pe-0']);
let spell_summary = make_elem('div', ["col", "spell-display", "dark-5", "rounded", "dark-shadow", "py-2", "border", "border-dark"]);
//Title //Title
let title_elemavg = document.createElement("b"); let title_elemavg = make_elem("b");
title_elemavg.textContent = "Poison Stats"; title_elemavg.append(make_elem('span', [], { textContent: "Poison Stats" }));
overallparent_elem.append(title_elemavg); spell_summary.append(title_elemavg);
let overallpoisonDamage = document.createElement("p");
let overallpoisonDamageFirst = document.createElement("span");
let overallpoisonDamageSecond = document.createElement("span");
let poison_tick = Math.ceil(build.statMap.get("poison") * (1+skillPointsToPercentage(build.total_skillpoints[0])) * (build.statMap.get("poisonPct"))/100 /3); let poison_tick = Math.ceil(build.statMap.get("poison") * (1+skillPointsToPercentage(build.total_skillpoints[0])) * (build.statMap.get("poisonPct"))/100 /3);
overallpoisonDamageFirst.textContent = "Poison Tick: ";
overallpoisonDamageSecond.textContent = Math.max(poison_tick,0);
overallpoisonDamageSecond.classList.add("Damage");
overallpoisonDamage.appendChild(overallpoisonDamageFirst); let overallpoisonDamage = make_elem("p");
overallpoisonDamage.appendChild(overallpoisonDamageSecond); overallpoisonDamage.append(
overallparent_elem.append(overallpoisonDamage); make_elem("span", [], { textContent: "Poison Tick: " }),
make_elem("span", ["Damage"], { textContent: Math.max(poison_tick,0) })
);
spell_summary.append(overallpoisonDamage);
container.append(spell_summary);
overallparent_elem.append(container);
} }
function displayEquipOrder(parent_elem, buildOrder){ function displayEquipOrder(parent_elem, buildOrder){
@ -1072,152 +1029,6 @@ function displayEquipOrder(parent_elem, buildOrder){
} }
} }
function displayMeleeDamage(parent_elem, overallparent_elem, meleeStats) {
let attackSpeeds = ["Super Slow", "Very Slow", "Slow", "Normal", "Fast", "Very Fast", "Super Fast"];
//let damagePrefixes = ["Neutral Damage: ","Earth Damage: ","Thunder Damage: ","Water Damage: ","Fire Damage: ","Air Damage: "];
parent_elem.textContent = "";
overallparent_elem.textContent = "";
const stats = meleeStats.slice();
for (let i = 0; i < 6; ++i) {
for (let j in stats[i]) {
stats[i][j] = stats[i][j].toFixed(2);
}
}
for (let i = 6; i < 8; ++i) {
for (let j = 0; j < 2; j++) {
stats[i][j] = stats[i][j].toFixed(2);
}
}
for (let i = 8; i < 11; ++i) {
stats[i] = stats[i].toFixed(2);
}
//title
let title_elem = document.createElement("p");
title_elem.classList.add("title");
title_elem.textContent = "Melee Stats";
parent_elem.append(title_elem);
parent_elem.append(document.createElement("br"));
//overall title
let title_elemavg = document.createElement("b");
title_elemavg.textContent = "Melee Stats";
overallparent_elem.append(title_elemavg);
//average DPS
let averageDamage = document.createElement("p");
averageDamage.classList.add("left");
averageDamage.textContent = "Average DPS: " + stats[10];
parent_elem.append(averageDamage);
//overall average DPS
let overallaverageDamage = document.createElement("p");
let overallaverageDamageFirst = document.createElement("span");
overallaverageDamageFirst.textContent = "Average DPS: "
let overallaverageDamageSecond = document.createElement("span");
overallaverageDamageSecond.classList.add("Damage");
overallaverageDamageSecond.textContent = stats[10];
overallaverageDamage.appendChild(overallaverageDamageFirst);
overallaverageDamage.appendChild(overallaverageDamageSecond);
overallparent_elem.append(overallaverageDamage);
//overallparent_elem.append(document.createElement("br"));
//attack speed
let atkSpd = document.createElement("p");
atkSpd.classList.add("left");
atkSpd.textContent = "Attack Speed: " + attackSpeeds[stats[11]];
parent_elem.append(atkSpd);
parent_elem.append(document.createElement("br"));
//overall attack speed
let overallatkSpd = document.createElement("p");
let overallatkSpdFirst = document.createElement("span");
overallatkSpdFirst.textContent = "Attack Speed: ";
let overallatkSpdSecond = document.createElement("span");
overallatkSpdSecond.classList.add("Damage");
overallatkSpdSecond.textContent = attackSpeeds[stats[11]];
overallatkSpd.appendChild(overallatkSpdFirst);
overallatkSpd.appendChild(overallatkSpdSecond);
overallparent_elem.append(overallatkSpd);
//Non-Crit: n->elem, total dmg, DPS
let nonCritStats = document.createElement("p");
nonCritStats.classList.add("left");
nonCritStats.textContent = "Non-Crit Stats: ";
nonCritStats.append(document.createElement("br"));
for (let i = 0; i < 6; i++) {
if (stats[i][1] != 0) {
let dmg = document.createElement("p");
dmg.textContent = stats[i][0] + " \u2013 " + stats[i][1];
dmg.classList.add(damageClasses[i]);
dmg.classList.add("itemp");
nonCritStats.append(dmg);
}
}
let normalDamage = document.createElement("p");
normalDamage.textContent = "Total: " + stats[6][0] + " \u2013 " + stats[6][1];
nonCritStats.append(normalDamage);
let normalDPS = document.createElement("p");
normalDPS.textContent = "Normal DPS: " + stats[8];
nonCritStats.append(normalDPS);
//overall average DPS
let singleHitDamage = document.createElement("p");
let singleHitDamageFirst = document.createElement("span");
singleHitDamageFirst.textContent = "Single Hit Average: ";
let singleHitDamageSecond = document.createElement("span");
singleHitDamageSecond.classList.add("Damage");
singleHitDamageSecond.textContent = stats[12].toFixed(2);
singleHitDamage.appendChild(singleHitDamageFirst);
singleHitDamage.appendChild(singleHitDamageSecond);
overallparent_elem.append(singleHitDamage);
let normalChance = document.createElement("p");
normalChance.textContent = "Non-Crit Chance: " + (stats[6][2]*100).toFixed(2) + "%";
normalChance.append(document.createElement("br"));
normalChance.append(document.createElement("br"));
nonCritStats.append(normalChance);
parent_elem.append(nonCritStats);
parent_elem.append(document.createElement("br"));
//Crit: n->elem, total dmg, DPS
let critStats = document.createElement("p");
critStats.classList.add("left");
critStats.textContent = "Crit Stats: ";
critStats.append(document.createElement("br"));
for (let i = 0; i < 6; i++){
if(stats[i][3] != 0) {
dmg = document.createElement("p");
dmg.textContent = stats[i][2] + " \u2013 " + stats[i][3];
dmg.classList.add(damageClasses[i]);
dmg.classList.add("itemp");
critStats.append(dmg);
}
}
let critDamage = document.createElement("p");
critDamage.textContent = "Total: " + stats[7][0] + " \u2013 " + stats[7][1];
critStats.append(critDamage);
let critDPS = document.createElement("p");
critDPS.textContent = "Crit DPS: " + stats[9];
critStats.append(critDPS);
let critChance = document.createElement("p");
critChance.textContent = "Crit Chance: " + (stats[7][2]*100).toFixed(2) + "%";
critChance.append(document.createElement("br"));
critChance.append(document.createElement("br"));
critStats.append(critChance);
parent_elem.append(critStats);
addClickableArrow(overallparent_elem, parent_elem);
}
function displayDefenseStats(parent_elem, statMap, insertSummary){ function displayDefenseStats(parent_elem, statMap, insertSummary){
let defenseStats = getDefenseStats(statMap); let defenseStats = getDefenseStats(statMap);
insertSummary = (typeof insertSummary !== 'undefined') ? insertSummary : false; insertSummary = (typeof insertSummary !== 'undefined') ? insertSummary : false;
@ -1424,6 +1235,13 @@ function displayDefenseStats(parent_elem, statMap, insertSummary){
} }
function displayPowderSpecials(parent_elem, powderSpecials, stats, weapon, overall=false) { function displayPowderSpecials(parent_elem, powderSpecials, stats, weapon, overall=false) {
parent_elem.textContent = "";
if (powderSpecials.length === 0) {
parent_elem.style = "display: none";
return;
}
parent_elem.style = "";
const skillpoints = [ const skillpoints = [
stats.get('str'), stats.get('str'),
stats.get('dex'), stats.get('dex'),
@ -1431,16 +1249,13 @@ function displayPowderSpecials(parent_elem, powderSpecials, stats, weapon, overa
stats.get('def'), stats.get('def'),
stats.get('agi') stats.get('agi')
]; ];
parent_elem.textContent = "" parent_elem.append(make_elem("b", [], { textContent: "Powder Specials" }));
let title = document.createElement("b");
title.textContent = "Powder Specials";
parent_elem.appendChild(title);
let specials = powderSpecials.slice(); let specials = powderSpecials.slice();
let expandedStats = new Map(); let expandedStats = new Map();
//each entry of powderSpecials is [ps, power] //each entry of powderSpecials is [ps, power]
for (special of specials) { for (special of specials) {
//iterate through the special and display its effects. //iterate through the special and display its effects.
let powder_special = document.createElement("p"); let powder_special = make_elem("p", ["pt-3"]);
let specialSuffixes = new Map([ ["Duration", " sec"], ["Radius", " blocks"], ["Chains", ""], ["Damage", "%"], ["Damage Boost", "%"], ["Knockback", " blocks"] ]); let specialSuffixes = new Map([ ["Duration", " sec"], ["Radius", " blocks"], ["Chains", ""], ["Damage", "%"], ["Damage Boost", "%"], ["Knockback", " blocks"] ]);
let specialTitle = document.createElement("p"); let specialTitle = document.createElement("p");
let specialEffects = document.createElement("p"); let specialEffects = document.createElement("p");
@ -1572,7 +1387,7 @@ function getSpellCost(stats, spell) {
function getBaseSpellCost(stats, spell) { function getBaseSpellCost(stats, spell) {
// old intelligence: // old intelligence:
let cost = spell.cost; //Math.ceil(spell.cost * (1 - skillPointsToPercentage(stats.get('int')))); let cost = Math.ceil(spell.cost * (1 - skillPointsToPercentage(stats.get('int')) * skillpoint_final_mult[2]));
cost += stats.get("spRaw"+spell.base_spell); cost += stats.get("spRaw"+spell.base_spell);
return Math.floor(cost * (1 + stats.get("spPct"+spell.base_spell) / 100)); return Math.floor(cost * (1 + stats.get("spPct"+spell.base_spell) / 100));
} }
@ -1583,31 +1398,23 @@ function displaySpellDamage(parent_elem, overallparent_elem, stats, spell, spell
// TODO: move cost calc out // TODO: move cost calc out
parent_elem.textContent = ""; parent_elem.textContent = "";
let title_elem = document.createElement("p"); let title_elem = make_elem("p");
overallparent_elem.textContent = ""; overallparent_elem.textContent = "";
let title_elemavg = document.createElement("b"); let title_elemavg = document.createElement("b");
if ('cost' in spell) { if ('cost' in spell) {
let first = document.createElement("span"); let first = make_elem("span", [], { textContent: spell.name + " (" });
first.textContent = spell.name + " (";
title_elem.appendChild(first.cloneNode(true)); //cloneNode is needed here. title_elem.appendChild(first.cloneNode(true)); //cloneNode is needed here.
title_elemavg.appendChild(first); title_elemavg.appendChild(first);
let second = document.createElement("span"); let second = make_elem("span", ["Mana"], { textContent: getSpellCost(stats, spell) });
second.textContent = getSpellCost(stats, spell);
second.classList.add("Mana");
title_elem.appendChild(second.cloneNode(true)); title_elem.appendChild(second.cloneNode(true));
title_elemavg.appendChild(second); title_elemavg.appendChild(second);
let third = document.createElement("span"); let third = make_elem("span", [], { textContent: ")" });// " + getBaseSpellCost(stats, spellIdx, spell.cost) + " ]";
third.textContent = ")";// [Base: " + getBaseSpellCost(stats, spellIdx, spell.cost) + " ]"; title_elem.appendChild(third.cloneNode(true));
title_elem.appendChild(third); title_elemavg.appendChild(third);
let third_summary = document.createElement("span");
third_summary.textContent = ")";
title_elemavg.appendChild(third_summary);
} }
else { else {
title_elem.textContent = spell.name; title_elem.textContent = spell.name;
@ -1624,30 +1431,26 @@ function displaySpellDamage(parent_elem, overallparent_elem, stats, spell, spell
let critChance = skillPointsToPercentage(stats.get('dex')); let critChance = skillPointsToPercentage(stats.get('dex'));
let part_divavg = document.createElement("p"); let part_divavg = make_elem("p");
overallparent_elem.append(part_divavg); overallparent_elem.append(part_divavg);
function _summary(text, val, fmt) { function add_summary(text, val, fmt) {
let overallaverageLabel = document.createElement("p"); if (typeof(val) === 'number') { val = val.toFixed(2); }
let first = document.createElement("span"); let summary_elem = make_elem("p");
let second = document.createElement("span"); summary_elem.append(
first.textContent = text; make_elem("span", [], { textContent: text }),
second.textContent = val.toFixed(2); make_elem("span", [fmt], { textContent: val })
overallaverageLabel.appendChild(first); );
overallaverageLabel.appendChild(second); part_divavg.append(summary_elem);
second.classList.add(fmt);
part_divavg.append(overallaverageLabel);
} }
for (let i = 0; i < spell_results.length; ++i) { for (let i = 0; i < spell_results.length; ++i) {
const spell_info = spell_results[i]; const spell_info = spell_results[i];
let part_div = document.createElement("p"); let part_div = make_elem("p", ["pt-3"]);
parent_elem.append(part_div); parent_elem.append(part_div);
let subtitle_elem = document.createElement("p"); part_div.append(make_elem("p", [], { textContent: spell_info.name }));
subtitle_elem.textContent = spell_info.name
part_div.append(subtitle_elem);
if (spell_info.type === "damage") { if (spell_info.type === "damage") {
let totalDamNormal = spell_info.normal_total; let totalDamNormal = spell_info.normal_total;
@ -1657,14 +1460,27 @@ function displaySpellDamage(parent_elem, overallparent_elem, stats, spell, spell
let critAverage = (totalDamCrit[0]+totalDamCrit[1])/2 || 0; let critAverage = (totalDamCrit[0]+totalDamCrit[1])/2 || 0;
let averageDamage = (1-critChance)*nonCritAverage+critChance*critAverage || 0; let averageDamage = (1-critChance)*nonCritAverage+critChance*critAverage || 0;
let averageLabel = document.createElement("p"); let averageLabel = make_elem("p", [], { textContent: "Average: "+averageDamage.toFixed(2) });
averageLabel.textContent = "Average: "+averageDamage.toFixed(2);
// averageLabel.classList.add("damageSubtitle"); // averageLabel.classList.add("damageSubtitle");
part_div.append(averageLabel); part_div.append(averageLabel);
if (spell_info.name === spell.display) { if (spell_info.name === spell.display) {
_summary(spell_info.name+ ": ", averageDamage, "Damage"); if (spellIdx === 0) {
let display_attack_speeds = ["Super Slow", "Very Slow", "Slow", "Normal", "Fast", "Very Fast", "Super Fast"];
let adjAtkSpd = attackSpeeds.indexOf(stats.get("atkSpd")) + stats.get("atkTier");
console.log(stats);
if(adjAtkSpd > 6) {
adjAtkSpd = 6;
} else if(adjAtkSpd < 0) {
adjAtkSpd = 0;
}
add_summary("Average DPS: ", averageDamage * baseDamageMultiplier[adjAtkSpd], "Damage");
add_summary("Attack Speed: ", display_attack_speeds[adjAtkSpd], "Damage");
add_summary("Per Attack: ", averageDamage, "Damage");
}
else {
add_summary(spell_info.name+ ": ", averageDamage, "Damage");
}
} }
function _damage_display(label_text, average, dmg_min, dmg_max) { function _damage_display(label_text, average, dmg_min, dmg_max) {
@ -1690,7 +1506,7 @@ function displaySpellDamage(parent_elem, overallparent_elem, stats, spell, spell
// healLabel.classList.add("damagep"); // healLabel.classList.add("damagep");
part_div.append(healLabel); part_div.append(healLabel);
if (spell_info.name === spell.display) { if (spell_info.name === spell.display) {
_summary(spell_info.name+ ": ", heal_amount, "Set"); add_summary(spell_info.name+ ": ", heal_amount, "Set");
} }
} }
} }
@ -1900,6 +1716,7 @@ function displayIDProbabilities(parent_id, item, amp) {
parent_elem.appendChild(table_elem); parent_elem.appendChild(table_elem);
for (const [id,val] of Object.entries(itemMap.get(item_name))) { for (const [id,val] of Object.entries(itemMap.get(item_name))) {
if (rolledIDs.includes(id)) { if (rolledIDs.includes(id)) {
if (!item.get("maxRolls").get(id)) { continue; }
let min = item.get("minRolls").get(id); let min = item.get("minRolls").get(id);
let max = item.get("maxRolls").get(id); let max = item.get("maxRolls").get(id);
//Apply corkian amps //Apply corkian amps
@ -2110,12 +1927,10 @@ function stringCDF(id,val,base,amp) {
function addClickableArrow(elem, target) { function addClickableArrow(elem, target) {
//up and down arrow - done ugly //up and down arrow - done ugly
let arrow = document.createElement("img"); let arrow = make_elem("img", [], { id: "arrow_" + elem.id, src: "../media/icons/" + (newIcons ? "new" : "old") + "/toggle_down.png" });
arrow.id = "arrow_" + elem.id;
arrow.style.maxWidth = document.body.clientWidth > 900 ? "3rem" : "10rem"; arrow.style.maxWidth = document.body.clientWidth > 900 ? "3rem" : "10rem";
arrow.src = "../media/icons/" + (newIcons ? "new" : "old") + "/toggle_down.png";
elem.appendChild(arrow); elem.appendChild(arrow);
arrow.addEventListener("click", () => toggle_spell_tab(arrow, target)); elem.addEventListener("click", () => toggle_spell_tab(arrow, target));
} }
// toggle arrow thinger // toggle arrow thinger

View file

@ -20,14 +20,17 @@ function init_itempage() {
//displayExpandedItem(expandItem(itemMap.get(item_url_tag).statMap, []), "item-view"); //displayExpandedItem(expandItem(itemMap.get(item_url_tag).statMap, []), "item-view");
try{ try{
item = expandItem(itemMap.get(item_url_tag.replaceAll("%20"," ")), []); item = expandItem(itemMap.get(item_url_tag.replaceAll("%20"," ")), []);
displaysq2ExpandedItem(item, "item-view"); if (item.get('category') === 'weapon') {
displaysq2AdditionalInfo("additional-info", item); item.set('powders', []);
displaysq2IDCosts("identification-costs", item); apply_weapon_powders(item);
if (item.get("set") && sets[item.get("set")]) {
displaysq2AllSetBonuses("set-bonus-info",item.get("set"));
} }
console.log(item); displayExpandedItem(item, "item-view");
displaysq2IDProbabilities("identification-probabilities", item, amp_state); displayAdditionalInfo("additional-info", item);
displayIDCosts("identification-costs", item);
if (item.get("set") && sets[item.get("set")]) {
displayAllSetBonuses("set-bonus-info",item.get("set"));
}
displayIDProbabilities("identification-probabilities", item, amp_state);
} catch (error) { } catch (error) {
console.log(error); console.log(error);
console.log(error.stack); console.log(error.stack);
@ -56,6 +59,8 @@ function toggleAmps(button_id) {
} }
(async function() {
load_init(init_itempage); let load_promises = [ load_init() ];
//load_ing_init(init); await Promise.all(load_promises);
init_itempage();
})();

View file

@ -1,4 +1,4 @@
const DB_VERSION = 91; const DB_VERSION = 99;
// @See https://github.com/mdn/learning-area/blob/master/javascript/apis/client-side-storage/indexeddb/video-store/index.jsA // @See https://github.com/mdn/learning-area/blob/master/javascript/apis/client-side-storage/indexeddb/video-store/index.jsA
let db; let db;

View file

@ -1,4 +1,4 @@
const ING_DB_VERSION = 13; const ING_DB_VERSION = 14;
// @See https://github.com/mdn/learning-area/blob/master/javascript/apis/client-side-storage/indexeddb/video-store/index.js // @See https://github.com/mdn/learning-area/blob/master/javascript/apis/client-side-storage/indexeddb/video-store/index.js
@ -9,13 +9,13 @@ let iload_complete = false;
let ings; let ings;
let recipes; let recipes;
let ingMap; let ingMap = new Map();
let ingList = []; let ingList = [];
let recipeMap; let recipeMap;
let recipeList = []; let recipeList = [];
let ingIDMap; let ingIDMap = new Map();
let recipeIDMap; let recipeIDMap;
/* /*
@ -163,39 +163,41 @@ async function load_ing_init() {
} }
function init_ing_maps() { function init_ing_maps() {
ingMap = new Map();
recipeMap = new Map(); recipeMap = new Map();
ingIDMap = new Map();
recipeIDMap = new Map(); recipeIDMap = new Map();
let ing = Object(); let ing = {
ing.name = "No Ingredient"; name: "No Ingredient",
ing.displayName = "No Ingredient"; displayName: "No Ingredient",
ing.tier = 0; tier: 0,
ing.lvl = 0; lvl: 0,
ing.skills = ["ARMOURING", "TAILORING", "WEAPONSMITHING", "WOODWORKING", "JEWELING", "COOKING", "ALCHEMISM", "SCRIBING"]; skills: ["ARMOURING", "TAILORING", "WEAPONSMITHING", "WOODWORKING", "JEWELING", "COOKING", "ALCHEMISM", "SCRIBING"],
ing.ids= {}; ids: {},
ing.itemIDs = {"dura": 0, "strReq": 0, "dexReq": 0,"intReq": 0,"defReq": 0,"agiReq": 0,}; itemIDs: {"dura": 0, "strReq": 0, "dexReq": 0,"intReq": 0,"defReq": 0,"agiReq": 0,},
ing.consumableIDs = {"dura": 0, "charges": 0}; consumableIDs: {"dura": 0, "charges": 0},
ing.posMods = {"left": 0, "right": 0, "above": 0, "under": 0, "touching": 0, "notTouching": 0}; posMods: {"left": 0, "right": 0, "above": 0, "under": 0, "touching": 0, "notTouching": 0},
ing.id = 4000; id: 4000
ingMap.set(ing["displayName"], ing); };
ingList.push(ing["displayName"]); ingMap.set(ing.displayName, ing);
ingIDMap.set(ing["id"], ing["displayName"]); ingList.push(ing.displayName);
ingIDMap.set(ing.id, ing.displayName);
let numerals = new Map([[1, "I"], [2, "II"], [3, "III"], [4, "IV"], [5, "V"], [6, "VI"]]); let numerals = new Map([[1, "I"], [2, "II"], [3, "III"], [4, "IV"], [5, "V"], [6, "VI"]]);
for (let i = 0; i < 5; i ++) { for (let i = 0; i < 5; i ++) {
for (const powderIng of powderIngreds) { for (const powderIng of powderIngreds) {
let ing = Object(); let ing = {
ing.name = "" + damageClasses[i+1] + " Powder " + numerals.get(powderIngreds.indexOf(powderIng) + 1); name: "" + damageClasses[i+1] + " Powder " + numerals.get(powderIngreds.indexOf(powderIng) + 1),
ing.displayName = ing.name tier: 0,
ing.tier = 0; lvl: 0,
ing.lvl = 0; skills: ["ARMOURING", "TAILORING", "WEAPONSMITHING", "WOODWORKING", "JEWELING"],
ing.skills = ["ARMOURING", "TAILORING", "WEAPONSMITHING", "WOODWORKING", "JEWELING"]; ids: {},
ing.ids = {}; isPowder: true,
ing.isPowder = true; pid: 6*i + powderIngreds.indexOf(powderIng),
ing.pid = 6*i + powderIngreds.indexOf(powderIng); itemIDs: {"dura": powderIng["durability"], "strReq": 0, "dexReq": 0,"intReq": 0,"defReq": 0,"agiReq": 0},
consumableIDs: {"dura": 0, "charges": 0},
posMods: {"left": 0, "right": 0, "above": 0, "under": 0, "touching": 0, "notTouching": 0}
};
ing.id = 4001 + ing.pid; ing.id = 4001 + ing.pid;
ing.itemIDs = {"dura": powderIng["durability"], "strReq": 0, "dexReq": 0,"intReq": 0,"defReq": 0,"agiReq": 0,}; ing.diplayName = ing.name;
switch(i) { switch(i) {
case 0: case 0:
ing.itemIDs["strReq"] = powderIng["skpReq"]; ing.itemIDs["strReq"] = powderIng["skpReq"];
@ -213,24 +215,21 @@ function init_ing_maps() {
ing.itemIDs["agiReq"] = powderIng["skpReq"]; ing.itemIDs["agiReq"] = powderIng["skpReq"];
break; break;
} }
ing.consumableIDs = {"dura": 0, "charges": 0}; ingMap.set(ing.displayName, ing);
ing.posMods = {"left": 0, "right": 0, "above": 0, "under": 0, "touching": 0, "notTouching": 0}; ingList.push(ing.displayName);
ingMap.set(ing["displayName"],ing); ingIDMap.set(ing.id, ing.displayName);
ingList.push(ing["displayName"]);
ingIDMap.set(ing["id"], ing["displayName"]);
} }
} }
for (const ing of ings) { for (const ing of ings) {
ingMap.set(ing["displayName"], ing); ingMap.set(ing.displayName, ing);
ingList.push(ing["displayName"]); ingList.push(ing.displayName);
ingIDMap.set(ing["id"], ing["displayName"]); ingIDMap.set(ing.id, ing.displayName);
} }
for (const recipe of recipes) { for (const recipe of recipes) {
recipeMap.set(recipe["name"], recipe); recipeMap.set(recipe.name, recipe);
recipeList.push(recipe["name"]); recipeList.push(recipe.name);
recipeIDMap.set(recipe["id"],recipe["name"]); recipeIDMap.set(recipe.id, recipe.name);
} }
console.log(ingMap);
} }

View file

@ -169,14 +169,14 @@ function calc_weapon_powder(weapon, damageBases) {
let min_diff = Math.min(neutralRemainingRaw[0], conversionRatio * neutralBase[0]); let min_diff = Math.min(neutralRemainingRaw[0], conversionRatio * neutralBase[0]);
let max_diff = Math.min(neutralRemainingRaw[1], conversionRatio * neutralBase[1]); let max_diff = Math.min(neutralRemainingRaw[1], conversionRatio * neutralBase[1]);
//damages[element+1][0] = Math.floor(round_near(damages[element+1][0] + min_diff)); damages[element+1][0] = Math.floor(round_near(damages[element+1][0] + min_diff));
//damages[element+1][1] = Math.floor(round_near(damages[element+1][1] + max_diff)); damages[element+1][1] = Math.floor(round_near(damages[element+1][1] + max_diff));
//neutralRemainingRaw[0] = Math.floor(round_near(neutralRemainingRaw[0] - min_diff)); neutralRemainingRaw[0] = Math.floor(round_near(neutralRemainingRaw[0] - min_diff));
//neutralRemainingRaw[1] = Math.floor(round_near(neutralRemainingRaw[1] - max_diff)); neutralRemainingRaw[1] = Math.floor(round_near(neutralRemainingRaw[1] - max_diff));
damages[element+1][0] += min_diff; //damages[element+1][0] += min_diff;
damages[element+1][1] += max_diff; //damages[element+1][1] += max_diff;
neutralRemainingRaw[0] -= min_diff; //neutralRemainingRaw[0] -= min_diff;
neutralRemainingRaw[1] -= max_diff; //neutralRemainingRaw[1] -= max_diff;
} }
damages[element+1][0] += powder.min; damages[element+1][0] += powder.min;
damages[element+1][1] += powder.max; damages[element+1][1] += powder.max;

View file

@ -1,98 +1,116 @@
/**
* Apply skillpoint bonuses from an item.
* Also applies set deltas.
* Modifies the skillpoints array.
*/
function apply_skillpoints(skillpoints, item, activeSetCounts) {
for (let i = 0; i < 5; i++) {
skillpoints[i] += item.skillpoints[i];
}
const setName = item.set;
if (setName) { // undefined/null means no set.
let setCount = activeSetCounts.get(setName);
let old_bonus = {};
if (setCount) {
old_bonus = sets.get(setName).bonuses[setCount-1];
activeSetCounts.set(setName, setCount + 1);
}
else {
setCount = 0;
activeSetCounts.set(setName, 1);
}
const new_bonus = sets.get(setName).bonuses[setCount];
//let skp_order = ["str","dex","int","def","agi"];
for (const i in skp_order) {
const delta = (new_bonus[skp_order[i]] || 0) - (old_bonus[skp_order[i]] || 0);
skillpoints[i] += delta;
}
}
}
/**
* Apply skillpoints until this item can be worn.
* Also applies set deltas.
* Confusingly, does not modify the skillpoints array.
* Instead, return an array of deltas.
*/
function apply_to_fit(skillpoints, item, skillpoint_min, activeSetCounts) {
let applied = [0, 0, 0, 0, 0];
for (let i = 0; i < 5; i++) {
if (item.skillpoints[i] < 0 && skillpoint_min[i]) {
const unadjusted = skillpoints[i] + item.skillpoints[i];
const delta = skillpoint_min[i] - unadjusted;
if (delta > 0) {
applied[i] += delta;
}
}
if (item.reqs[i] == 0) continue;
skillpoint_min[i] = Math.max(skillpoint_min[i], item.reqs[i] + item.skillpoints[i]);
const req = item.reqs[i];
const cur = skillpoints[i];
if (req > cur) {
const diff = req - cur;
applied[i] += diff;
}
}
const setName = item.set;
if (setName) { // undefined/null means no set.
const setCount = activeSetCounts.get(setName);
if (setCount) {
const old_bonus = sets.get(setName).bonuses[setCount-1];
const new_bonus = sets.get(setName).bonuses[setCount];
//let skp_order = ["str","dex","int","def","agi"];
for (const i in skp_order) {
const set_delta = (new_bonus[skp_order[i]] || 0) - (old_bonus[skp_order[i]] || 0);
if (set_delta < 0 && skillpoint_min[i]) {
const unadjusted = skillpoints[i] + set_delta;
const delta = skillpoint_min[i] - unadjusted;
if (delta > 0) {
applied[i] += delta;
}
}
}
}
}
return applied;
}
function calculate_skillpoints(equipment, weapon) { function calculate_skillpoints(equipment, weapon) {
// const start = performance.now();
// Calculate equipment equipping order and required skillpoints. // Calculate equipment equipping order and required skillpoints.
// Return value: [equip_order, best_skillpoints, final_skillpoints, best_total]; // Return value: [equip_order, best_skillpoints, final_skillpoints, best_total];
let fixed = []; let fixed = [];
let consider = []; let consider = [];
let noboost = []; let noboost = [];
let crafted = []; let crafted = [];
weapon.skillpoints = weapon.get('skillpoints');
weapon.reqs = weapon.get('reqs');
weapon.set = weapon.get('set');
for (const item of equipment) { for (const item of equipment) {
item.skillpoints = item.get('skillpoints');
item.reqs = item.get('reqs');
item.set = item.get('set');
if (item.get("crafted")) { if (item.get("crafted")) {
crafted.push(item); crafted.push(item);
} }
else if (item.get("reqs").every(x => x === 0) && item.get("skillpoints").every(x => x >= 0)) { // TODO hack: We will treat ALL set items as unsafe :(
else if (item.set !== null) {
consider.push(item);
}
else if (item.get("reqs").every(x => x === 0) && item.skillpoints.every(x => x >= 0)) {
// All reqless item without -skillpoints. // All reqless item without -skillpoints.
fixed.push(item); fixed.push(item);
} }
// TODO hack: We will treat ALL set items as unsafe :( else if (item.skillpoints.every(x => x <= 0)) {
else if (item.get("skillpoints").every(x => x === 0) && item.get("set") === null) {
noboost.push(item); noboost.push(item);
} }
else { else {
consider.push(item); consider.push(item);
} }
} }
function apply_skillpoints(skillpoints, item, activeSetCounts) {
for (let i = 0; i < 5; i++) {
skillpoints[i] += item.get("skillpoints")[i];
}
const setName = item.get("set");
if (setName) { // undefined/null means no set.
let setCount = activeSetCounts.get(setName);
let old_bonus = {};
if (setCount) {
old_bonus = sets.get(setName).bonuses[setCount-1];
activeSetCounts.set(setName, setCount + 1);
}
else {
setCount = 0;
activeSetCounts.set(setName, 1);
}
const new_bonus = sets.get(setName).bonuses[setCount];
//let skp_order = ["str","dex","int","def","agi"];
for (const i in skp_order) {
const delta = (new_bonus[skp_order[i]] || 0) - (old_bonus[skp_order[i]] || 0);
skillpoints[i] += delta;
}
}
}
function apply_to_fit(skillpoints, item, skillpoint_min, activeSetCounts) {
let applied = [0, 0, 0, 0, 0];
let total = 0;
for (let i = 0; i < 5; i++) {
if (item.get("skillpoints")[i] < 0 && skillpoint_min[i]) {
const unadjusted = skillpoints[i] + item.get("skillpoints")[i];
const delta = skillpoint_min[i] - unadjusted;
if (delta > 0) {
applied[i] += delta;
total += delta;
}
}
if (item.get("reqs")[i] == 0) continue;
skillpoint_min[i] = Math.max(skillpoint_min[i], item.get("reqs")[i] + item.get("skillpoints")[i]);
const req = item.get("reqs")[i];
const cur = skillpoints[i];
if (req > cur) {
const diff = req - cur;
applied[i] += diff;
total += diff;
}
}
const setName = item.get("set");
if (setName) { // undefined/null means no set.
const setCount = activeSetCounts.get(setName);
if (setCount) {
const old_bonus = sets.get(setName).bonuses[setCount-1];
const new_bonus = sets.get(setName).bonuses[setCount];
//let skp_order = ["str","dex","int","def","agi"];
for (const i in skp_order) {
const set_delta = (new_bonus[skp_order[i]] || 0) - (old_bonus[skp_order[i]] || 0);
if (set_delta < 0 && skillpoint_min[i]) {
const unadjusted = skillpoints[i] + set_delta;
const delta = skillpoint_min[i] - unadjusted;
if (delta > 0) {
applied[i] += delta;
total += delta;
}
}
}
}
}
return [applied, total];
}
// Separate out the no req items and add them to the static skillpoint base. // Separate out the no req items and add them to the static skillpoint base.
let static_skillpoints_base = [0, 0, 0, 0, 0] let static_skillpoints_base = [0, 0, 0, 0, 0]
@ -101,7 +119,7 @@ function calculate_skillpoints(equipment, weapon) {
apply_skillpoints(static_skillpoints_base, item, static_activeSetCounts); apply_skillpoints(static_skillpoints_base, item, static_activeSetCounts);
} }
let best = consider.concat(noboost); let best = consider;
let final_skillpoints = static_skillpoints_base.slice(); let final_skillpoints = static_skillpoints_base.slice();
let best_skillpoints = [0, 0, 0, 0, 0]; let best_skillpoints = [0, 0, 0, 0, 0];
let best_total = Infinity; let best_total = Infinity;
@ -110,100 +128,125 @@ function calculate_skillpoints(equipment, weapon) {
let allFalse = [0, 0, 0, 0, 0]; let allFalse = [0, 0, 0, 0, 0];
if (consider.length > 0 || noboost.length > 0 || crafted.length > 0) { if (consider.length > 0 || noboost.length > 0 || crafted.length > 0) {
// Try every combination and pick the best one. // Try every combination and pick the best one.
for (let permutation of perm(consider)) { const [root, terminal, sccs] = construct_scc_graph(consider);
let activeSetCounts = new Map(static_activeSetCounts); const end_checks = crafted.concat(noboost);
end_checks.push(weapon);
let has_skillpoint = allFalse.slice(); function check_end(skillpoints_applied, skillpoints, activeSetCounts, total_applied) {
permutation = permutation.concat(noboost);
let skillpoints_applied = [0, 0, 0, 0, 0];
// Complete slice is a shallow copy.
let skillpoints = static_skillpoints_base.slice();
let total_applied = 0;
let result;
let needed_skillpoints;
let total_diff;
for (const item of permutation) {
result = apply_to_fit(skillpoints, item, has_skillpoint, activeSetCounts);
needed_skillpoints = result[0];
total_diff = result[1];
for (let i = 0; i < 5; ++i) {
skillpoints_applied[i] += needed_skillpoints[i];
skillpoints[i] += needed_skillpoints[i];
}
apply_skillpoints(skillpoints, item, activeSetCounts);
total_applied += total_diff;
if (total_applied >= best_total) {
break;
}
}
// Crafted skillpoint does not count initially. // Crafted skillpoint does not count initially.
for (const item of crafted) { for (const item of end_checks) {
//console.log(item) const needed_skillpoints = apply_to_fit(skillpoints, item,
result = apply_to_fit(skillpoints, item, allFalse.slice(), activeSetCounts); [false, false, false, false, false], activeSetCounts);
//console.log(result)
needed_skillpoints = result[0];
total_diff = result[1];
for (let i = 0; i < 5; ++i) { for (let i = 0; i < 5; ++i) {
skillpoints_applied[i] += needed_skillpoints[i]; const skp = needed_skillpoints[i]
skillpoints[i] += needed_skillpoints[i]; skillpoints_applied[i] += skp;
skillpoints[i] += skp;
total_applied += skp;
} }
total_applied += total_diff; if (best_total < total_applied) { return -1; }
}
if (total_applied >= best_total) {
continue;
}
let pre = skillpoints.slice();
result = apply_to_fit(skillpoints, weapon, allFalse.slice(), activeSetCounts);
needed_skillpoints = result[0];
total_diff = result[1];
for (let i = 0; i < 5; ++i) {
skillpoints_applied[i] += needed_skillpoints[i];
skillpoints[i] += needed_skillpoints[i];
}
apply_skillpoints(skillpoints, weapon, activeSetCounts);
total_applied += total_diff;
// Applying crafted item skill points last.
for (const item of crafted) {
apply_skillpoints(skillpoints, item, activeSetCounts);
//total_applied += total_diff;
}
if (total_applied < best_total) {
best = permutation;
final_skillpoints = skillpoints;
best_skillpoints = skillpoints_applied;
best_total = total_applied;
best_activeSetCounts = activeSetCounts;
} }
return total_applied;
} }
function permute_check(idx, _applied, _skillpoints, _sets, _has, _total_applied, order) {
const {nodes, children} = sccs[idx];
if (nodes[0] === terminal) {
const total = check_end(_applied, _skillpoints, _sets, _total_applied);
if (total !== -1 && total < best_total) {
final_skillpoints = _skillpoints;
best_skillpoints = _applied;
best_total = total;
best_activeSetCounts = _sets;
best = order;
}
return;
}
for (let permutation of perm(nodes)) {
const skillpoints_applied = _applied.slice();
const skillpoints = _skillpoints.slice();
const activeSetCounts = new Map(_sets);
const has_skillpoint = _has.slice();
let total_applied = _total_applied;
let short_circuit = false;
for (const {item} of permutation) {
needed_skillpoints = apply_to_fit(skillpoints, item, has_skillpoint, activeSetCounts);
for (let i = 0; i < 5; ++i) {
skp = needed_skillpoints[i];
skillpoints_applied[i] += skp;
skillpoints[i] += skp;
total_applied += skp;
}
if (total_applied >= best_total) {
short_circuit = true;
break; // short circuit failure
}
apply_skillpoints(skillpoints, item, activeSetCounts);
}
if (short_circuit) { continue; }
permute_check(idx+1, skillpoints_applied, skillpoints, activeSetCounts, has_skillpoint, total_applied, order.concat(permutation.map(x => x.item)));
}
}
// skip root.
permute_check(1, best_skillpoints, final_skillpoints, best_activeSetCounts, allFalse.slice(), 0, []);
// add extra sp bonus
apply_skillpoints(final_skillpoints, weapon, best_activeSetCounts);
// Applying crafted item skill points last.
for (const item of crafted) {
apply_skillpoints(final_skillpoints, item, best_activeSetCounts);
}
} }
else { else {
best_total = 0; best_total = 0;
result = apply_to_fit(final_skillpoints, weapon, allFalse.slice(), best_activeSetCounts); needed_skillpoints = apply_to_fit(final_skillpoints, weapon, allFalse.slice(), best_activeSetCounts);
needed_skillpoints = result[0];
total_diff = result[1];
for (let i = 0; i < 5; ++i) { for (let i = 0; i < 5; ++i) {
best_skillpoints[i] += needed_skillpoints[i]; const skp = needed_skillpoints[i];
final_skillpoints[i] += needed_skillpoints[i]; best_skillpoints[i] += skp;
final_skillpoints[i] += skp;
best_total += skp;
} }
apply_skillpoints(final_skillpoints, weapon, best_activeSetCounts); apply_skillpoints(final_skillpoints, weapon, best_activeSetCounts);
best_total += total_diff;
} }
let equip_order = fixed.concat(best).concat(crafted); let equip_order = fixed.concat(best).concat(noboost).concat(crafted);
// best_skillpoints: manually assigned (before any gear) // best_skillpoints: manually assigned (before any gear)
// final_skillpoints: final totals (5 individ) // final_skillpoints: final totals (5 individ)
// best_total: total skillpoints assigned (number) // best_total: total skillpoints assigned (number)
// const end = performance.now();
// const output_msg = `skillpoint calculation took ${(end-start)/ 1000} seconds.`;
// console.log(output_msg);
return [equip_order, best_skillpoints, final_skillpoints, best_total, best_activeSetCounts]; return [equip_order, best_skillpoints, final_skillpoints, best_total, best_activeSetCounts];
} }
function construct_scc_graph(items_to_consider) {
let nodes = [];
let terminal_node = {
item: null,
children: [],
parents: nodes
};
let root_node = {
item: null,
children: nodes,
parents: [],
};
for (const item of items_to_consider) {
nodes.push({item: item, children: [terminal_node], parents: [root_node]});
}
// Dependency graph construction.
for (const node_a of nodes) {
const {item: a, children: a_children} = node_a;
for (const node_b of nodes) {
const {item: b, parents: b_parents} = node_b;
for (let i = 0; i < 5; ++i) {
if (a.skillpoints[i] > 0 && (a.reqs[i] < b.reqs[i] || b.skillpoints[i] < 0)) {
a_children.push(node_b);
b_parents.push(node_a);
break;
}
}
}
}
const sccs = make_SCC_graph(root_node, nodes);
return [root_node, terminal_node, sccs];
}

View file

@ -1,57 +1,4 @@
document.addEventListener("DOMContentLoaded", function() { let itemCategories = [ "armor", "accessory", "weapon" ];
let filterInputs = new Map([["item-category", ["ALL", "armor", "helmet", "chestplate", "leggings", "boots", "accessory", "ring", "bracelet", "necklace", "weapon", "wand", "spear", "bow", "dagger", "relik"]],
["item-rarity", ["ANY", "Normal", "Unique", "Set", "Rare", "Legendary", "Fabled", "Mythic", "Sane"]],
["filter1", sq2ItemFilters],
["filter2", sq2ItemFilters],
["filter3", sq2ItemFilters],
["filter4", sq2ItemFilters]]);
for (const [field, data] of filterInputs) {
let field_choice = document.getElementById(field+"-choice");
// show dropdown on click
field_choice.onclick = function() {field_choice.dispatchEvent(new Event('input', {bubbles:true}));};
filterInputs.set(field, new autoComplete({
data: {
src: data,
},
threshold: 0,
selector: "#"+ field +"-choice",
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 = document.getElementById(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) {
message = document.createElement('li');
message.classList.add('scaled-font');
message.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;
};
},
},
}
}));
};
});
const sq2_translate_mappings = { const sq2_translate_mappings = {
//"Name": "name", //"Name": "name",
@ -184,7 +131,11 @@ function displayItems(items_copy) {
box.appendChild(bckgrdbox); box.appendChild(bckgrdbox);
bckgrdbox.id = "item"+i+"b"; bckgrdbox.id = "item"+i+"b";
items_parent.appendChild(box); items_parent.appendChild(box);
displaysq2ExpandedItem(item, bckgrdbox.id); item.set("powders", []);
if (item.get("category") == "weapon") {
apply_weapon_powders(item);
}
displayExpandedItem(item, bckgrdbox.id, true);
} }
} }
@ -218,12 +169,12 @@ function doItemSearch() {
for (let i = 1; i <= 4; ++i) { for (let i = 1; i <= 4; ++i) {
let raw_dat = document.getElementById("filter"+i+"-choice").value; let raw_dat = document.getElementById("filter"+i+"-choice").value;
let filter_dat = translate_mappings[raw_dat]; let filter_dat = sq2_translate_mappings[raw_dat];
if (filter_dat !== undefined) { if (filter_dat !== undefined) {
queries.push(new IdQuery(filter_dat)); queries.push(new IdQuery(filter_dat));
continue; continue;
} }
filter_dat = special_mappings[raw_dat]; filter_dat = sq2_special_mappings[raw_dat];
if (filter_dat !== undefined) { if (filter_dat !== undefined) {
queries.push(filter_dat); queries.push(filter_dat);
continue; continue;
@ -251,6 +202,63 @@ function resetItemSearch() {
function init_items() { function init_items() {
items_expanded = items.filter( (i) => !("remapID" in i) ).map( (i) => expandItem(i) ); items_expanded = items.filter( (i) => !("remapID" in i) ).map( (i) => expandItem(i) );
//init dropdowns
let filterInputs = new Map([["item-category", ["ALL", "armor", "helmet", "chestplate", "leggings", "boots", "accessory", "ring", "bracelet", "necklace", "weapon", "wand", "spear", "bow", "dagger", "relik"]],
["item-rarity", ["ANY", "Normal", "Unique", "Set", "Rare", "Legendary", "Fabled", "Mythic", "Sane"]],
["filter1", sq2ItemFilters],
["filter2", sq2ItemFilters],
["filter3", sq2ItemFilters],
["filter4", sq2ItemFilters]]);
for (const [field, data] of filterInputs) {
let field_choice = document.getElementById(field+"-choice");
// show dropdown on click
field_choice.onclick = function() {field_choice.dispatchEvent(new Event('input', {bubbles:true}));};
filterInputs.set(field, new autoComplete({
data: {
src: data,
},
threshold: 0,
selector: "#"+ field +"-choice",
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 = document.getElementById(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) {
message = document.createElement('li');
message.classList.add('scaled-font');
message.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;
};
},
},
}
}));
};
} }
load_init(init_items); (async function() {
await Promise.resolve(load_init());
init_items();
})();

View file

@ -630,8 +630,15 @@ function addClasses(elem, classes) {
*/ */
async function hardReload() { async function hardReload() {
//https://gist.github.com/rmehner/b9a41d9f659c9b1c3340 //https://gist.github.com/rmehner/b9a41d9f659c9b1c3340
const dbs = await window.indexedDB.databases(); try {
await dbs.forEach(db => { window.indexedDB.deleteDatabase(db.name) }); const dbs = await window.indexedDB.databases();
await dbs.forEach(db => { window.indexedDB.deleteDatabase(db.name) });
} catch (error) {
// Hacky patch for firefox...
console.log(error);
const db_names = ['item_db', 'ing_db', 'map_db', 'tome_db'];
await db_names.forEach(db => { window.indexedDB.deleteDatabase(db) });
}
location.reload(true); location.reload(true);
} }
@ -770,112 +777,204 @@ function assert_error(func_binding, msg) {
/** /**
* Deep copy object/array of basic types. * Deep copy object/array of basic types.
*/ */
function deepcopy(obj) { function deepcopy(obj, refs=undefined) {
if (refs === undefined) {
refs = new Map();
}
if (typeof(obj) !== 'object' || obj === null) { // null or value type if (typeof(obj) !== 'object' || obj === null) { // null or value type
return obj; return obj;
} }
let ret = Array.isArray(obj) ? [] : {}; let ret = Array.isArray(obj) ? [] : {};
for (let key in obj) { for (let key in obj) {
ret[key] = deepcopy(obj[key]); let val;
try {
val = obj[key];
} catch (exc) {
console.trace();
val = undefined;
}
if (typeof(obj) === 'object') {
if (refs.has(val)) {
ret[key] = refs.get(val);
}
else {
refs.set(val, val);
ret[key] = deepcopy(val, refs);
}
}
else {
ret[key] = val;
}
} }
return ret; return ret;
} }
/**
*
*/
function gen_slider_labeled({label_name, label_classlist = [], min = 0, max = 100, step = 1, default_val = min, id = undefined, color = "#FFFFFF", classlist = []}) {
let slider_container = document.createElement("div");
function bv_test() { let buf_col = document.createElement("div");
console.log("=====STARTING BITVECTOR UNIT TESTS====="); buf_col.classList.add("col");
let label = document.createElement("div");
label.classList.add("col");
label.classList.add(...label_classlist);
label.textContent = label_name + ": " + default_val;
// Empty Constructor + append str let slider = gen_slider(min, max, step, default_val, id, color, classlist, label);
let bv = new BitVector("");
bv.append("Bc8");
assert_equals(bv.bits.length, 1);
assert_equals(bv.length, 18);
assert_equals(bv.toB64(), "Bc8");
// Empty Constructor + append num 1 //we set IDs here because the slider's id is potentially only meaningful after gen_slider() is called
bv = new BitVector(""); label.id = slider.id + "_label";
bv.append(10000, 18); slider_container.id = slider.id + "-container";
assert_equals(bv.bits.length, 1);
assert_equals(bv.length, 18);
assert_equals(bv.toB64(), "GS2"); //have to read backwards
// Empty Constructor + append num 1 buf_col.append(slider, label);
bv = new BitVector(""); slider_container.appendChild(buf_col);
bv.append(10000, 14);
assert_equals(bv.bits.length, 1);
assert_equals(bv.length, 14);
assert_equals(bv.toB64(), "GS2"); //have to read backwards
// 1-int constructor (num) return slider_container;
bv = new BitVector(10000, 14);
assert_equals(bv.bits.length, 1);
assert_equals(bv.length, 14);
assert_equals(bv.toB64(), "GS2");
// 1-int constructor (str)
bv = new BitVector("abcde");
assert_equals(bv.bits.length, 1);
assert_equals(bv.length, 30);
assert_equals(bv.toB64(), "abcde");
// test constructor ignore length when data is str
bv = new BitVector("abcde", 40);
assert_equals(bv.bits.length, 1);
assert_equals(bv.length, 30);
assert_equals(bv.toB64(), "abcde");
bv = new BitVector("abcdefghij", 20);
assert_equals(bv.bits.length, 2);
assert_equals(bv.length, 60);
assert_equals(bv.toB64(), "abcdefghij");
//test 32-bit length constructor
bv = new BitVector(2**31, 32);
assert_equals(bv.bits.length, 1);
assert_equals(bv.length, 32);
//test multiple length constructor (+ get to last bit)
bv = new BitVector("abcdefghijklmnop");
assert_equals(bv.bits.length, 3);
assert_equals(bv.length, 96);
assert_equals(bv.toB64(), "abcdefghijklmnop");
//test append resize w num 1
bv = new BitVector("abcd");
bv.append(10000, 14);
assert_equals(bv.bits.length, 2);
assert_equals(bv.length, 38);
assert_equals(bv.slice(24, 38), 10000);
assert_equals(bv.toB64().slice(0, 4), "abcd");
//test append resize w num 2
bv = new BitVector("abcdefghi");
bv.append(10000, 14);
assert_equals(bv.bits.length, 4);
assert_equals(bv.length, 68);
assert_equals(bv.slice(54, 68), 10000);
assert_equals(bv.toB64().slice(0, 9), "abcdefghi");
//test append resize w str 1
bv = new BitVector("abcd");
bv.append("efgh");
assert_equals(bv.bits.length, 2);
assert_equals(bv.length, 48);
assert_equals(bv.toB64(), "abcdefgh");
//test append resize w str 2
bv = new BitVector("abcd");
bv.append("efghijklmnopqrstuvwxyz");
assert_equals(bv.bits.length, 8);
assert_equals(bv.length, 156);
assert_equals(bv.toB64(), "abcdefghijklmnopqrstuvwxyz");
//test append resize w str 3
bv = new BitVector("abcdefgh");
bv.append("ijkl");
assert_equals(bv.bits.length, 4);
assert_equals(bv.length, 72);
assert_equals(bv.toB64(), "abcdefghijkl");
console.log("=====FINISHED BITVECTOR UNIT TESTS=====");
} }
bv_test(); /** Creates a slider input (input type = range) given styling parameters
*
* @param {Number | String} min - The minimum value for the slider. defaults to 0
* @param {Number | String} max - The maximum value for the slider. defaults to 100
* @param {Number | String} step - The granularity between possible values. defaults to 1
* @param {Number | String} default_val - The default value to set the slider to.
* @param {String} id - The element ID to use for the slider. defaults to the current date time
* @param {String} color - The hex color to use for the slider. Needs the # character.
* @param {Array<String>} classlist - A list of classes to add to the slider.
* @returns
*/
function gen_slider(min = 0, max = 100, step = 1, default_val = min, id = undefined, color = "#FFFFFF", classlist = [], label = undefined) {
//simple attribute vals
let slider = document.createElement("input");
slider.type = "range";
slider.min = min;
slider.max = max;
slider.step = step;
slider.value = default_val;
slider.autocomplete = "off";
if (id) {
if (document.getElementById(id)) {
throw new Error("ID " + id + " already exists within the DOM.")
} else {
slider.id = id;
}
} else {
slider.id = new Date().toLocaleTimeString();
}
slider.color = color;
slider.classList.add(...classlist); //special spread operator -
//necessary for display purposes
slider.style.webkitAppearance = "none";
slider.style.borderRadius = "30px";
slider.style.height = "0.5rem";
slider.classList.add("px-0", "slider");
//set up recoloring
slider.addEventListener("change", function(e) {
recolor_slider(slider, label);
});
//do recoloring for the default val
let pct = Math.round(100 * (parseInt(slider.value) - parseInt(slider.min)) / (parseInt(slider.max) - parseInt(slider.min)));
slider.style.background = `rgba(0, 0, 0, 0) linear-gradient(to right, ${color}, ${color} ${pct}%, #AAAAAA ${pct}%, #AAAAAA 100%)`;
//return slider
return slider;
}
/** Recolors a slider. If the corresponding label exists, also update that.
*
* @param {slider} slider - the slider element
* @param {label} label - the label element
*/
function recolor_slider(slider, label) {
let color = slider.color;
let pct = Math.round(100 * (parseInt(slider.value) - parseInt(slider.min)) / (parseInt(slider.max) - parseInt(slider.min)));
slider.style.background = `rgba(0, 0, 0, 0) linear-gradient(to right, ${color}, ${color} ${pct}%, #AAAAAA ${pct}%, #AAAAAA 100%)`;
if (label) {
//convention is that the number goes at the end... I parse by separating it at ':'
label.textContent = label.textContent.split(":")[0] + ": " + slider.value;
}
}
/**
* Shorthand for making an element in html.
*
* @param {String} type : type of element
* @param {List[String]} classlist : css classes for element
* @param {Map[String, String]} args : Properties for the element
*/
function make_elem(type, classlist = [], args = {}) {
const ret_elem = document.createElement(type);
ret_elem.classList.add(...classlist);
for (const i in args) {
ret_elem[i] = args[i];
}
return ret_elem;
}
/**
* Nodes must have:
* node: {
* parents: List[node]
* children: List[node]
* }
*
* This function will define: "visited, assigned, scc" properties
* Assuming a connected graph. (only one root)
*/
function make_SCC_graph(root_node, nodes) {
for (const node of nodes) {
node.visited = false;
node.assigned = false;
node.scc = null;
}
const res = []
/*
* SCC graph construction.
* https://en.wikipedia.org/wiki/Kosaraju%27s_algorithm
*/
function visit(u, res) {
if (u.visited) { return; }
u.visited = true;
for (const child of u.children) {
if (!child.visited) { visit(child, res); }
}
res.push(u);
}
visit(root_node, res);
res.reverse();
const sccs = [];
function assign(node, cur_scc) {
if (node.assigned) { return; }
cur_scc.nodes.push(node);
node.scc = cur_scc;
node.assigned = true;
for (const parent of node.parents) {
assign(parent, cur_scc);
}
}
for (const node of res) {
if (node.assigned) { continue; }
const cur_scc = {
nodes: [],
children: new Set(),
parents: new Set()
};
assign(node, cur_scc);
sccs.push(cur_scc);
}
for (const scc of sccs) {
for (const node of scc.nodes) {
for (const child of node.children) {
scc.children.add(child.scc);
}
for (const parent of node.parents) {
scc.parents.add(parent.scc);
}
}
}
return sccs;
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 182 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 183 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 178 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 202 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 184 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 177 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 202 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 184 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 205 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 203 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 221 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.6 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.1 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.3 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.2 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 962 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.1 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.1 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.1 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 974 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 708 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 666 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 654 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.4 KiB

After

Width:  |  Height:  |  Size: 1.1 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.4 KiB

After

Width:  |  Height:  |  Size: 1.1 KiB

Some files were not shown because too many files have changed in this diff Show more