fix merge conflicts
19
LICENSE.txt
Normal 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.
|
|
@ -18,7 +18,7 @@
|
|||
-->
|
||||
|
||||
<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">
|
||||
|
||||
|
@ -45,12 +45,15 @@
|
|||
<a href = "../custom/"><img src = "../media/icons/new/custom.png" alt = "WynnCustom" title = "WynnCustom"><b>WynnCustom</b></a>
|
||||
<a href = "../map/"><img src = "../media/icons/new/compass.png" alt = "WynnGPS" title = "WynnGPS"><b>WynnGPS</b></a>
|
||||
<a href = "../wynnfo/"><img src = "../media/icons/new/book.png" alt = "Wynnfo" title = "Wynnfo"><b>Wynnfo</b></a>
|
||||
<a onclick = "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>
|
||||
<hr/>
|
||||
<a href = "https://discord.gg/CGavnAnerv" target = "_blank"><img src = "../media/icons/discord.png" alt = "WB Discord" title = "WB Discord"><b>WB Discord</b></a>
|
||||
</div>
|
||||
<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="col-xl-6">
|
||||
<div class="row row-cols-1 mb-3 gy-4">
|
||||
|
@ -407,6 +410,8 @@
|
|||
</div>
|
||||
<div class="col text-center">
|
||||
<div id="summary-box"></div>
|
||||
<div id="err-box"></div>
|
||||
<div id="stack-box"></div>
|
||||
<div id="str-warnings"></div>
|
||||
<div id="dex-warnings"></div>
|
||||
<div id="int-warnings"></div>
|
||||
|
@ -428,7 +433,7 @@
|
|||
</div>
|
||||
<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')">
|
||||
Show Ability Tree
|
||||
Edit Abilities
|
||||
</button>
|
||||
</div>
|
||||
<div class = "col-3 py-2">
|
||||
|
@ -617,10 +622,14 @@
|
|||
</div>
|
||||
<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="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 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>
|
||||
|
@ -965,7 +974,12 @@
|
|||
</div>
|
||||
<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')">
|
||||
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>
|
||||
</div>
|
||||
<div class="col-auto p-1">
|
||||
|
@ -979,8 +993,8 @@
|
|||
</button>
|
||||
</div>
|
||||
<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')">
|
||||
Bash (+50%)
|
||||
<button class="button-boost w-100 border-0 text-white dark-8u dark-shadow-sm" id="fortitude-boost" onclick="update_boosts('fortitude-boost')">
|
||||
Fortitude (+60%)
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
|
@ -1045,11 +1059,6 @@
|
|||
<div class="col eDam">
|
||||
Rage (Passive)
|
||||
</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 class="col" id="dex-boost" style="display: none;">
|
||||
|
@ -1089,11 +1098,6 @@
|
|||
<div class="col tDam">
|
||||
Kill Streak (Passive)
|
||||
</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 class="col" id="int-boost">
|
||||
|
@ -1133,11 +1137,6 @@
|
|||
<div class="col wDam">
|
||||
Concentration (Passive)
|
||||
</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 class="col" id="def-boost" style="display: none;">
|
||||
|
@ -1177,11 +1176,6 @@
|
|||
<div class="col fDam">
|
||||
Endurance (Passive)
|
||||
</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 class="col" id="agi-boost" style="display: none;">
|
||||
|
@ -1221,11 +1215,6 @@
|
|||
<div class="col aDam">
|
||||
Dodge (Passive)
|
||||
</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>
|
||||
|
@ -1263,21 +1252,10 @@
|
|||
<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>
|
||||
<div class = "col">
|
||||
<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 spell-display dark-5 rounded dark-shadow py-2" id = "spell0-info" style="display: none;">Spell 1</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 id="all-spells-display" class="row row-cols-1 gy-3 text-center scaled-font pe-0">
|
||||
<div class = "col pe-0">
|
||||
<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 = "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">
|
||||
<footer class="text-center">
|
||||
<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>
|
||||
</div>
|
||||
<div id="credits">
|
||||
<a href="credits.txt" class="link">Additional credits</a>
|
||||
<a href="../credits.txt" class="link">Additional credits</a>
|
||||
</div>
|
||||
</footer>
|
||||
</div>
|
||||
|
@ -1393,7 +1371,6 @@
|
|||
</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/macy@2"></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/skillpoints.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/display_constants.js"></script>
|
||||
|
||||
<script type="text/javascript" src="../js/display.js"></script>
|
||||
|
||||
<script type="text/javascript" src="../js/query.js"></script>
|
||||
<script type="text/javascript" src="../js/query_2.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_tome.js"></script>
|
||||
|
@ -1424,9 +1395,6 @@
|
|||
<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_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>
|
||||
|
||||
<div id="graph_body" style="max-width: 100%; height: 100vh">
|
||||
|
@ -1434,6 +1402,7 @@
|
|||
<a id="saveLink">savelink</a>
|
||||
</div>
|
||||
<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>
|
||||
</html>
|
||||
|
|
1447
builder/index.html
1279
builder/index_full.html
Normal file
4293
clean.json
|
@ -31,265 +31,252 @@
|
|||
<hr/>
|
||||
<a href = "https://discord.gg/CGavnAnerv" target = "_blank"><img src = "../media/icons/discord.png" alt = "WB Discord" title = "WB Discord"><b>WB Discord</b></a>
|
||||
</div>
|
||||
<div class = "container py-5 vh-100 mx-0 mx-lg-auto">
|
||||
<div class = "col">
|
||||
<div class = "row g-3">
|
||||
<div class = "col-lg-5 col-sm-12 text-center">
|
||||
<div class = "row gx-5 mb-2">
|
||||
<div class = "col-lg-6 col-sm-12">
|
||||
<div id = "recipe-dropdown" class = "row h-100 dark-shadow dark-6 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">
|
||||
<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 class="container mt-5">
|
||||
<div class="row row-cols-1 row-cols-lg-3 gy-5">
|
||||
<div class="col col-lg-5">
|
||||
<!--crafter ui-->
|
||||
<div class="row row-cols-1 row-cols-lg-2 gx-5 gy-4 gy-lg-2">
|
||||
<div class="col" id="recipe-dropdown">
|
||||
<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">
|
||||
<img id = "recipe-img" class = "img-fluid rounded Crafted-shadow" src = "../media/items/new/generic-potion.png">
|
||||
</div>
|
||||
</div>
|
||||
<div class = "col-lg-6 col-sm-12">
|
||||
<div id = "atkSpdChoices" class = "row h-100 dark-shadow dark-6 rounded">
|
||||
<div class = "col py-2">
|
||||
<div class = "row h-50 align-items-center">
|
||||
<p class = "text-right mb-0 scaled-font fw-bold">Attack Speed</p>
|
||||
<div class = "col ps-3">
|
||||
<div class = "row row-cols-2 align-items-center">
|
||||
<div class = "col-4 px-0">
|
||||
<p class = "mb-0 scaled-font fw-bold">Type:</p>
|
||||
</div>
|
||||
<div class = "row h-50">
|
||||
<div class = "col-4 pl-1">
|
||||
<button class = "button rounded scaled-font fw-bold text-light dark-5" id = "slow-atk-button" onclick = "toggleAtkSpd('slow-atk-button')">
|
||||
Slow
|
||||
</button>
|
||||
</div>
|
||||
<div class = "col-4 px-0">
|
||||
<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-4 pr-1">
|
||||
<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 class = "col-8 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 class = "col-4 px-0">
|
||||
<p class = "mb-0 scaled-font fw-bold">Lv:</p>
|
||||
</div>
|
||||
<div class = "col-8 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 class = "row gx-5 mb-2">
|
||||
<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-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 class="col">
|
||||
<div id = "atkSpdChoices" class = "row row-cols-1 dark-shadow dark-5 rounded">
|
||||
<div class="col pt-1">
|
||||
<p class = "text-center scaled-font fw-bold mb-1">Attack Speed</p>
|
||||
</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 class="col mb-2">
|
||||
<div class="row justify-content-center">
|
||||
<div class="col-auto px-2">
|
||||
<button class = "button rounded scaled-font fw-bold text-light dark-5" id = "slow-atk-button" onclick = "toggleAtkSpd('slow-atk-button')">
|
||||
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>
|
||||
</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 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-1">Mat 1 Tier:</p>
|
||||
</div>
|
||||
</div>
|
||||
<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 2:</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-2" id="ing-choice-2" name="ing-choice-2" placeholder="No Ingredient" />
|
||||
<datalist id="ing-choices-2">
|
||||
</datalist>
|
||||
</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 = "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 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 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>
|
||||
<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 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 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 = "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 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>
|
||||
<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 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 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 class = "row rounded dark-shadow dark-6 py-2 gy-3">
|
||||
<div class = "col-lg-2 col-sm-6">
|
||||
<button class = "button rounded scaled-font fw-bold text-light dark-5" id = "reset-button" onclick = "resetFields()">
|
||||
Reset
|
||||
</button>
|
||||
<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 2:</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-2" id="ing-choice-2" name="ing-choice-2" placeholder="No Ingredient" />
|
||||
<datalist id="ing-choices-2">
|
||||
</datalist>
|
||||
</div>
|
||||
</div>
|
||||
<div class = "col-lg-3 col-sm-6">
|
||||
<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">
|
||||
<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 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 class = "col-lg-4 col-sm-6">
|
||||
<button class = "button rounded scaled-font fw-bold text-light dark-5" id = "copy-button" onclick = "copyRecipe()">
|
||||
Copy Short
|
||||
</button>
|
||||
</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 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 class = "col-lg-3 col-sm-6">
|
||||
<button class = "button rounded scaled-font fw-bold text-light dark-5" id = "share-button" onclick = "shareRecipe()">
|
||||
Copy Long
|
||||
</button>
|
||||
</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 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 class = "col-lg-4">
|
||||
<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 = "row recipe-stats">
|
||||
<div class = "col" id = "recipe-stats"></div>
|
||||
</div>
|
||||
<div class = "row craft-warnings">
|
||||
<div class = "" id = "craft-warnings"></div>
|
||||
</div>
|
||||
<div class = "row rounded dark-shadow dark-6 mt-3 p-2 align-items-center justify-content-center">
|
||||
<div class = "col-auto mx-auto">
|
||||
<button class = "button rounded scaled-font fw-bold text-light dark-5" id = "reset-button" onclick = "resetFields()">
|
||||
Reset
|
||||
</button>
|
||||
</div>
|
||||
<div class = "col-auto mx-auto">
|
||||
<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 class = "col-lg-3">
|
||||
<div class = "crafted row hide-container-block" style = "display:none">
|
||||
<div class = "craft-stats">
|
||||
<div class = "col rounded dark-6 text-light scaled-font p-3 border-dark dark-shadow g-0" id = "craft-stats"></div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col col-lg-4">
|
||||
<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 = "row row-cols-1 recipe-stats " id = "recipe-stats">
|
||||
</div>
|
||||
<div class = "row craft-warnings">
|
||||
<div class = "" id = "craft-warnings"></div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col col-lg-3">
|
||||
<div class = "crafted row hide-container-block" style = "display:none">
|
||||
<div class = "craft-stats">
|
||||
<div class = "col rounded dark-6 text-light scaled-font p-3 border-dark dark-shadow g-0" id = "craft-stats"></div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col ingredients-container hide-container-grid" id = "ingreds" style = "display:none">
|
||||
<div class = "col-lg-6 col-sm-12 hide-container-grid" id = "ingreds">
|
||||
<div class="row my-3">
|
||||
<div class="col col-lg-6 ingredients-container hide-container-grid" id = "ingreds" style = "display:none">
|
||||
<div class = "row mb-3">
|
||||
<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 class="col">
|
||||
<p class="box-title hide-container-block">
|
||||
Ingredients
|
||||
</p>
|
||||
</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 class="row row-cols-1 row-cols-lg-2 g-3">
|
||||
<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-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 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>
|
||||
<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 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-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 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>
|
||||
</div>
|
||||
<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 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>
|
||||
<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/crafter.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>
|
||||
</html>
|
||||
|
|
|
@ -7,14 +7,16 @@ The game, of course
|
|||
|
||||
Additional Contributors, in no particular order:
|
||||
- Kiocifer (Icons!)
|
||||
- IncinerateMe (helping transition to 1.20.3 / CI helper)
|
||||
- puppy (wynn2 ability tree help)
|
||||
- IncinerateMe (helping transition to 1.20.3 / atree / CI helper)
|
||||
- puppy (dog)
|
||||
- SockMower (ability tree encode/decode optimization)
|
||||
- ITechnically (coding emotional support / misc)
|
||||
- touhoku (best IM)
|
||||
- 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)
|
||||
- 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)
|
||||
- Atlas Inc discord (feedback, ideas, damage calc, etc)
|
||||
|
|
|
@ -8,7 +8,7 @@
|
|||
/* builder containers */
|
||||
|
||||
|
||||
.e_slider, .t_slider, .w_slider, .f_slider, .a_slider {
|
||||
.slider {
|
||||
-webkit-appearance: none;
|
||||
background: #AAAAAA;
|
||||
border-radius: 30px;
|
||||
|
@ -16,15 +16,14 @@
|
|||
}
|
||||
|
||||
/***** 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;
|
||||
background:transparent;
|
||||
height: 0.5rem;
|
||||
}
|
||||
|
||||
|
||||
/******** 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;
|
||||
background-color: transparent;
|
||||
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;
|
||||
appearance: none;
|
||||
height: 0.75rem;
|
||||
|
@ -133,10 +132,6 @@ input.equipment-input {
|
|||
font-weight: bold;
|
||||
}
|
||||
|
||||
.spell-expand {
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
:root {
|
||||
--scaled-fontsize: 2.5rem;
|
||||
}
|
||||
|
@ -449,36 +444,6 @@ a:hover {
|
|||
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 {
|
||||
|
@ -489,16 +454,6 @@ a:hover {
|
|||
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{
|
||||
color: #20c2b6;
|
||||
}
|
||||
|
|
|
@ -182,3 +182,22 @@ Wynn-Related CSS
|
|||
.restrict {
|
||||
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; }
|
|
@ -1889,7 +1889,7 @@
|
|||
<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>
|
||||
<a href="../credits.txt" class="link">Additional credits</a>
|
||||
</div>
|
||||
</footer>
|
||||
</div>
|
||||
|
@ -1906,8 +1906,6 @@
|
|||
<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.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/customizer.js"></script>
|
||||
</body>
|
||||
|
|
|
@ -67,6 +67,6 @@
|
|||
<script type="text/javascript" src="/js/utils.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/dps_vis.js"></script>
|
||||
<script type="text/javascript" src="/js/debug/dps_vis.js"></script>
|
||||
</body>
|
||||
</html>
|
||||
|
|
|
@ -200,8 +200,8 @@
|
|||
"lvl": 75,
|
||||
"ids": {
|
||||
"mr": {
|
||||
"minimum": 1,
|
||||
"maximum": 1
|
||||
"minimum": 5,
|
||||
"maximum": 5
|
||||
},
|
||||
"sdPct": {
|
||||
"minimum": -22,
|
||||
|
@ -9834,7 +9834,7 @@
|
|||
"ids": {
|
||||
"mr": {
|
||||
"minimum": 0,
|
||||
"maximum": 1
|
||||
"maximum": 5
|
||||
}
|
||||
},
|
||||
"itemIDs": {
|
||||
|
@ -10533,7 +10533,7 @@
|
|||
"ids": {
|
||||
"ms": {
|
||||
"minimum": 0,
|
||||
"maximum": 1
|
||||
"maximum": 5
|
||||
}
|
||||
},
|
||||
"itemIDs": {
|
||||
|
@ -10882,8 +10882,8 @@
|
|||
"maximum": 15
|
||||
},
|
||||
"ms": {
|
||||
"minimum": 1,
|
||||
"maximum": 1
|
||||
"minimum": 5,
|
||||
"maximum": 5
|
||||
}
|
||||
},
|
||||
"itemIDs": {
|
||||
|
@ -11906,8 +11906,8 @@
|
|||
"maximum": -5
|
||||
},
|
||||
"ms": {
|
||||
"minimum": 1,
|
||||
"maximum": 1
|
||||
"minimum": 5,
|
||||
"maximum": 5
|
||||
},
|
||||
"gXp": {
|
||||
"minimum": 4,
|
||||
|
@ -14594,8 +14594,8 @@
|
|||
"lvl": 76,
|
||||
"ids": {
|
||||
"ms": {
|
||||
"minimum": 1,
|
||||
"maximum": 1
|
||||
"minimum": 5,
|
||||
"maximum": 5
|
||||
},
|
||||
"spd": {
|
||||
"minimum": -12,
|
||||
|
@ -15404,8 +15404,8 @@
|
|||
"lvl": 28,
|
||||
"ids": {
|
||||
"mr": {
|
||||
"minimum": 1,
|
||||
"maximum": 1
|
||||
"minimum": 5,
|
||||
"maximum": 5
|
||||
},
|
||||
"xpb": {
|
||||
"minimum": -10,
|
||||
|
@ -15569,8 +15569,8 @@
|
|||
"lvl": 102,
|
||||
"ids": {
|
||||
"ms": {
|
||||
"minimum": 1,
|
||||
"maximum": 1
|
||||
"minimum": 5,
|
||||
"maximum": 5
|
||||
},
|
||||
"hpBonus": {
|
||||
"minimum": -260,
|
||||
|
@ -15684,8 +15684,8 @@
|
|||
"lvl": 87,
|
||||
"ids": {
|
||||
"mr": {
|
||||
"minimum": 1,
|
||||
"maximum": 1
|
||||
"minimum": 5,
|
||||
"maximum": 5
|
||||
},
|
||||
"sdRaw": {
|
||||
"minimum": 65,
|
||||
|
@ -15762,8 +15762,8 @@
|
|||
"lvl": 65,
|
||||
"ids": {
|
||||
"ms": {
|
||||
"minimum": 1,
|
||||
"maximum": 1
|
||||
"minimum": 5,
|
||||
"maximum": 5
|
||||
}
|
||||
},
|
||||
"itemIDs": {
|
||||
|
@ -16037,8 +16037,8 @@
|
|||
"lvl": 77,
|
||||
"ids": {
|
||||
"mr": {
|
||||
"minimum": 1,
|
||||
"maximum": 1
|
||||
"minimum": 5,
|
||||
"maximum": 5
|
||||
},
|
||||
"hpBonus": {
|
||||
"minimum": -775,
|
||||
|
@ -16270,8 +16270,8 @@
|
|||
"lvl": 50,
|
||||
"ids": {
|
||||
"mr": {
|
||||
"minimum": -1,
|
||||
"maximum": -1
|
||||
"minimum": -5,
|
||||
"maximum": -5
|
||||
},
|
||||
"sdPct": {
|
||||
"minimum": 8,
|
||||
|
@ -16355,8 +16355,8 @@
|
|||
"lvl": 90,
|
||||
"ids": {
|
||||
"mr": {
|
||||
"minimum": 1,
|
||||
"maximum": 1
|
||||
"minimum": 5,
|
||||
"maximum": 5
|
||||
},
|
||||
"sdPct": {
|
||||
"minimum": 6,
|
||||
|
@ -16396,8 +16396,8 @@
|
|||
"lvl": 90,
|
||||
"ids": {
|
||||
"ms": {
|
||||
"minimum": 1,
|
||||
"maximum": 1
|
||||
"minimum": 5,
|
||||
"maximum": 5
|
||||
},
|
||||
"mdRaw": {
|
||||
"minimum": 50,
|
||||
|
@ -16734,8 +16734,8 @@
|
|||
"maximum": 20
|
||||
},
|
||||
"ms": {
|
||||
"minimum": -1,
|
||||
"maximum": -1
|
||||
"minimum": -5,
|
||||
"maximum": -5
|
||||
},
|
||||
"fDamPct": {
|
||||
"minimum": 10,
|
||||
|
@ -16777,8 +16777,8 @@
|
|||
"lvl": 99,
|
||||
"ids": {
|
||||
"mr": {
|
||||
"minimum": 1,
|
||||
"maximum": 1
|
||||
"minimum": 5,
|
||||
"maximum": 5
|
||||
},
|
||||
"sdPct": {
|
||||
"minimum": 10,
|
||||
|
@ -16944,8 +16944,8 @@
|
|||
"maximum": 10
|
||||
},
|
||||
"mr": {
|
||||
"minimum": 1,
|
||||
"maximum": 1
|
||||
"minimum": 5,
|
||||
"maximum": 5
|
||||
}
|
||||
},
|
||||
"itemIDs": {
|
||||
|
@ -17488,12 +17488,12 @@
|
|||
"lvl": 23,
|
||||
"ids": {
|
||||
"mr": {
|
||||
"minimum": 1,
|
||||
"maximum": 1
|
||||
"minimum": 5,
|
||||
"maximum": 5
|
||||
},
|
||||
"ms": {
|
||||
"minimum": 0,
|
||||
"maximum": 1
|
||||
"maximum": 5
|
||||
}
|
||||
},
|
||||
"itemIDs": {
|
||||
|
@ -18623,8 +18623,8 @@
|
|||
"maximum": -100
|
||||
},
|
||||
"ms": {
|
||||
"minimum": 1,
|
||||
"maximum": 1
|
||||
"minimum": 5,
|
||||
"maximum": 5
|
||||
},
|
||||
"wDamPct": {
|
||||
"minimum": 10,
|
||||
|
@ -18908,8 +18908,8 @@
|
|||
"lvl": 29,
|
||||
"ids": {
|
||||
"mr": {
|
||||
"minimum": 1,
|
||||
"maximum": 1
|
||||
"minimum": 5,
|
||||
"maximum": 5
|
||||
},
|
||||
"sdPct": {
|
||||
"minimum": -8,
|
||||
|
@ -18947,8 +18947,8 @@
|
|||
"lvl": 105,
|
||||
"ids": {
|
||||
"ms": {
|
||||
"minimum": 1,
|
||||
"maximum": 1
|
||||
"minimum": 5,
|
||||
"maximum": 5
|
||||
},
|
||||
"agi": {
|
||||
"minimum": 8,
|
||||
|
@ -19535,8 +19535,8 @@
|
|||
"lvl": 104,
|
||||
"ids": {
|
||||
"ms": {
|
||||
"minimum": 1,
|
||||
"maximum": 1
|
||||
"minimum": 5,
|
||||
"maximum": 5
|
||||
},
|
||||
"gXp": {
|
||||
"minimum": 3,
|
||||
|
@ -21060,8 +21060,8 @@
|
|||
"lvl": 75,
|
||||
"ids": {
|
||||
"ms": {
|
||||
"minimum": 1,
|
||||
"maximum": 1
|
||||
"minimum": 5,
|
||||
"maximum": 5
|
||||
},
|
||||
"int": {
|
||||
"minimum": 3,
|
||||
|
@ -21387,12 +21387,12 @@
|
|||
"lvl": 78,
|
||||
"ids": {
|
||||
"mr": {
|
||||
"minimum": 1,
|
||||
"maximum": 1
|
||||
"minimum": 5,
|
||||
"maximum": 5
|
||||
},
|
||||
"ms": {
|
||||
"minimum": -1,
|
||||
"maximum": -1
|
||||
"minimum": -5,
|
||||
"maximum": -5
|
||||
},
|
||||
"wDamPct": {
|
||||
"minimum": 5,
|
||||
|
@ -21550,8 +21550,8 @@
|
|||
"lvl": 93,
|
||||
"ids": {
|
||||
"ms": {
|
||||
"minimum": 1,
|
||||
"maximum": 1
|
||||
"minimum": 5,
|
||||
"maximum": 5
|
||||
},
|
||||
"sdRaw": {
|
||||
"minimum": 45,
|
||||
|
@ -21595,8 +21595,8 @@
|
|||
"lvl": 20,
|
||||
"ids": {
|
||||
"ms": {
|
||||
"minimum": 1,
|
||||
"maximum": 1
|
||||
"minimum": 5,
|
||||
"maximum": 5
|
||||
},
|
||||
"sdRaw": {
|
||||
"minimum": 8,
|
||||
|
@ -21958,8 +21958,8 @@
|
|||
"lvl": 43,
|
||||
"ids": {
|
||||
"mr": {
|
||||
"minimum": -1,
|
||||
"maximum": -1
|
||||
"minimum": -5,
|
||||
"maximum": -5
|
||||
},
|
||||
"sdPct": {
|
||||
"minimum": 11,
|
||||
|
@ -22216,8 +22216,8 @@
|
|||
"lvl": 75,
|
||||
"ids": {
|
||||
"mr": {
|
||||
"minimum": -1,
|
||||
"maximum": -1
|
||||
"minimum": -5,
|
||||
"maximum": -5
|
||||
},
|
||||
"sdPct": {
|
||||
"minimum": 15,
|
||||
|
@ -22714,8 +22714,8 @@
|
|||
"lvl": 80,
|
||||
"ids": {
|
||||
"mr": {
|
||||
"minimum": 1,
|
||||
"maximum": 1
|
||||
"minimum": 5,
|
||||
"maximum": 5
|
||||
},
|
||||
"sdPct": {
|
||||
"minimum": -20,
|
||||
|
@ -22911,8 +22911,8 @@
|
|||
"lvl": 8,
|
||||
"ids": {
|
||||
"ms": {
|
||||
"minimum": 1,
|
||||
"maximum": 1
|
||||
"minimum": 5,
|
||||
"maximum": 5
|
||||
},
|
||||
"ref": {
|
||||
"minimum": 2,
|
||||
|
@ -22988,8 +22988,8 @@
|
|||
"lvl": 45,
|
||||
"ids": {
|
||||
"mr": {
|
||||
"minimum": 2,
|
||||
"maximum": 2
|
||||
"minimum": 10,
|
||||
"maximum": 10
|
||||
}
|
||||
},
|
||||
"itemIDs": {
|
||||
|
@ -23583,8 +23583,8 @@
|
|||
"lvl": 42,
|
||||
"ids": {
|
||||
"mr": {
|
||||
"minimum": 1,
|
||||
"maximum": 1
|
||||
"minimum": 5,
|
||||
"maximum": 5
|
||||
}
|
||||
},
|
||||
"itemIDs": {
|
||||
|
@ -23878,8 +23878,8 @@
|
|||
"lvl": 50,
|
||||
"ids": {
|
||||
"mr": {
|
||||
"minimum": 1,
|
||||
"maximum": 1
|
||||
"minimum": 5,
|
||||
"maximum": 5
|
||||
},
|
||||
"sdPct": {
|
||||
"minimum": -12,
|
||||
|
@ -23957,8 +23957,8 @@
|
|||
"lvl": 55,
|
||||
"ids": {
|
||||
"ms": {
|
||||
"minimum": 1,
|
||||
"maximum": 1
|
||||
"minimum": 5,
|
||||
"maximum": 5
|
||||
},
|
||||
"spd": {
|
||||
"minimum": 8,
|
||||
|
@ -24035,8 +24035,8 @@
|
|||
"lvl": 43,
|
||||
"ids": {
|
||||
"mr": {
|
||||
"minimum": -2,
|
||||
"maximum": -2
|
||||
"minimum": -10,
|
||||
"maximum": -10
|
||||
},
|
||||
"sdPct": {
|
||||
"minimum": 24,
|
||||
|
@ -24120,8 +24120,8 @@
|
|||
"maximum": 14
|
||||
},
|
||||
"mr": {
|
||||
"minimum": 1,
|
||||
"maximum": 1
|
||||
"minimum": 5,
|
||||
"maximum": 5
|
||||
},
|
||||
"hprRaw": {
|
||||
"minimum": 24,
|
||||
|
@ -24160,8 +24160,8 @@
|
|||
"lvl": 92,
|
||||
"ids": {
|
||||
"mr": {
|
||||
"minimum": 1,
|
||||
"maximum": 1
|
||||
"minimum": 5,
|
||||
"maximum": 5
|
||||
},
|
||||
"sdRaw": {
|
||||
"minimum": 110,
|
||||
|
@ -24373,8 +24373,8 @@
|
|||
"lvl": 90,
|
||||
"ids": {
|
||||
"mr": {
|
||||
"minimum": 1,
|
||||
"maximum": 1
|
||||
"minimum": 5,
|
||||
"maximum": 5
|
||||
},
|
||||
"spd": {
|
||||
"minimum": 16,
|
||||
|
@ -25193,8 +25193,8 @@
|
|||
"maximum": 20
|
||||
},
|
||||
"mr": {
|
||||
"minimum": -1,
|
||||
"maximum": -1
|
||||
"minimum": -5,
|
||||
"maximum": -5
|
||||
}
|
||||
},
|
||||
"itemIDs": {
|
||||
|
@ -25249,8 +25249,8 @@
|
|||
"maximum": 20
|
||||
},
|
||||
"mr": {
|
||||
"minimum": -1,
|
||||
"maximum": -1
|
||||
"minimum": -5,
|
||||
"maximum": -5
|
||||
}
|
||||
},
|
||||
"itemIDs": {
|
||||
|
@ -25285,8 +25285,8 @@
|
|||
"lvl": 83,
|
||||
"ids": {
|
||||
"mr": {
|
||||
"minimum": 2,
|
||||
"maximum": 2
|
||||
"minimum": 10,
|
||||
"maximum": 10
|
||||
}
|
||||
},
|
||||
"itemIDs": {
|
||||
|
@ -25544,8 +25544,8 @@
|
|||
"lvl": 10,
|
||||
"ids": {
|
||||
"mr": {
|
||||
"minimum": 1,
|
||||
"maximum": 1
|
||||
"minimum": 5,
|
||||
"maximum": 5
|
||||
}
|
||||
},
|
||||
"itemIDs": {
|
||||
|
@ -26028,8 +26028,8 @@
|
|||
"lvl": 47,
|
||||
"ids": {
|
||||
"ms": {
|
||||
"minimum": 1,
|
||||
"maximum": 1
|
||||
"minimum": 5,
|
||||
"maximum": 5
|
||||
},
|
||||
"tDamPct": {
|
||||
"minimum": 6,
|
||||
|
@ -26200,8 +26200,8 @@
|
|||
"lvl": 87,
|
||||
"ids": {
|
||||
"mr": {
|
||||
"minimum": 1,
|
||||
"maximum": 1
|
||||
"minimum": 5,
|
||||
"maximum": 5
|
||||
},
|
||||
"eDamPct": {
|
||||
"minimum": 10,
|
||||
|
@ -26769,8 +26769,8 @@
|
|||
"maximum": 12
|
||||
},
|
||||
"ms": {
|
||||
"minimum": 2,
|
||||
"maximum": 2
|
||||
"minimum": 10,
|
||||
"maximum": 10
|
||||
},
|
||||
"atkTier": {
|
||||
"minimum": -1,
|
||||
|
@ -26971,8 +26971,8 @@
|
|||
"lvl": 68,
|
||||
"ids": {
|
||||
"ms": {
|
||||
"minimum": 2,
|
||||
"maximum": 2
|
||||
"minimum": 10,
|
||||
"maximum": 10
|
||||
}
|
||||
},
|
||||
"itemIDs": {
|
||||
|
@ -27344,8 +27344,8 @@
|
|||
"lvl": 25,
|
||||
"ids": {
|
||||
"ms": {
|
||||
"minimum": 1,
|
||||
"maximum": 1
|
||||
"minimum": 5,
|
||||
"maximum": 5
|
||||
}
|
||||
},
|
||||
"itemIDs": {
|
||||
|
|
|
@ -58,6 +58,7 @@
|
|||
<script type="text/javascript" src="/js/build_utils.js"></script>
|
||||
<script type="text/javascript" src="/js/icons.js"></script>
|
||||
<script type="text/javascript" src="/js/damage_calc.js"></script>
|
||||
<script type="text/javascript" src="/js/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_ing.js"></script>
|
||||
|
|
|
@ -140,13 +140,11 @@
|
|||
<script type="text/javascript" src="../js/damage_calc.js"></script>
|
||||
<script type="text/javascript" src="../js/display_constants.js"></script>
|
||||
<script type="text/javascript" src="../js/display.js"></script>
|
||||
<script type="text/javascript" src="../js/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_2.js"></script>
|
||||
<script type="text/javascript" src="../js/expr_parser.js"></script>
|
||||
<script type="text/javascript" src="../js/load.js"></script>
|
||||
<script type="text/javascript" src="../js/items.js"></script>
|
||||
<script type="text/javascript" src="../js/sq2items.js"></script>
|
||||
<script type="text/javascript" src="../js/powders.js"></script>
|
||||
</body>
|
||||
</html>
|
||||
|
|
|
@ -36,7 +36,7 @@
|
|||
<div class = "col">
|
||||
<div class = "row">
|
||||
<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 class = "col text-center" id = "help">
|
||||
<a href="items_2_help.html" class="link" target="_blank">Search Guide</a>
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
How to convert:
|
||||
|
||||
0. start in the `js` directory
|
||||
1. edit `atree_constants.js`
|
||||
2. run `python3 ../py_script/atree-generateID.py
|
||||
3. check that the site still works
|
||||
|
|
947
js/atree.js
|
@ -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
|
||||
}
|
||||
}
|
101
js/build.js
|
@ -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.
|
||||
* @module ItemNotFound
|
||||
/*
|
||||
* Class that represents a wynn player's build.
|
||||
*/
|
||||
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{
|
||||
|
||||
/**
|
||||
|
@ -115,7 +30,6 @@ class Build{
|
|||
this.level = level;
|
||||
} else if (typeof level === "string") {
|
||||
this.level = level;
|
||||
errors.push(new IncorrectInput(level, "a number", "level-choice"));
|
||||
} else {
|
||||
errors.push("Level is not a string or number.");
|
||||
}
|
||||
|
@ -168,7 +82,6 @@ class Build{
|
|||
|
||||
//Create a map of this build's stats
|
||||
let statMap = new Map();
|
||||
statMap.set("defMultiplier", 1);
|
||||
|
||||
for (const staticID of staticIDs) {
|
||||
statMap.set(staticID, 0);
|
||||
|
@ -198,8 +111,10 @@ class Build{
|
|||
}
|
||||
}
|
||||
}
|
||||
statMap.set('damageMultiplier', 1 + (statMap.get('damMobs') / 100));
|
||||
statMap.set('defMultiplier', 1 - (statMap.get('defMobs') / 100));
|
||||
statMap.set('damMult', new Map());
|
||||
statMap.set('defMult', new Map());
|
||||
statMap.get('damMult').set('tome', statMap.get('damMobs'))
|
||||
statMap.get('defMult').set('tome', statMap.get('defMobs'))
|
||||
statMap.set("activeMajorIDs", major_ids);
|
||||
for (const [setName, count] of this.activeSetCounts) {
|
||||
const bonus = sets.get(setName).bonuses[count-1];
|
||||
|
@ -213,6 +128,8 @@ class Build{
|
|||
}
|
||||
}
|
||||
statMap.set("poisonPct", 100);
|
||||
statMap.set("critDamPct", 100);
|
||||
statMap.set("healPct", 100);
|
||||
|
||||
// The stuff relevant for damage calculation!!! @ferricles
|
||||
statMap.set("atkSpd", this.weapon.statMap.get("atkSpd"));
|
||||
|
|
|
@ -7,8 +7,6 @@ const url_tag = location.hash.slice(1);
|
|||
|
||||
const BUILD_VERSION = "7.0.19";
|
||||
|
||||
let player_build;
|
||||
|
||||
|
||||
// THIS IS SUPER DANGEROUS, WE SHOULD NOT BE KEEPING THIS IN SO MANY PLACES
|
||||
let editable_item_fields = [ "sdPct", "sdRaw", "mdPct", "mdRaw", "poison",
|
||||
|
|
|
@ -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) {
|
||||
// TODO: Make this run in linear instead of quadratic time... ew
|
||||
let powdering = [];
|
||||
|
@ -124,7 +130,6 @@ function decodeBuild(url_tag) {
|
|||
for (let i in tomes) {
|
||||
let tome_str = info[1].charAt(i);
|
||||
let tome_name = getTomeNameFromID(Base64.toInt(tome_str));
|
||||
console.log(tome_name);
|
||||
setValue(tomeInputs[i], tome_name);
|
||||
}
|
||||
info[1] = info[1].slice(7);
|
||||
|
@ -200,7 +205,7 @@ function encodeBuild(build, powders, skillpoints, atree, atree_state) {
|
|||
}
|
||||
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);
|
||||
const bitvec = encode_atree(atree, atree_state);
|
||||
build_string += bitvec.toB64();
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
||||
// 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.
|
||||
*
|
||||
* @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",
|
||||
|
||||
// wynn2 damages.
|
||||
"eMdPct","eMdRaw","eSdPct","eSdRaw",/*"eDamPct"*/,"eDamRaw","eDamAddMin","eDamAddMax",
|
||||
"tMdPct","tMdRaw","tSdPct","tSdRaw",/*"tDamPct"*/,"tDamRaw","tDamAddMin","tDamAddMax",
|
||||
"wMdPct","wMdRaw","wSdPct","wSdRaw",/*"wDamPct"*/,"wDamRaw","wDamAddMin","wDamAddMax",
|
||||
"fMdPct","fMdRaw","fSdPct","fSdRaw",/*"fDamPct"*/,"fDamRaw","fDamAddMin","fDamAddMax",
|
||||
"aMdPct","aMdRaw","aSdPct","aSdRaw",/*"aDamPct"*/,"aDamRaw","aDamAddMin","aDamAddMax",
|
||||
"eMdPct","eMdRaw","eSdPct","eSdRaw",/*"eDamPct,"*/"eDamRaw","eDamAddMin","eDamAddMax",
|
||||
"tMdPct","tMdRaw","tSdPct","tSdRaw",/*"tDamPct,"*/"tDamRaw","tDamAddMin","tDamAddMax",
|
||||
"wMdPct","wMdRaw","wSdPct","wSdRaw",/*"wDamPct,"*/"wDamRaw","wDamAddMin","wDamAddMax",
|
||||
"fMdPct","fMdRaw","fSdPct","fSdRaw",/*"fDamPct,"*/"fDamRaw","fDamAddMin","fDamAddMax",
|
||||
"aMdPct","aMdRaw","aSdPct","aSdRaw",/*"aDamPct,"*/"aDamRaw","aDamAddMin","aDamAddMax",
|
||||
"nMdPct","nMdRaw","nSdPct","nSdRaw","nDamPct","nDamRaw","nDamAddMin","nDamAddMax", // neutral which is now an element
|
||||
/*"mdPct","mdRaw","sdPct","sdRaw",*/"damPct","damRaw","damAddMin","damAddMax", // These are the old ids. Become proportional.
|
||||
"rMdPct","rMdRaw","rSdPct",/*"rSdRaw",*/"rDamPct","rDamRaw","rDamAddMin","rDamAddMax", // rainbow (the "element" of all minus neutral). rSdRaw is rainraw
|
||||
"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" ]
|
||||
|
||||
//File reading for ID translations for JSON purposes
|
||||
|
@ -164,11 +169,11 @@ let rolledIDs = [
|
|||
"gXp",
|
||||
"gSpd",
|
||||
// wynn2 damages.
|
||||
"eMdPct","eMdRaw","eSdPct","eSdRaw",/*"eDamPct"*/,"eDamRaw","eDamAddMin","eDamAddMax",
|
||||
"tMdPct","tMdRaw","tSdPct","tSdRaw",/*"tDamPct"*/,"tDamRaw","tDamAddMin","tDamAddMax",
|
||||
"wMdPct","wMdRaw","wSdPct","wSdRaw",/*"wDamPct"*/,"wDamRaw","wDamAddMin","wDamAddMax",
|
||||
"fMdPct","fMdRaw","fSdPct","fSdRaw",/*"fDamPct"*/,"fDamRaw","fDamAddMin","fDamAddMax",
|
||||
"aMdPct","aMdRaw","aSdPct","aSdRaw",/*"aDamPct"*/,"aDamRaw","aDamAddMin","aDamAddMax",
|
||||
"eMdPct","eMdRaw","eSdPct","eSdRaw",/*"eDamPct,"*/"eDamRaw","eDamAddMin","eDamAddMax",
|
||||
"tMdPct","tMdRaw","tSdPct","tSdRaw",/*"tDamPct,"*/"tDamRaw","tDamAddMin","tDamAddMax",
|
||||
"wMdPct","wMdRaw","wSdPct","wSdRaw",/*"wDamPct,"*/"wDamRaw","wDamAddMin","wDamAddMax",
|
||||
"fMdPct","fMdRaw","fSdPct","fSdRaw",/*"fDamPct,"*/"fDamRaw","fDamAddMin","fDamAddMax",
|
||||
"aMdPct","aMdRaw","aSdPct","aSdRaw",/*"aDamPct,"*/"aDamRaw","aDamAddMin","aDamAddMax",
|
||||
"nMdPct","nMdRaw","nSdPct","nSdRaw","nDamPct","nDamRaw","nDamAddMin","nDamAddMax", // neutral which is now an element
|
||||
/*"mdPct","mdRaw","sdPct","sdRaw",*/"damPct","damRaw","damAddMin","damAddMax", // These are the old ids. Become proportional.
|
||||
"rMdPct","rMdRaw","rSdPct",/*"rSdRaw",*/"rDamPct","rDamRaw","rDamAddMin","rDamAddMax" // rainbow (the "element" of all minus neutral). rSdRaw is rainraw
|
||||
|
@ -295,3 +300,28 @@ function idRound(id){
|
|||
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); }
|
||||
}
|
||||
|
|
|
@ -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() {
|
||||
const buildList = document.getElementById("build-choice");
|
||||
|
@ -98,7 +83,6 @@ function resetFields(){
|
|||
for (const elem of skp_order) {
|
||||
console.log(document.getElementById(elem + "_boost_armor").value);
|
||||
document.getElementById(elem + "_boost_armor").value = 0;
|
||||
document.getElementById(elem + "_boost_armor_prev").value = 0;
|
||||
document.getElementById(elem + "_boost_armor").style.background = `linear-gradient(to right, #AAAAAA, #AAAAAA 0%, #AAAAAA 100%)`;
|
||||
document.getElementById(elem + "_boost_armor_label").textContent = `% ${damageClasses[skp_order.indexOf(elem)+1]} Damage Boost: 0`;
|
||||
}
|
||||
|
@ -149,7 +133,6 @@ function toggle_tab(tab) {
|
|||
}
|
||||
}
|
||||
|
||||
|
||||
function toggle_boost_tab(tab) {
|
||||
for (const i of skp_order) {
|
||||
document.querySelector("#"+i+"-boost").style.display = "none";
|
||||
|
@ -157,13 +140,10 @@ function toggle_boost_tab(tab) {
|
|||
}
|
||||
document.querySelector("#"+tab+"-boost").style.display = "";
|
||||
document.getElementById(tab + "-boost-tab").classList.add("selected-btn");
|
||||
|
||||
}
|
||||
|
||||
let tabs = ['overall-stats', 'offensive-stats', 'defensive-stats'];
|
||||
function show_tab(tab) {
|
||||
//console.log(itemFilters)
|
||||
|
||||
//hide all tabs, then show the tab of the div clicked and highlight the correct button
|
||||
for (const i in tabs) {
|
||||
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) {
|
||||
|
@ -394,6 +329,19 @@ function init() {
|
|||
for (const eq of equipment_keys) {
|
||||
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
|
||||
let masonry = Macy({
|
||||
|
@ -425,6 +373,15 @@ function init() {
|
|||
});
|
||||
decodeBuild(url_tag);
|
||||
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) {
|
||||
|
|
|
@ -11,29 +11,7 @@ let armor_powder_node = new (class extends ComputeNode {
|
|||
}
|
||||
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 {
|
||||
constructor() { super('builder-boost-input'); }
|
||||
|
@ -45,13 +23,13 @@ let boosts_node = new (class extends ComputeNode {
|
|||
let elem = document.getElementById(key + "-boost")
|
||||
if (elem.classList.contains("toggleOn")) {
|
||||
damage_boost += value;
|
||||
if (key === "warscream") { def_boost += .20 }
|
||||
if (key === "warscream") { def_boost += .10 }
|
||||
if (key === "vanish") { def_boost += .15 }
|
||||
}
|
||||
}
|
||||
let res = new Map();
|
||||
res.set('damageMultiplier', 1+damage_boost);
|
||||
res.set('defMultiplier', 1-def_boost);
|
||||
res.set('damMult.Potion', 100*damage_boost);
|
||||
res.set('defMult.Potion', 100*def_boost);
|
||||
return res;
|
||||
}
|
||||
})().update();
|
||||
|
@ -181,7 +159,8 @@ class ItemInputNode extends InputNode {
|
|||
|
||||
if (item) {
|
||||
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;
|
||||
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 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 null;
|
||||
|
@ -257,7 +242,7 @@ class ItemInputDisplayNode extends ComputeNode {
|
|||
this.input_field.classList.add("is-invalid");
|
||||
return null;
|
||||
}
|
||||
if (item.statMap.has('powders')) {
|
||||
if (this.powder_field && item.statMap.has('powders')) {
|
||||
this.powder_field.placeholder = "powders";
|
||||
}
|
||||
|
||||
|
@ -265,7 +250,7 @@ class ItemInputDisplayNode extends ComputeNode {
|
|||
return null;
|
||||
}
|
||||
|
||||
if (item.statMap.has('powders')) {
|
||||
if (this.powder_field && item.statMap.has('powders')) {
|
||||
this.powder_field.placeholder = item.statMap.get('slots') + ' slots';
|
||||
}
|
||||
|
||||
|
@ -422,7 +407,10 @@ class BuildAssembleNode extends ComputeNode {
|
|||
input_map.get('guildTome1-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');
|
||||
for (const item of equipments) {
|
||||
|
@ -502,16 +490,22 @@ class SpellSelectNode extends ComputeNode {
|
|||
*/
|
||||
function getDefenseStats(stats) {
|
||||
let defenseStats = [];
|
||||
let def_pct = skillPointsToPercentage(stats.get('def'));
|
||||
let agi_pct = skillPointsToPercentage(stats.get('agi'));
|
||||
let def_pct = skillPointsToPercentage(stats.get('def')) * skillpoint_final_mult[3];
|
||||
let agi_pct = skillPointsToPercentage(stats.get('agi')) * skillpoint_final_mult[4];
|
||||
//total hp
|
||||
let totalHp = stats.get("hp") + stats.get("hpBonus");
|
||||
if (totalHp < 5) totalHp = 5;
|
||||
defenseStats.push(totalHp);
|
||||
//EHP
|
||||
let ehp = [totalHp, totalHp];
|
||||
let defMult = (2 - stats.get("classDef")) * stats.get("defMultiplier");
|
||||
ehp[0] /= (1-def_pct)*(1-agi_pct)*defMult;
|
||||
let defMult = (2 - stats.get("classDef"));
|
||||
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;
|
||||
defenseStats.push(ehp);
|
||||
//HPR
|
||||
|
@ -554,7 +548,6 @@ class SpellDamageCalcNode extends ComputeNode {
|
|||
const spell = spell_info[0];
|
||||
const spell_parts = spell_info[1];
|
||||
const stats = input_map.get('stats');
|
||||
const damage_mult = stats.get('damageMultiplier');
|
||||
const skillpoints = [
|
||||
stats.get('str'),
|
||||
stats.get('dex'),
|
||||
|
@ -571,7 +564,7 @@ class SpellDamageCalcNode extends ComputeNode {
|
|||
for (const part of spell_parts) {
|
||||
let spell_result;
|
||||
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 = {
|
||||
type: "damage",
|
||||
normal_min: results[2].map(x => x[0]),
|
||||
|
@ -583,7 +576,7 @@ class SpellDamageCalcNode extends ComputeNode {
|
|||
}
|
||||
} else if ('power' in part) {
|
||||
// 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 = {
|
||||
type: "heal",
|
||||
heal_amount: _heal_amount
|
||||
|
@ -663,59 +656,10 @@ class SpellDisplayNode extends ComputeNode {
|
|||
const i = this.spell_idx;
|
||||
let parent_elem = document.getElementById("spell"+i+"-info");
|
||||
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.
|
||||
*
|
||||
|
@ -730,10 +674,7 @@ class BuildDisplayNode extends ComputeNode {
|
|||
displayBuildStats('overall-stats', build, build_all_display_commands, stats);
|
||||
displayBuildStats("offensive-stats", build, build_offensive_display_commands, stats);
|
||||
displaySetBonuses("set-info", build);
|
||||
let meleeStats = getMeleeStats(stats, build.weapon);
|
||||
// TODO: move weapon out?
|
||||
displayMeleeDamage(document.getElementById("build-melee-stats"), document.getElementById("build-melee-statsAvg"), meleeStats);
|
||||
|
||||
displayDefenseStats(document.getElementById("defensive-stats"), stats);
|
||||
|
||||
displayPoisonDamage(document.getElementById("build-poison-stats"), build);
|
||||
|
@ -770,7 +711,7 @@ class DisplayBuildWarningsNode extends ComputeNode {
|
|||
setValue(skp_order[i] + "-skp", skillpoints[i]);
|
||||
let linebreak = document.createElement("br");
|
||||
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 = ''
|
||||
if (assigned > 100) {
|
||||
let skp_warning = document.createElement("p");
|
||||
|
@ -859,18 +800,7 @@ class AggregateStatsNode extends ComputeNode {
|
|||
const output_stats = new Map();
|
||||
for (const [k, v] of input_map.entries()) {
|
||||
for (const [k2, v2] of v.entries()) {
|
||||
if (output_stats.has(k2)) {
|
||||
// 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);
|
||||
}
|
||||
merge_stat(output_stats, k2, v2);
|
||||
}
|
||||
}
|
||||
return output_stats;
|
||||
|
@ -972,7 +902,7 @@ class SkillPointSetterNode extends ComputeNode {
|
|||
class SumNumberInputNode extends InputNode {
|
||||
compute_func(input_map) {
|
||||
let value = this.input_field.value;
|
||||
if (value === "") { value = 0; }
|
||||
if (value === "") { value = "0"; }
|
||||
|
||||
let input_num = 0;
|
||||
if (value.includes("+")) {
|
||||
|
@ -1035,6 +965,9 @@ function builder_graph_init() {
|
|||
// Level input node.
|
||||
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_node = new BuildAssembleNode();
|
||||
for (const input of item_nodes) {
|
||||
|
@ -1063,9 +996,6 @@ function builder_graph_init() {
|
|||
|
||||
// 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)
|
||||
stat_agg_node = new AggregateStatsNode();
|
||||
edit_agg_node = new AggregateEditableIDNode();
|
||||
|
@ -1092,16 +1022,15 @@ function builder_graph_init() {
|
|||
skp_inputs.push(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.
|
||||
|
||||
let class_node = new PlayerClassNode('builder-class').link_to(build_node);
|
||||
// These two are defined in `atree.js`
|
||||
atree_node.link_to(class_node, 'player-class');
|
||||
atree_merge.link_to(build_node, 'build');
|
||||
atree_graph_creator = new AbilityTreeEnsureNodesNode(build_node, stat_agg_node)
|
||||
.link_to(atree_collect_spells, 'spells');
|
||||
atree_merge.link_to(class_node, 'player-class');
|
||||
atree_stats.link_to(build_node, 'build');
|
||||
stat_agg_node.link_to(atree_stats, 'atree-stats');
|
||||
|
||||
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)) {
|
||||
input_node.update();
|
||||
}
|
||||
armor_powder_node.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
|
||||
if (atree_data !== null && atree_node.value !== null) { // janky check if atree is valid
|
||||
const atree_state = atree_state_node.value;
|
||||
|
@ -1138,6 +1071,10 @@ function builder_graph_init() {
|
|||
|
||||
// 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) {
|
||||
node.update();
|
||||
}
|
||||
|
@ -1157,5 +1094,6 @@ function builder_graph_init() {
|
|||
// this will propagate the update to the `stat_agg_node`, and then to damage calc
|
||||
|
||||
console.log("Set up graph");
|
||||
graph_live_update = true;
|
||||
}
|
||||
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
let all_nodes = [];
|
||||
let node_debug_stack = [];
|
||||
class ComputeNode {
|
||||
/**
|
||||
* Make a generic compute node.
|
||||
|
@ -33,6 +34,7 @@ class ComputeNode {
|
|||
if (this.dirty === 0) {
|
||||
return;
|
||||
}
|
||||
node_debug_stack.push(this.name);
|
||||
if (this.dirty == 2) {
|
||||
let calc_inputs = new Map();
|
||||
for (const input of this.inputs) {
|
||||
|
@ -44,6 +46,7 @@ class ComputeNode {
|
|||
for (const child of this.children) {
|
||||
child.mark_input_clean(this.name, this.value);
|
||||
}
|
||||
node_debug_stack.pop();
|
||||
return this;
|
||||
}
|
||||
|
||||
|
@ -174,17 +177,20 @@ class ValueCheckComputeNode extends ComputeNode {
|
|||
|
||||
}
|
||||
|
||||
let graph_live_update = false;
|
||||
/**
|
||||
* Schedule a ComputeNode to be updated.
|
||||
*
|
||||
* @param node : ComputeNode to schedule an update for.
|
||||
*/
|
||||
function calcSchedule(node, timeout) {
|
||||
if (!graph_live_update) return;
|
||||
if (node.update_task !== null) {
|
||||
clearTimeout(node.update_task);
|
||||
}
|
||||
node.mark_dirty();
|
||||
node.update_task = setTimeout(function() {
|
||||
node_debug_stack = [];
|
||||
node.update();
|
||||
node.update_task = null;
|
||||
}, timeout);
|
||||
|
|
|
@ -44,14 +44,16 @@ function init_crafter() {
|
|||
try {
|
||||
document.getElementById("recipe-choice").addEventListener("change", (event) => {
|
||||
updateMaterials();
|
||||
updateCraftedImage();
|
||||
calculateCraftSchedule();
|
||||
});
|
||||
document.getElementById("recipe-choice").addEventListener("oninput", (event) => {
|
||||
updateCraftedImage();
|
||||
});
|
||||
document.getElementById("level-choice").addEventListener("change", (event) => {
|
||||
updateMaterials();
|
||||
calculateCraftSchedule();
|
||||
});
|
||||
document.getElementById("recipe-choice").setAttribute("oninput", "updateCraftedImage()");
|
||||
document.getElementById("recipe-choice").setAttribute("change", "updateCraftedImage()");
|
||||
|
||||
for (let i = 1; i < 4; ++i) {
|
||||
document.getElementById("mat-1-"+i).setAttribute("onclick", document.getElementById("mat-1-"+i).getAttribute("onclick") + "; calculateCraftSchedule();");
|
||||
|
@ -177,7 +179,7 @@ function calculateCraft() {
|
|||
//Display Craft Stats
|
||||
// displayCraftStats(player_craft, "craft-stats");
|
||||
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");
|
||||
|
||||
//Display Ingredients' Stats
|
||||
|
|
|
@ -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) {
|
||||
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
|
||||
|
||||
// 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 {
|
||||
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.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.
|
||||
let damages = [];
|
||||
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.
|
||||
// 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) {
|
||||
if (conversions[i] > 0) {
|
||||
const conv_frac = conversions[i]/100;
|
||||
|
@ -66,9 +87,7 @@ function calculateSpellDamage(stats, weapon, conversions, use_spell_damage, igno
|
|||
total_convert += conv_frac
|
||||
}
|
||||
}
|
||||
|
||||
// Also theres prop and rainbow!!
|
||||
const damage_elements = ['n'].concat(skp_elements); // netwfa
|
||||
total_convert += conversions[0]/100;
|
||||
|
||||
if (!ignore_speed) {
|
||||
// 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?
|
||||
for (let i = 0; i < 6; ++i) {
|
||||
for (let i in damage_elements) {
|
||||
if (present[i]) {
|
||||
damages[i][0] += stats.get(damage_elements[i]+'DamAddMin');
|
||||
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
|
||||
let skill_boost = [0]; // no neutral skillpoint booster
|
||||
for (const skp of skp_order) {
|
||||
skill_boost.push(skillPointsToPercentage(stats.get(skp)));
|
||||
for (let i in skp_order) {
|
||||
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;
|
||||
|
||||
// These do not count raw damage. I think. Easy enough to change
|
||||
let total_min = 0;
|
||||
let total_max = 0;
|
||||
for (let i in damages) {
|
||||
let damage_prefix = damage_elements[i] + specific_boost_str;
|
||||
for (let i in damage_elements) {
|
||||
let damage_specific = damage_elements[i] + specific_boost_str + 'Pct';
|
||||
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][1] *= Math.max(damageBoost, 0);
|
||||
// Collect total damage post %boost
|
||||
|
@ -131,13 +151,21 @@ function calculateSpellDamage(stats, weapon, conversions, use_spell_damage, igno
|
|||
let min_boost = raw_boost;
|
||||
let max_boost = raw_boost;
|
||||
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;
|
||||
}
|
||||
max_boost += (damages_obj[1] / total_max) * prop_raw;
|
||||
}
|
||||
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;
|
||||
}
|
||||
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_crit = [0, 0];
|
||||
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) {
|
||||
const res = [
|
||||
damage[0] * strBoost * damage_mult, // Normal min
|
||||
damage[1] * strBoost * damage_mult, // Normal max
|
||||
damage[0] * (strBoost + 1) * damage_mult, // Crit min
|
||||
damage[1] * (strBoost + 1) * damage_mult, // Crit max
|
||||
damage[0] * (strBoost + crit_mult) * damage_mult, // Crit min
|
||||
damage[1] * (strBoost + crit_mult) * damage_mult, // Crit max
|
||||
];
|
||||
damages_results.push(res);
|
||||
total_dam_norm[0] += res[0];
|
||||
|
@ -245,15 +286,6 @@ const default_spells = {
|
|||
scaling: "melee", use_atkspd: false,
|
||||
display: "Melee",
|
||||
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: [{
|
||||
type: "replace_spell", // not needed but makes this usable as an "abil part"
|
||||
|
@ -294,130 +326,6 @@ const default_spells = {
|
|||
};
|
||||
|
||||
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.
|
||||
{ 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},
|
||||
|
|
541
js/display.js
|
@ -5,13 +5,10 @@ function apply_elemental_format(p_elem, id, suffix) {
|
|||
let parts = idPrefixes[id].split(/ (.*)/);
|
||||
let element_prefix = parts[0];
|
||||
let desc = parts[1];
|
||||
let i_elem = document.createElement('span');
|
||||
i_elem.classList.add(element_prefix);
|
||||
i_elem.textContent = element_prefix;
|
||||
let i_elem = make_elem('span', [element_prefix], {textContent: element_prefix});
|
||||
p_elem.appendChild(i_elem);
|
||||
|
||||
let i_elem2 = document.createElement('span');
|
||||
i_elem2.textContent = " " + desc + suffix;
|
||||
let i_elem2 = make_elem('span', [], {textContent: " "+desc+suffix});
|
||||
p_elem.appendChild(i_elem2);
|
||||
}
|
||||
|
||||
|
@ -19,17 +16,14 @@ function displaySetBonuses(parent_id,build) {
|
|||
setHTML(parent_id, "");
|
||||
let parent_div = document.getElementById(parent_id);
|
||||
|
||||
let set_summary_elem = document.createElement('p');
|
||||
set_summary_elem.classList.add('text-center');
|
||||
set_summary_elem.textContent = "Set Bonuses";
|
||||
let set_summary_elem = make_elem('p', ['text-center'], {textContent: "Set Bonuses"});
|
||||
parent_div.append(set_summary_elem);
|
||||
|
||||
for (const [setName, count] of build.activeSetCounts) {
|
||||
const active_set = sets.get(setName);
|
||||
if (active_set["hidden"]) { continue; }
|
||||
|
||||
let set_elem = document.createElement('p');
|
||||
set_elem.id = "set-"+setName;
|
||||
let set_elem = make_elem('p', [], {id: "set-"+setName});
|
||||
set_summary_elem.append(set_elem);
|
||||
|
||||
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);
|
||||
if (id === "poison" && id_val > 0) {
|
||||
let row = document.createElement('div');
|
||||
row.classList.add("row")
|
||||
let value_elem = document.createElement('div');
|
||||
value_elem.classList.add('col');
|
||||
value_elem.classList.add('text-end');
|
||||
let row = make_elem('div', ['row']);
|
||||
let value_elem = make_elem('div', ['col', 'text-end']);
|
||||
|
||||
let prefix_elem = document.createElement('b');
|
||||
prefix_elem.textContent = "\u279C With Strength: ";
|
||||
let number_elem = document.createElement('b');
|
||||
number_elem.classList.add(style);
|
||||
number_elem.textContent = (id_val * (1+skillPointsToPercentage(stats.get('str'))) ).toFixed(0) + idSuffixes[id];
|
||||
let prefix_elem = make_elem('b', [], {textContent: "\u279C With Strength: "});
|
||||
let number_elem = make_elem('b', [style], {
|
||||
textContent: (id_val * (1+skillPointsToPercentage(stats.get('str'))) ).toFixed(0) + idSuffixes[id]
|
||||
});
|
||||
value_elem.append(prefix_elem);
|
||||
value_elem.append(number_elem);
|
||||
row.appendChild(value_elem);
|
||||
parent_div.appendChild(row);
|
||||
}
|
||||
else if (id === "ls" && id_val != 0) {
|
||||
let row = document.createElement('div');
|
||||
row.classList.add("row")
|
||||
let value_elem = document.createElement('div');
|
||||
value_elem.classList.add('col');
|
||||
value_elem.classList.add('text-end');
|
||||
let row = make_elem('div', ['row']);
|
||||
let value_elem = make_elem('div', ['col', 'text-end']);
|
||||
|
||||
let prefix_elem = document.createElement('b');
|
||||
prefix_elem.textContent = "\u279C Effective LS: ";
|
||||
let prefix_elem = make_elem('b', [], {textContent: "\u279C Effective LS: "});
|
||||
|
||||
let defStats = getDefenseStats(stats);
|
||||
let number_elem = document.createElement('b');
|
||||
number_elem.classList.add(style);
|
||||
number_elem.textContent = Math.round(defStats[1][0]*id_val/defStats[0]) + "/3s";
|
||||
let number_elem = make_elem('b', [style], {
|
||||
textContent: Math.round(defStats[1][0]*id_val/defStats[0]) + "/3s"
|
||||
});
|
||||
value_elem.append(prefix_elem);
|
||||
value_elem.append(number_elem);
|
||||
row.appendChild(value_elem);
|
||||
|
@ -195,8 +181,7 @@ function displayExpandedItem(item, parent_id){
|
|||
elemental_format = !elemental_format;
|
||||
}
|
||||
else if (command === "!spacer") {
|
||||
let spacer = document.createElement('div');
|
||||
spacer.classList.add("row", "my-2");
|
||||
let spacer = make_elem('div', ["row", "my-2"], {});
|
||||
parent_div.appendChild(spacer);
|
||||
continue;
|
||||
}
|
||||
|
@ -205,49 +190,41 @@ function displayExpandedItem(item, parent_id){
|
|||
let id = command;
|
||||
if(nonRolledIDs.includes(id)){//nonRolledID & non-0/non-null/non-und 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)))) {
|
||||
continue;
|
||||
}
|
||||
}
|
||||
if (id === "slots") {
|
||||
let p_elem = document.createElement("div");
|
||||
p_elem.classList.add("col");
|
||||
let p_elem = make_elem("div", ["col"]);
|
||||
|
||||
// PROPER POWDER DISPLAYING
|
||||
let numerals = new Map([[1, "I"], [2, "II"], [3, "III"], [4, "IV"], [5, "V"], [6, "VI"]]);
|
||||
|
||||
let powderPrefix = document.createElement("b");
|
||||
powderPrefix.textContent = "Powder Slots: " + item.get(id) + " [";
|
||||
p_elem.appendChild(powderPrefix);
|
||||
p_elem.appendChild(make_elem("b", [], {
|
||||
textContent: "Powder Slots: " + item.get(id) + " ["
|
||||
}));
|
||||
|
||||
let powders = item.get("powders");
|
||||
for (let i = 0; i < powders.length; i++) {
|
||||
let powder = document.createElement("b");
|
||||
powder.textContent = numerals.get((powders[i]%6)+1)+" ";
|
||||
powder.classList.add(damageClasses[Math.floor(powders[i]/6)+1]+"_powder");
|
||||
p_elem.appendChild(powder);
|
||||
p_elem.appendChild(make_elem("b", [damageClasses[Math.floor(powders[i]/6)+1]+"_powder"], {
|
||||
textContent: numerals.get((powders[i]%6)+1)+" "
|
||||
}));
|
||||
}
|
||||
|
||||
let powderSuffix = document.createElement("b");
|
||||
powderSuffix.textContent = "]";
|
||||
p_elem.appendChild(powderSuffix);
|
||||
p_elem.appendChild(make_elem("b", [], { textContent: "]" }));
|
||||
parent_div.appendChild(p_elem);
|
||||
} else if (id === "set") {
|
||||
if (item.get("hideSet")) { continue; }
|
||||
|
||||
let p_elem = document.createElement("div");
|
||||
p_elem.classList.add("col");
|
||||
p_elem.textContent = "Set: " + item.get(id).toString();
|
||||
parent_div.appendChild(p_elem);
|
||||
parent_div.appendChild(make_elem("div", ["col"], { textContent: "Set: " + item.get(id).toString() }));
|
||||
} else if (id === "majorIds") {
|
||||
//console.log(item.get(id));
|
||||
for (let majorID of item.get(id)) {
|
||||
let p_elem = document.createElement("div");
|
||||
p_elem.classList.add("col");
|
||||
let p_elem = make_elem("div", ['col']);
|
||||
|
||||
let title_elem = document.createElement("b");
|
||||
let b_elem = document.createElement("b");
|
||||
let title_elem = make_elem("b");
|
||||
let b_elem = make_elem("b");
|
||||
if (majorID.includes(":")) {
|
||||
let name = majorID.substring(0, majorID.indexOf(":")+1);
|
||||
let mid = majorID.substring(majorID.indexOf(":")+1);
|
||||
|
@ -268,20 +245,30 @@ function displayExpandedItem(item, parent_id){
|
|||
parent_div.appendChild(p_elem);
|
||||
}
|
||||
} else if (id === "lvl" && item.get("tier") === "Crafted") {
|
||||
let p_elem = document.createElement("div");
|
||||
p_elem.classList.add("col");
|
||||
p_elem.textContent = "Combat Level Min: " + item.get("lvlLow") + "-" + item.get(id);
|
||||
parent_div.appendChild(p_elem);
|
||||
parent_div.appendChild(make_elem("div", ["col"], {
|
||||
textContent: "Combat Level Min: " + item.get("lvlLow") + "-" + item.get(id)
|
||||
}));
|
||||
} else if (id === "displayName") {
|
||||
let row = document.createElement("div");
|
||||
let row = make_elem("div", ["row", "justify-content-center"]);
|
||||
|
||||
let a_elem = document.createElement("a");
|
||||
row.classList.add("row", "justify-content-center");
|
||||
a_elem.classList.add("col-auto", "text-center", "item-title", "p-0");
|
||||
a_elem.classList.add(item.has("tier") ? item.get("tier").replace(" ","") : "Normal");
|
||||
// a_elem.style.textGrow = 1;
|
||||
let nolink_row = make_elem("div", ["row", "justify-content-center"]);
|
||||
nolink_row.style.display = "none";
|
||||
|
||||
row.appendChild(a_elem);
|
||||
const tier_class = item.has("tier") ? item.get("tier").replace(" ","") : "Normal";
|
||||
let item_link;
|
||||
if (item.get("custom")) {
|
||||
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).
|
||||
|
@ -295,50 +282,23 @@ function displayExpandedItem(item, parent_id){
|
|||
//plusminus.style.flexGrow = 0;
|
||||
//plusminus.textContent = "\u2795";
|
||||
//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);
|
||||
|
||||
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);
|
||||
|
||||
let img = document.createElement("img");
|
||||
if (item && item.has("type")) {
|
||||
img.src = "../media/items/" + (newIcons ? "new/":"old/") + "generic-" + item.get("type") + ".png";
|
||||
img.alt = item.get("type");
|
||||
img.style = " z=index: 1; position: relative;";
|
||||
let container = document.createElement("div");
|
||||
if (item.has("type")) {
|
||||
let img = make_elem("img", [], {
|
||||
src: "../media/items/" + (newIcons ? "new/":"old/") + "generic-" + item.get("type") + ".png",
|
||||
alt: item.get("type"),
|
||||
style: " z=index: 1; position: relative;"
|
||||
});
|
||||
let container = make_elem("div");
|
||||
|
||||
let bckgrd = document.createElement("div");
|
||||
bckgrd.classList.add("col", "px-0", "d-flex", "align-items-center", "justify-content-center");// , "no-collapse");
|
||||
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);
|
||||
let bckgrd = make_elem("div", ["col", "px-0", "d-flex", "align-items-center", "justify-content-center", 'scaled-bckgrd'], { // , "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.appendChild(img);
|
||||
container.appendChild(bckgrd);
|
||||
parent_div.appendChild(container);
|
||||
}
|
||||
} else {
|
||||
if (id.endsWith('Dam_')) {
|
||||
|
@ -365,8 +325,7 @@ function displayExpandedItem(item, parent_id){
|
|||
p_elem.style = "font-style: italic";
|
||||
} else if (skp_order.includes(id)) { //id = str, dex, int, def, or agi
|
||||
if ( item.get("tier") !== "Crafted") {
|
||||
row = document.createElement("div");
|
||||
row.classList.add("col");
|
||||
row = make_elem("div", ["col"]);
|
||||
|
||||
let title = document.createElement("b");
|
||||
title.textContent = idPrefixes[id] + " ";
|
||||
|
@ -550,9 +509,6 @@ function displayExpandedItem(item, parent_id){
|
|||
*/
|
||||
function displayRecipeStats(craft, parent_id) {
|
||||
let elem = document.getElementById(parent_id);
|
||||
if (!elem.classList.contains("col")) {
|
||||
elem.classList.add("col");
|
||||
}
|
||||
|
||||
//local vars
|
||||
elem.textContent = "";
|
||||
|
@ -565,91 +521,85 @@ function displayRecipeStats(craft, parent_id) {
|
|||
let effectiveness = craft["statMap"].get("ingredEffectiveness");
|
||||
|
||||
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";
|
||||
elem.appendChild(title);
|
||||
|
||||
let mats = document.createElement("div");
|
||||
mats.classList.add("row");
|
||||
mats.classList.add("col");
|
||||
mats.textContent = "Crafting Materials: ";
|
||||
elem.appendChild(mats);
|
||||
|
||||
for (let i = 0; i < 2; i++) {
|
||||
let tier = mat_tiers[i];
|
||||
let row = document.createElement("div");
|
||||
row.classList.add("row", "px-0", "mx-0");
|
||||
let b = document.createElement("div");
|
||||
let col = document.createElement("div");
|
||||
col.classList.add("col", "ps-4");
|
||||
let b = document.createElement("span");
|
||||
let mat = recipe.get("materials")[i];
|
||||
b.textContent = "- " + mat.get("amount") + "x " + mat.get("item").split(" ").slice(1).join(" ");
|
||||
b.classList.add("col");
|
||||
row.appendChild(b);
|
||||
col.appendChild(b);
|
||||
|
||||
let starsB = document.createElement("div");
|
||||
starsB.classList.add("T1-bracket", "col-auto", "px-0");
|
||||
let starsContainer = document.createElement("span");
|
||||
let starsB = document.createElement("span");
|
||||
starsB.classList.add("T1-bracket", "px-0");
|
||||
starsB.textContent = "[";
|
||||
row.appendChild(starsB);
|
||||
starsContainer.appendChild(starsB);
|
||||
for(let j = 0; j < 3; j ++) {
|
||||
let star = document.createElement("div");
|
||||
star.classList.add("col-auto", "px-0");
|
||||
let star = document.createElement("span");
|
||||
star.classList.add("px-0");
|
||||
star.textContent = "\u272B";
|
||||
if(j < tier) {
|
||||
star.classList.add("T1");
|
||||
} else {
|
||||
star.classList.add("T0");
|
||||
}
|
||||
row.append(star);
|
||||
starsContainer.append(star);
|
||||
}
|
||||
let starsE = document.createElement("div");
|
||||
starsE.classList.add("T1-bracket", "col-auto", "px-0");
|
||||
let starsE = document.createElement("span");
|
||||
starsE.classList.add("T1-bracket", "px-0");
|
||||
starsE.textContent = "]";
|
||||
row.appendChild(starsE);
|
||||
starsContainer.appendChild(starsE);
|
||||
|
||||
elem.appendChild(row);
|
||||
col.appendChild(starsContainer);
|
||||
|
||||
elem.appendChild(col);
|
||||
}
|
||||
|
||||
let ingredTable = document.createElement("div");
|
||||
ingredTable.classList.add("row");
|
||||
ingredTable.classList.add("col", "mt-2");
|
||||
|
||||
for (let i = 0; i < 3; i++) {
|
||||
let row = document.createElement("div");
|
||||
row.classList.add("row", "g-1", "justify-content-center");
|
||||
let ingredContainer = document.createElement("div");
|
||||
ingredContainer.classList.add("row", "row-cols-2", "g-3");
|
||||
for (let i = 0; i < 6; i++) {
|
||||
let ingredCell = document.createElement("div");
|
||||
ingredCell.classList.add("col");
|
||||
|
||||
let ingredTextContainer = document.createElement("div");
|
||||
ingredTextContainer.classList.add("border", "border-3", "rounded")
|
||||
|
||||
for (let j = 0; j < 2; j++) {
|
||||
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 ingredName = ingreds[i];
|
||||
let ingred_text = document.createElement("p");
|
||||
ingred_text.classList.add("mb-2", "ps-2");
|
||||
ingred_text.textContent = ingredName;
|
||||
ingredTextContainer.appendChild(ingred_text);
|
||||
|
||||
let temp_row = document.createElement("div");
|
||||
temp_row.classList.add("row");
|
||||
col.appendChild(temp_row);
|
||||
|
||||
let ingred_div = document.createElement("div");
|
||||
ingred_div.classList.add("col");
|
||||
ingred_div.textContent = ingredName;
|
||||
temp_row.appendChild(ingred_div);
|
||||
|
||||
let eff_div = document.createElement("div");
|
||||
eff_div.classList.add("col-auto");
|
||||
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);
|
||||
let eff_div = document.createElement("p");
|
||||
eff_div.classList.add("mb-2", "ps-2");
|
||||
let e = effectiveness[i];
|
||||
if (e > 0) {
|
||||
eff_div.classList.add("positive");
|
||||
} else if (e < 0) {
|
||||
eff_div.classList.add("negative");
|
||||
}
|
||||
ingredTable.appendChild(row);
|
||||
eff_div.textContent = "[" + e + "%]";
|
||||
ingredTextContainer.appendChild(eff_div);
|
||||
|
||||
ingredCell.appendChild(ingredTextContainer);
|
||||
|
||||
ingredContainer.appendChild(ingredCell);
|
||||
}
|
||||
ingredTable.appendChild(ingredContainer);
|
||||
elem.appendChild(ingredTable);
|
||||
}
|
||||
|
||||
|
@ -877,7 +827,7 @@ function displayExpandedIngredient(ingred, parent_id) {
|
|||
row.appendChild(title);
|
||||
for(const skill of ingred.get("skills")) {
|
||||
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();
|
||||
row.appendChild(skill_div);
|
||||
}
|
||||
|
@ -1039,23 +989,30 @@ function displayFixedID(active, id, value, elemental_format, style) {
|
|||
|
||||
function displayPoisonDamage(overallparent_elem, build) {
|
||||
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
|
||||
let title_elemavg = document.createElement("b");
|
||||
title_elemavg.textContent = "Poison Stats";
|
||||
overallparent_elem.append(title_elemavg);
|
||||
let title_elemavg = make_elem("b");
|
||||
title_elemavg.append(make_elem('span', [], { textContent: "Poison Stats" }));
|
||||
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);
|
||||
overallpoisonDamageFirst.textContent = "Poison Tick: ";
|
||||
overallpoisonDamageSecond.textContent = Math.max(poison_tick,0);
|
||||
overallpoisonDamageSecond.classList.add("Damage");
|
||||
|
||||
overallpoisonDamage.appendChild(overallpoisonDamageFirst);
|
||||
overallpoisonDamage.appendChild(overallpoisonDamageSecond);
|
||||
overallparent_elem.append(overallpoisonDamage);
|
||||
let overallpoisonDamage = make_elem("p");
|
||||
overallpoisonDamage.append(
|
||||
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){
|
||||
|
@ -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){
|
||||
let defenseStats = getDefenseStats(statMap);
|
||||
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) {
|
||||
parent_elem.textContent = "";
|
||||
if (powderSpecials.length === 0) {
|
||||
parent_elem.style = "display: none";
|
||||
return;
|
||||
}
|
||||
parent_elem.style = "";
|
||||
|
||||
const skillpoints = [
|
||||
stats.get('str'),
|
||||
stats.get('dex'),
|
||||
|
@ -1431,16 +1249,13 @@ function displayPowderSpecials(parent_elem, powderSpecials, stats, weapon, overa
|
|||
stats.get('def'),
|
||||
stats.get('agi')
|
||||
];
|
||||
parent_elem.textContent = ""
|
||||
let title = document.createElement("b");
|
||||
title.textContent = "Powder Specials";
|
||||
parent_elem.appendChild(title);
|
||||
parent_elem.append(make_elem("b", [], { textContent: "Powder Specials" }));
|
||||
let specials = powderSpecials.slice();
|
||||
let expandedStats = new Map();
|
||||
//each entry of powderSpecials is [ps, power]
|
||||
for (special of specials) {
|
||||
//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 specialTitle = document.createElement("p");
|
||||
let specialEffects = document.createElement("p");
|
||||
|
@ -1572,7 +1387,7 @@ function getSpellCost(stats, spell) {
|
|||
|
||||
function getBaseSpellCost(stats, spell) {
|
||||
// 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);
|
||||
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
|
||||
parent_elem.textContent = "";
|
||||
|
||||
let title_elem = document.createElement("p");
|
||||
let title_elem = make_elem("p");
|
||||
|
||||
overallparent_elem.textContent = "";
|
||||
let title_elemavg = document.createElement("b");
|
||||
|
||||
if ('cost' in spell) {
|
||||
let first = document.createElement("span");
|
||||
first.textContent = spell.name + " (";
|
||||
let first = make_elem("span", [], { textContent: spell.name + " (" });
|
||||
title_elem.appendChild(first.cloneNode(true)); //cloneNode is needed here.
|
||||
title_elemavg.appendChild(first);
|
||||
|
||||
let second = document.createElement("span");
|
||||
second.textContent = getSpellCost(stats, spell);
|
||||
second.classList.add("Mana");
|
||||
|
||||
let second = make_elem("span", ["Mana"], { textContent: getSpellCost(stats, spell) });
|
||||
title_elem.appendChild(second.cloneNode(true));
|
||||
title_elemavg.appendChild(second);
|
||||
|
||||
|
||||
let third = document.createElement("span");
|
||||
third.textContent = ")";// [Base: " + getBaseSpellCost(stats, spellIdx, spell.cost) + " ]";
|
||||
title_elem.appendChild(third);
|
||||
let third_summary = document.createElement("span");
|
||||
third_summary.textContent = ")";
|
||||
title_elemavg.appendChild(third_summary);
|
||||
let third = make_elem("span", [], { textContent: ")" });// " + getBaseSpellCost(stats, spellIdx, spell.cost) + " ]";
|
||||
title_elem.appendChild(third.cloneNode(true));
|
||||
title_elemavg.appendChild(third);
|
||||
}
|
||||
else {
|
||||
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 part_divavg = document.createElement("p");
|
||||
let part_divavg = make_elem("p");
|
||||
overallparent_elem.append(part_divavg);
|
||||
|
||||
function _summary(text, val, fmt) {
|
||||
let overallaverageLabel = document.createElement("p");
|
||||
let first = document.createElement("span");
|
||||
let second = document.createElement("span");
|
||||
first.textContent = text;
|
||||
second.textContent = val.toFixed(2);
|
||||
overallaverageLabel.appendChild(first);
|
||||
overallaverageLabel.appendChild(second);
|
||||
second.classList.add(fmt);
|
||||
part_divavg.append(overallaverageLabel);
|
||||
function add_summary(text, val, fmt) {
|
||||
if (typeof(val) === 'number') { val = val.toFixed(2); }
|
||||
let summary_elem = make_elem("p");
|
||||
summary_elem.append(
|
||||
make_elem("span", [], { textContent: text }),
|
||||
make_elem("span", [fmt], { textContent: val })
|
||||
);
|
||||
part_divavg.append(summary_elem);
|
||||
}
|
||||
|
||||
for (let i = 0; i < spell_results.length; ++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);
|
||||
|
||||
let subtitle_elem = document.createElement("p");
|
||||
subtitle_elem.textContent = spell_info.name
|
||||
part_div.append(subtitle_elem);
|
||||
part_div.append(make_elem("p", [], { textContent: spell_info.name }));
|
||||
|
||||
if (spell_info.type === "damage") {
|
||||
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 averageDamage = (1-critChance)*nonCritAverage+critChance*critAverage || 0;
|
||||
|
||||
let averageLabel = document.createElement("p");
|
||||
averageLabel.textContent = "Average: "+averageDamage.toFixed(2);
|
||||
let averageLabel = make_elem("p", [], { textContent: "Average: "+averageDamage.toFixed(2) });
|
||||
// averageLabel.classList.add("damageSubtitle");
|
||||
part_div.append(averageLabel);
|
||||
|
||||
|
||||
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) {
|
||||
|
@ -1690,7 +1506,7 @@ function displaySpellDamage(parent_elem, overallparent_elem, stats, spell, spell
|
|||
// healLabel.classList.add("damagep");
|
||||
part_div.append(healLabel);
|
||||
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);
|
||||
for (const [id,val] of Object.entries(itemMap.get(item_name))) {
|
||||
if (rolledIDs.includes(id)) {
|
||||
if (!item.get("maxRolls").get(id)) { continue; }
|
||||
let min = item.get("minRolls").get(id);
|
||||
let max = item.get("maxRolls").get(id);
|
||||
//Apply corkian amps
|
||||
|
@ -2110,12 +1927,10 @@ function stringCDF(id,val,base,amp) {
|
|||
|
||||
function addClickableArrow(elem, target) {
|
||||
//up and down arrow - done ugly
|
||||
let arrow = document.createElement("img");
|
||||
arrow.id = "arrow_" + elem.id;
|
||||
let arrow = make_elem("img", [], { id: "arrow_" + elem.id, src: "../media/icons/" + (newIcons ? "new" : "old") + "/toggle_down.png" });
|
||||
arrow.style.maxWidth = document.body.clientWidth > 900 ? "3rem" : "10rem";
|
||||
arrow.src = "../media/icons/" + (newIcons ? "new" : "old") + "/toggle_down.png";
|
||||
elem.appendChild(arrow);
|
||||
arrow.addEventListener("click", () => toggle_spell_tab(arrow, target));
|
||||
elem.addEventListener("click", () => toggle_spell_tab(arrow, target));
|
||||
}
|
||||
|
||||
// toggle arrow thinger
|
||||
|
|
25
js/item.js
|
@ -20,14 +20,17 @@ function init_itempage() {
|
|||
//displayExpandedItem(expandItem(itemMap.get(item_url_tag).statMap, []), "item-view");
|
||||
try{
|
||||
item = expandItem(itemMap.get(item_url_tag.replaceAll("%20"," ")), []);
|
||||
displaysq2ExpandedItem(item, "item-view");
|
||||
displaysq2AdditionalInfo("additional-info", item);
|
||||
displaysq2IDCosts("identification-costs", item);
|
||||
if (item.get("set") && sets[item.get("set")]) {
|
||||
displaysq2AllSetBonuses("set-bonus-info",item.get("set"));
|
||||
if (item.get('category') === 'weapon') {
|
||||
item.set('powders', []);
|
||||
apply_weapon_powders(item);
|
||||
}
|
||||
console.log(item);
|
||||
displaysq2IDProbabilities("identification-probabilities", item, amp_state);
|
||||
displayExpandedItem(item, "item-view");
|
||||
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) {
|
||||
console.log(error);
|
||||
console.log(error.stack);
|
||||
|
@ -56,6 +59,8 @@ function toggleAmps(button_id) {
|
|||
}
|
||||
|
||||
|
||||
|
||||
load_init(init_itempage);
|
||||
//load_ing_init(init);
|
||||
(async function() {
|
||||
let load_promises = [ load_init() ];
|
||||
await Promise.all(load_promises);
|
||||
init_itempage();
|
||||
})();
|
||||
|
|
|
@ -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
|
||||
|
||||
let db;
|
||||
|
|
|
@ -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
|
||||
|
||||
|
@ -9,13 +9,13 @@ let iload_complete = false;
|
|||
let ings;
|
||||
let recipes;
|
||||
|
||||
let ingMap;
|
||||
let ingMap = new Map();
|
||||
let ingList = [];
|
||||
|
||||
let recipeMap;
|
||||
let recipeList = [];
|
||||
|
||||
let ingIDMap;
|
||||
let ingIDMap = new Map();
|
||||
let recipeIDMap;
|
||||
|
||||
/*
|
||||
|
@ -163,39 +163,41 @@ async function load_ing_init() {
|
|||
}
|
||||
|
||||
function init_ing_maps() {
|
||||
ingMap = new Map();
|
||||
recipeMap = new Map();
|
||||
ingIDMap = new Map();
|
||||
recipeIDMap = new Map();
|
||||
|
||||
let ing = Object();
|
||||
ing.name = "No Ingredient";
|
||||
ing.displayName = "No Ingredient";
|
||||
ing.tier = 0;
|
||||
ing.lvl = 0;
|
||||
ing.skills = ["ARMOURING", "TAILORING", "WEAPONSMITHING", "WOODWORKING", "JEWELING", "COOKING", "ALCHEMISM", "SCRIBING"];
|
||||
ing.ids= {};
|
||||
ing.itemIDs = {"dura": 0, "strReq": 0, "dexReq": 0,"intReq": 0,"defReq": 0,"agiReq": 0,};
|
||||
ing.consumableIDs = {"dura": 0, "charges": 0};
|
||||
ing.posMods = {"left": 0, "right": 0, "above": 0, "under": 0, "touching": 0, "notTouching": 0};
|
||||
ing.id = 4000;
|
||||
ingMap.set(ing["displayName"], ing);
|
||||
ingList.push(ing["displayName"]);
|
||||
ingIDMap.set(ing["id"], ing["displayName"]);
|
||||
let ing = {
|
||||
name: "No Ingredient",
|
||||
displayName: "No Ingredient",
|
||||
tier: 0,
|
||||
lvl: 0,
|
||||
skills: ["ARMOURING", "TAILORING", "WEAPONSMITHING", "WOODWORKING", "JEWELING", "COOKING", "ALCHEMISM", "SCRIBING"],
|
||||
ids: {},
|
||||
itemIDs: {"dura": 0, "strReq": 0, "dexReq": 0,"intReq": 0,"defReq": 0,"agiReq": 0,},
|
||||
consumableIDs: {"dura": 0, "charges": 0},
|
||||
posMods: {"left": 0, "right": 0, "above": 0, "under": 0, "touching": 0, "notTouching": 0},
|
||||
id: 4000
|
||||
};
|
||||
ingMap.set(ing.displayName, ing);
|
||||
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"]]);
|
||||
for (let i = 0; i < 5; i ++) {
|
||||
for (const powderIng of powderIngreds) {
|
||||
let ing = Object();
|
||||
ing.name = "" + damageClasses[i+1] + " Powder " + numerals.get(powderIngreds.indexOf(powderIng) + 1);
|
||||
ing.displayName = ing.name
|
||||
ing.tier = 0;
|
||||
ing.lvl = 0;
|
||||
ing.skills = ["ARMOURING", "TAILORING", "WEAPONSMITHING", "WOODWORKING", "JEWELING"];
|
||||
ing.ids = {};
|
||||
ing.isPowder = true;
|
||||
ing.pid = 6*i + powderIngreds.indexOf(powderIng);
|
||||
let ing = {
|
||||
name: "" + damageClasses[i+1] + " Powder " + numerals.get(powderIngreds.indexOf(powderIng) + 1),
|
||||
tier: 0,
|
||||
lvl: 0,
|
||||
skills: ["ARMOURING", "TAILORING", "WEAPONSMITHING", "WOODWORKING", "JEWELING"],
|
||||
ids: {},
|
||||
isPowder: true,
|
||||
pid: 6*i + powderIngreds.indexOf(powderIng),
|
||||
itemIDs: {"dura": powderIng["durability"], "strReq": 0, "dexReq": 0,"intReq": 0,"defReq": 0,"agiReq": 0},
|
||||
consumableIDs: {"dura": 0, "charges": 0},
|
||||
posMods: {"left": 0, "right": 0, "above": 0, "under": 0, "touching": 0, "notTouching": 0}
|
||||
};
|
||||
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) {
|
||||
case 0:
|
||||
ing.itemIDs["strReq"] = powderIng["skpReq"];
|
||||
|
@ -213,24 +215,21 @@ function init_ing_maps() {
|
|||
ing.itemIDs["agiReq"] = powderIng["skpReq"];
|
||||
break;
|
||||
}
|
||||
ing.consumableIDs = {"dura": 0, "charges": 0};
|
||||
ing.posMods = {"left": 0, "right": 0, "above": 0, "under": 0, "touching": 0, "notTouching": 0};
|
||||
ingMap.set(ing["displayName"],ing);
|
||||
ingList.push(ing["displayName"]);
|
||||
ingIDMap.set(ing["id"], ing["displayName"]);
|
||||
ingMap.set(ing.displayName, ing);
|
||||
ingList.push(ing.displayName);
|
||||
ingIDMap.set(ing.id, ing.displayName);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
for (const ing of ings) {
|
||||
ingMap.set(ing["displayName"], ing);
|
||||
ingList.push(ing["displayName"]);
|
||||
ingIDMap.set(ing["id"], ing["displayName"]);
|
||||
ingMap.set(ing.displayName, ing);
|
||||
ingList.push(ing.displayName);
|
||||
ingIDMap.set(ing.id, ing.displayName);
|
||||
}
|
||||
for (const recipe of recipes) {
|
||||
recipeMap.set(recipe["name"], recipe);
|
||||
recipeList.push(recipe["name"]);
|
||||
recipeIDMap.set(recipe["id"],recipe["name"]);
|
||||
recipeMap.set(recipe.name, recipe);
|
||||
recipeList.push(recipe.name);
|
||||
recipeIDMap.set(recipe.id, recipe.name);
|
||||
}
|
||||
console.log(ingMap);
|
||||
}
|
||||
|
|
|
@ -169,14 +169,14 @@ function calc_weapon_powder(weapon, damageBases) {
|
|||
let min_diff = Math.min(neutralRemainingRaw[0], conversionRatio * neutralBase[0]);
|
||||
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][1] = Math.floor(round_near(damages[element+1][1] + max_diff));
|
||||
//neutralRemainingRaw[0] = Math.floor(round_near(neutralRemainingRaw[0] - min_diff));
|
||||
//neutralRemainingRaw[1] = Math.floor(round_near(neutralRemainingRaw[1] - max_diff));
|
||||
damages[element+1][0] += min_diff;
|
||||
damages[element+1][1] += max_diff;
|
||||
neutralRemainingRaw[0] -= min_diff;
|
||||
neutralRemainingRaw[1] -= max_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));
|
||||
neutralRemainingRaw[0] = Math.floor(round_near(neutralRemainingRaw[0] - min_diff));
|
||||
neutralRemainingRaw[1] = Math.floor(round_near(neutralRemainingRaw[1] - max_diff));
|
||||
//damages[element+1][0] += min_diff;
|
||||
//damages[element+1][1] += max_diff;
|
||||
//neutralRemainingRaw[0] -= min_diff;
|
||||
//neutralRemainingRaw[1] -= max_diff;
|
||||
}
|
||||
damages[element+1][0] += powder.min;
|
||||
damages[element+1][1] += powder.max;
|
||||
|
|
|
@ -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) {
|
||||
// const start = performance.now();
|
||||
// Calculate equipment equipping order and required skillpoints.
|
||||
// Return value: [equip_order, best_skillpoints, final_skillpoints, best_total];
|
||||
let fixed = [];
|
||||
let consider = [];
|
||||
let noboost = [];
|
||||
let crafted = [];
|
||||
weapon.skillpoints = weapon.get('skillpoints');
|
||||
weapon.reqs = weapon.get('reqs');
|
||||
weapon.set = weapon.get('set');
|
||||
for (const item of equipment) {
|
||||
item.skillpoints = item.get('skillpoints');
|
||||
item.reqs = item.get('reqs');
|
||||
item.set = item.get('set');
|
||||
if (item.get("crafted")) {
|
||||
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.
|
||||
fixed.push(item);
|
||||
}
|
||||
// TODO hack: We will treat ALL set items as unsafe :(
|
||||
else if (item.get("skillpoints").every(x => x === 0) && item.get("set") === null) {
|
||||
else if (item.skillpoints.every(x => x <= 0)) {
|
||||
noboost.push(item);
|
||||
}
|
||||
else {
|
||||
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.
|
||||
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);
|
||||
}
|
||||
|
||||
let best = consider.concat(noboost);
|
||||
let best = consider;
|
||||
let final_skillpoints = static_skillpoints_base.slice();
|
||||
let best_skillpoints = [0, 0, 0, 0, 0];
|
||||
let best_total = Infinity;
|
||||
|
@ -110,100 +128,125 @@ function calculate_skillpoints(equipment, weapon) {
|
|||
let allFalse = [0, 0, 0, 0, 0];
|
||||
if (consider.length > 0 || noboost.length > 0 || crafted.length > 0) {
|
||||
// Try every combination and pick the best one.
|
||||
for (let permutation of perm(consider)) {
|
||||
let activeSetCounts = new Map(static_activeSetCounts);
|
||||
|
||||
let has_skillpoint = allFalse.slice();
|
||||
|
||||
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;
|
||||
}
|
||||
}
|
||||
const [root, terminal, sccs] = construct_scc_graph(consider);
|
||||
const end_checks = crafted.concat(noboost);
|
||||
end_checks.push(weapon);
|
||||
|
||||
function check_end(skillpoints_applied, skillpoints, activeSetCounts, total_applied) {
|
||||
// Crafted skillpoint does not count initially.
|
||||
for (const item of crafted) {
|
||||
//console.log(item)
|
||||
result = apply_to_fit(skillpoints, item, allFalse.slice(), activeSetCounts);
|
||||
//console.log(result)
|
||||
needed_skillpoints = result[0];
|
||||
total_diff = result[1];
|
||||
for (const item of end_checks) {
|
||||
const needed_skillpoints = apply_to_fit(skillpoints, item,
|
||||
[false, false, false, false, false], activeSetCounts);
|
||||
|
||||
for (let i = 0; i < 5; ++i) {
|
||||
skillpoints_applied[i] += needed_skillpoints[i];
|
||||
skillpoints[i] += needed_skillpoints[i];
|
||||
const skp = needed_skillpoints[i]
|
||||
skillpoints_applied[i] += skp;
|
||||
skillpoints[i] += skp;
|
||||
total_applied += skp;
|
||||
}
|
||||
total_applied += total_diff;
|
||||
}
|
||||
|
||||
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;
|
||||
if (best_total < total_applied) { return -1; }
|
||||
}
|
||||
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 {
|
||||
best_total = 0;
|
||||
result = apply_to_fit(final_skillpoints, weapon, allFalse.slice(), best_activeSetCounts);
|
||||
needed_skillpoints = result[0];
|
||||
total_diff = result[1];
|
||||
needed_skillpoints = apply_to_fit(final_skillpoints, weapon, allFalse.slice(), best_activeSetCounts);
|
||||
for (let i = 0; i < 5; ++i) {
|
||||
best_skillpoints[i] += needed_skillpoints[i];
|
||||
final_skillpoints[i] += needed_skillpoints[i];
|
||||
const skp = needed_skillpoints[i];
|
||||
best_skillpoints[i] += skp;
|
||||
final_skillpoints[i] += skp;
|
||||
best_total += skp;
|
||||
}
|
||||
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)
|
||||
// final_skillpoints: final totals (5 individ)
|
||||
// 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];
|
||||
}
|
||||
|
||||
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];
|
||||
}
|
||||
|
|
124
js/sq2items.js
|
@ -1,57 +1,4 @@
|
|||
document.addEventListener("DOMContentLoaded", function() {
|
||||
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;
|
||||
};
|
||||
},
|
||||
},
|
||||
}
|
||||
}));
|
||||
};
|
||||
});
|
||||
let itemCategories = [ "armor", "accessory", "weapon" ];
|
||||
|
||||
const sq2_translate_mappings = {
|
||||
//"Name": "name",
|
||||
|
@ -184,7 +131,11 @@ function displayItems(items_copy) {
|
|||
box.appendChild(bckgrdbox);
|
||||
bckgrdbox.id = "item"+i+"b";
|
||||
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) {
|
||||
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) {
|
||||
queries.push(new IdQuery(filter_dat));
|
||||
continue;
|
||||
}
|
||||
filter_dat = special_mappings[raw_dat];
|
||||
filter_dat = sq2_special_mappings[raw_dat];
|
||||
if (filter_dat !== undefined) {
|
||||
queries.push(filter_dat);
|
||||
continue;
|
||||
|
@ -251,6 +202,63 @@ function resetItemSearch() {
|
|||
|
||||
function init_items() {
|
||||
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();
|
||||
})();
|
||||
|
|
289
js/utils.js
|
@ -630,8 +630,15 @@ function addClasses(elem, classes) {
|
|||
*/
|
||||
async function hardReload() {
|
||||
//https://gist.github.com/rmehner/b9a41d9f659c9b1c3340
|
||||
const dbs = await window.indexedDB.databases();
|
||||
await dbs.forEach(db => { window.indexedDB.deleteDatabase(db.name) });
|
||||
try {
|
||||
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);
|
||||
}
|
||||
|
@ -770,112 +777,204 @@ function assert_error(func_binding, msg) {
|
|||
/**
|
||||
* 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
|
||||
return obj;
|
||||
}
|
||||
let ret = Array.isArray(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;
|
||||
}
|
||||
/**
|
||||
*
|
||||
*/
|
||||
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() {
|
||||
console.log("=====STARTING BITVECTOR UNIT TESTS=====");
|
||||
let buf_col = document.createElement("div");
|
||||
buf_col.classList.add("col");
|
||||
|
||||
// Empty Constructor + append str
|
||||
let bv = new BitVector("");
|
||||
bv.append("Bc8");
|
||||
assert_equals(bv.bits.length, 1);
|
||||
assert_equals(bv.length, 18);
|
||||
assert_equals(bv.toB64(), "Bc8");
|
||||
let label = document.createElement("div");
|
||||
label.classList.add("col");
|
||||
label.classList.add(...label_classlist);
|
||||
label.textContent = label_name + ": " + default_val;
|
||||
|
||||
// Empty Constructor + append num 1
|
||||
bv = new BitVector("");
|
||||
bv.append(10000, 18);
|
||||
assert_equals(bv.bits.length, 1);
|
||||
assert_equals(bv.length, 18);
|
||||
assert_equals(bv.toB64(), "GS2"); //have to read backwards
|
||||
let slider = gen_slider(min, max, step, default_val, id, color, classlist, label);
|
||||
|
||||
// Empty Constructor + append num 1
|
||||
bv = new BitVector("");
|
||||
bv.append(10000, 14);
|
||||
assert_equals(bv.bits.length, 1);
|
||||
assert_equals(bv.length, 14);
|
||||
assert_equals(bv.toB64(), "GS2"); //have to read backwards
|
||||
//we set IDs here because the slider's id is potentially only meaningful after gen_slider() is called
|
||||
label.id = slider.id + "_label";
|
||||
slider_container.id = slider.id + "-container";
|
||||
|
||||
// 1-int constructor (num)
|
||||
bv = new BitVector(10000, 14);
|
||||
assert_equals(bv.bits.length, 1);
|
||||
assert_equals(bv.length, 14);
|
||||
assert_equals(bv.toB64(), "GS2");
|
||||
buf_col.append(slider, label);
|
||||
slider_container.appendChild(buf_col);
|
||||
|
||||
// 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=====");
|
||||
return slider_container;
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
|
BIN
media/atree/connect_0011.png
Normal file
After Width: | Height: | Size: 182 B |
BIN
media/atree/connect_0011_1.png
Normal file
After Width: | Height: | Size: 1.5 KiB |
BIN
media/atree/connect_0101.png
Normal file
After Width: | Height: | Size: 183 B |
BIN
media/atree/connect_0101_1.png
Normal file
After Width: | Height: | Size: 1.5 KiB |
BIN
media/atree/connect_0110.png
Normal file
After Width: | Height: | Size: 178 B |
BIN
media/atree/connect_0110_1.png
Normal file
After Width: | Height: | Size: 1.5 KiB |
BIN
media/atree/connect_0111.png
Normal file
After Width: | Height: | Size: 202 B |
BIN
media/atree/connect_0111_0011.png
Normal file
After Width: | Height: | Size: 1.6 KiB |
BIN
media/atree/connect_0111_0101.png
Normal file
After Width: | Height: | Size: 1.6 KiB |
BIN
media/atree/connect_0111_0110.png
Normal file
After Width: | Height: | Size: 1.6 KiB |
BIN
media/atree/connect_0111_0111.png
Normal file
After Width: | Height: | Size: 1.6 KiB |
BIN
media/atree/connect_1001.png
Normal file
After Width: | Height: | Size: 184 B |
BIN
media/atree/connect_1001_1.png
Normal file
After Width: | Height: | Size: 1.5 KiB |
BIN
media/atree/connect_1010.png
Normal file
After Width: | Height: | Size: 177 B |
BIN
media/atree/connect_1010_1.png
Normal file
After Width: | Height: | Size: 1.5 KiB |
BIN
media/atree/connect_1011.png
Normal file
After Width: | Height: | Size: 202 B |
BIN
media/atree/connect_1011_0011.png
Normal file
After Width: | Height: | Size: 1.6 KiB |
BIN
media/atree/connect_1011_1001.png
Normal file
After Width: | Height: | Size: 1.6 KiB |
BIN
media/atree/connect_1011_1010.png
Normal file
After Width: | Height: | Size: 1.6 KiB |
BIN
media/atree/connect_1011_1011.png
Normal file
After Width: | Height: | Size: 1.6 KiB |
BIN
media/atree/connect_1100.png
Normal file
After Width: | Height: | Size: 184 B |
BIN
media/atree/connect_1100_1.png
Normal file
After Width: | Height: | Size: 1.6 KiB |
BIN
media/atree/connect_1101.png
Normal file
After Width: | Height: | Size: 205 B |
BIN
media/atree/connect_1101_0101.png
Normal file
After Width: | Height: | Size: 1.6 KiB |
BIN
media/atree/connect_1101_1001.png
Normal file
After Width: | Height: | Size: 1.6 KiB |
BIN
media/atree/connect_1101_1100.png
Normal file
After Width: | Height: | Size: 1.6 KiB |
BIN
media/atree/connect_1101_1101.png
Normal file
After Width: | Height: | Size: 1.6 KiB |
BIN
media/atree/connect_1110.png
Normal file
After Width: | Height: | Size: 203 B |
BIN
media/atree/connect_1110_0110.png
Normal file
After Width: | Height: | Size: 1.6 KiB |
BIN
media/atree/connect_1110_1010.png
Normal file
After Width: | Height: | Size: 1.6 KiB |
BIN
media/atree/connect_1110_1100.png
Normal file
After Width: | Height: | Size: 1.6 KiB |
BIN
media/atree/connect_1110_1110.png
Normal file
After Width: | Height: | Size: 1.6 KiB |
BIN
media/atree/connect_1111.png
Normal file
After Width: | Height: | Size: 221 B |
BIN
media/atree/connect_1111_0011.png
Normal file
After Width: | Height: | Size: 1.6 KiB |
BIN
media/atree/connect_1111_0101.png
Normal file
After Width: | Height: | Size: 1.6 KiB |
BIN
media/atree/connect_1111_0110.png
Normal file
After Width: | Height: | Size: 1.6 KiB |
BIN
media/atree/connect_1111_0111.png
Normal file
After Width: | Height: | Size: 1.6 KiB |
BIN
media/atree/connect_1111_1001.png
Normal file
After Width: | Height: | Size: 1.6 KiB |
BIN
media/atree/connect_1111_1010.png
Normal file
After Width: | Height: | Size: 1.6 KiB |
BIN
media/atree/connect_1111_1011.png
Normal file
After Width: | Height: | Size: 1.6 KiB |
BIN
media/atree/connect_1111_1100.png
Normal file
After Width: | Height: | Size: 1.6 KiB |
BIN
media/atree/connect_1111_1101.png
Normal file
After Width: | Height: | Size: 1.6 KiB |
BIN
media/atree/connect_1111_1110.png
Normal file
After Width: | Height: | Size: 1.6 KiB |
BIN
media/atree/connect_1111_1111.png
Normal file
After Width: | Height: | Size: 1.6 KiB |
Before Width: | Height: | Size: 1.1 KiB |
Before Width: | Height: | Size: 1.3 KiB |
Before Width: | Height: | Size: 1.2 KiB |
Before Width: | Height: | Size: 962 B |
Before Width: | Height: | Size: 1 KiB |
Before Width: | Height: | Size: 1 KiB |
Before Width: | Height: | Size: 1.1 KiB |
Before Width: | Height: | Size: 1.1 KiB |
Before Width: | Height: | Size: 1.1 KiB |
Before Width: | Height: | Size: 974 B |
Before Width: | Height: | Size: 708 B |
Before Width: | Height: | Size: 666 B |
Before Width: | Height: | Size: 654 B |
Before Width: | Height: | Size: 2.4 KiB After Width: | Height: | Size: 1.1 KiB |
Before Width: | Height: | Size: 2.4 KiB After Width: | Height: | Size: 1.1 KiB |