Merge remote-tracking branch 'origin/master' into atlas-revamp

This commit is contained in:
fin444 2022-08-18 17:15:47 -07:00
commit 787dea106c
33 changed files with 2995 additions and 2221 deletions

View file

@ -36,20 +36,71 @@
<hr/> <hr/>
<a href = "https://discord.gg/CGavnAnerv" target = "_blank"><img src = "../media/icons/discord.png" alt = "WB Discord" title = "WB Discord"><b>WB Discord</b></a> <a href = "https://discord.gg/CGavnAnerv" target = "_blank"><img src = "../media/icons/discord.png" alt = "WB Discord" title = "WB Discord"><b>WB Discord</b></a>
</div> </div>
<div class="container-fluid me-4" style="max-width: 95%; display: none"> <div id="mobile-navbar" class="navbar dark-5 dark-shadow fixed-top d-lg-none pb-0" style="display: none">
<div class="container-fluid scaled-font justify-content-center" style="height: 5vh;">
<div class="navbar-brand mx-auto scaled-font" style="height: 100%;">
<img src="../media/icons/new/builder.png" alt="" style="height: 100%;">
<span>WynnBuilder</span>
</div>
<button class="btn dropdown-toggle dark-2 px-4 text-white scaled-font border-dark border-3" onclick="toggle_tab('mobile-navbar-dropdown');"></button>
</div>
<div class="container-fluid scaled-font dark-3 px-3 py-3" id="mobile-navbar-dropdown" style="display: none;">
<a href="../builder/" class="w-100 mb-3 text-white" style="height: 5vh; text-decoration: none;">
<img src="../media/icons/new/builder.png" alt="" style="height: 100%;">
<span>WynnBuilder</span>
</a>
<a href="../crafter/" class="w-100 mb-3 text-white" style="height: 5vh; text-decoration: none;">
<img src="../media/icons/new/crafter.png" alt="" style="height: 100%;">
<span>WynnCrafter</span>
</a>
<a href="../items/" class="w-100 mb-3 text-white" style="height: 5vh; text-decoration: none;">
<img src="../media/icons/new/searcher.png" alt="" style="height: 100%;">
<span>WynnAtlas</span>
</a>
<a href="../custom/" class="w-100 mb-3 text-white" style="height: 5vh; text-decoration: none;">
<img src="../media/icons/new/custom.png" alt="" style="height: 100%;">
<span>WynnCustom</span>
</a>
<a href="../map/" class="w-100 mb-3 text-white" style="height: 5vh; text-decoration: none;">
<img src="../media/icons/new/compass.png" alt="" style="height: 100%;">
<span>WynnGPS</span>
</a>
<a href="../wynnfo/" class="w-100 mb-3 text-white" style="height: 5vh; text-decoration: none;">
<img src="../media/icons/new/book.png" alt="" style="height: 100%;">
<span>WynnFo</span>
</a>
<a onclick = "toggleIcons()" class="w-100 mb-3 text-white" style="height: 5vh; text-decoration: none;">
<img src="../media/icons/new/reload.png" alt="" style="height: 100%;">
<span>Swap Icon Style</span>
</a>
<a href="https://discord.gg/CGavnAnerv" class="w-100 mb-3 text-white" style="height: 5vh; text-decoration: none;">
<img src="../media/icons/discord.png" alt="" style="height: 100%;">
<span>Discord</span>
</a>
</div>
</div>
<div class="container-fluid overall-box mt-lg-2" style="margin-top: 6vh; display: none">
<!-- REMOVE THIS DIV AT SOME POINT. --> <!-- REMOVE THIS DIV AT SOME POINT. -->
<div class = "row scaled-font mx-auto" id = "discord-banner-dev"> <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 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>
<div class="row h-100 gx-lg-5 gy-3 mx-2 mx-lg-3 py-3"> <div class="row h-100 gx-lg-5 gy-3 mx-2 mx-lg-3 py-3 gx-0">
<div class="col-xl-6"> <div class="col-xl-6">
<div class="row row-cols-1 mb-3 gy-4"> <div class="row my-2 dark-6 rounded text-center g-0 px-3 d-flex d-lg-none">
<div class="col"> <div class="col">
<div class="row row-cols-1 row-cols-xl-2 rounded gy-4 gx-5 justify-content-center"> <p class="fake-button scaled-font mb-0 selected-btn" id="equipment-inputs-btn" onclick="show_tab('equipment-inputs', ['equipment-inputs', 'adjust-id'])">Equipments</p>
<div class="col-auto rounded order-xl-0 order-0"> </div>
<div class="row h-100 dark-shadow dark-6 rounded" id="helmet-dropdown"> <div class="col">
<p class="fake-button scaled-font mb-0" id="adjust-id-btn" onclick="show_tab('adjust-id', ['equipment-inputs', 'adjust-id'])">Ability Tree</p>
</div>
</div>
<div class="row row-cols-1 mb-3 gy-4" id="equipment-inputs">
<div class="col">
<div class="row row-cols-1 row-cols-xl-2 dark-shadow dark-6 justify-content-center equipment-input rounded gy-3 gy-lg-0 mt-auto">
<div class="col-auto rounded order-xl-0 order-0 my-0">
<div class="row h-100 px-1" id="helmet-dropdown">
<div class="col-auto px-lg-1 g-0 dark-7 rounded-end my-auto text-center scaled-item-icon" id="helmet-img-loc"> <div class="col-auto px-lg-1 g-0 dark-7 rounded-end my-auto text-center scaled-item-icon" id="helmet-img-loc">
<img id="helmet-img" class="img-fluid rounded" src="../media/items/new/generic-helmet.png"> <div id="helmet-img" class="img-fluid rounded item-display-new-toggleable" style="background-image: url('../media/items/new.png'); background-position: 45.45454545454546% 0;"></div>
</div> </div>
<div class="col-3"> <div class="col-3">
<div class="row row-cols-1 h-100 align-items-center"> <div class="row row-cols-1 h-100 align-items-center">
@ -73,10 +124,10 @@
</div> </div>
</div> </div>
</div> </div>
<div class="col-auto order-xl-0 order-1"> <div class="col-auto order-xl-0 order-1 my-0">
<div class="row h-100 dark-shadow dark-6 rounded" id="ring1-dropdown"> <div class="row h-100 px-1" id="ring1-dropdown">
<div class="col-auto px-lg-1 g-0 dark-7 rounded-end my-auto text-center scaled-item-icon" id="ring1-img-loc"> <div class="col-auto px-lg-1 g-0 dark-7 rounded-end my-auto text-center scaled-item-icon" id="ring1-img-loc">
<img id="ring1-img" class="img-fluid rounded" src="../media/items/new/generic-ring.png"> <div id="ring1-img" class="img-fluid rounded item-display-new-toggleable" style="background-image: url('../media/items/new.png'); background-position: 81.81818181818181% 0;"></div>
</div> </div>
<div class="col-3"> <div class="col-3">
<div class="row row-cols-1 h-100 align-items-center"> <div class="row row-cols-1 h-100 align-items-center">
@ -94,16 +145,15 @@
<input class="equipment-input text-light form-control" id="ring1-choice" name="ring1-choice" placeholder="No ring" value="" tabindex="2"/> <input class="equipment-input text-light form-control" id="ring1-choice" name="ring1-choice" placeholder="No ring" value="" tabindex="2"/>
</div> </div>
<div class="col d-flex justify-content-end" style="height: 100%;"> <div class="col d-flex justify-content-end" style="height: 100%;">
<!-- <input class="equipment-input text-light form-control" type="text" id="ring1-powder" name="ring1-powder" placeholder="no powders" tabindex="2"/> -->
</div> </div>
</div> </div>
</div> </div>
</div> </div>
</div> </div>
<div class="col-auto order-xl-0 order-0"> <div class="col-auto order-xl-0 order-0">
<div class="row h-100 dark-shadow dark-6 rounded" id="chestplate-dropdown"> <div class="row h-100 px-1" id="chestplate-dropdown">
<div class="col-auto px-lg-1 g-0 dark-7 rounded-end my-auto text-center scaled-item-icon" id="chestplate-img-loc"> <div class="col-auto px-lg-1 g-0 dark-7 rounded-end my-auto text-center scaled-item-icon" id="chestplate-img-loc">
<img id="chestplate-img" class="img-fluid rounded" src="../media/items/new/generic-chestplate.png"> <div id="chestplate-img" class="img-fluid rounded item-display-new-toggleable" style="background-image: url('../media/items/new.png'); background-position: 54.54545454545454% 0;"></div>
</div> </div>
<div class="col-3"> <div class="col-3">
<div class="row row-cols-1 h-100 align-items-center"> <div class="row row-cols-1 h-100 align-items-center">
@ -128,9 +178,9 @@
</div> </div>
</div> </div>
<div class="col-auto order-xl-0 order-1"> <div class="col-auto order-xl-0 order-1">
<div class="row h-100 dark-shadow dark-6 rounded" id="ring2-dropdown"> <div class="row h-100 px-1" id="ring2-dropdown">
<div class="col-auto px-lg-1 g-0 dark-7 rounded-end my-auto text-center scaled-item-icon" id="ring2-img-loc"> <div class="col-auto px-lg-1 g-0 dark-7 rounded-end my-auto text-center scaled-item-icon" id="ring2-img-loc">
<img id="ring2-img" class="img-fluid rounded" src="../media/items/new/generic-ring.png"> <div id="ring2-img" class="img-fluid rounded item-display-new-toggleable" style="background-image: url('../media/items/new.png'); background-position: 81.81818181818181% 0;"></div>
</div> </div>
<div class="col-3"> <div class="col-3">
<div class="row row-cols-1 h-100 align-items-center"> <div class="row row-cols-1 h-100 align-items-center">
@ -154,9 +204,9 @@
</div> </div>
</div> </div>
<div class="col-auto order-xl-0 order-0"> <div class="col-auto order-xl-0 order-0">
<div class="row h-100 dark-shadow dark-6 rounded" id="leggings-dropdown"> <div class="row h-100 px-1" id="leggings-dropdown">
<div class="col-auto px-lg-1 g-0 dark-7 rounded-end my-auto text-center scaled-item-icon" id="leggings-img-loc"> <div class="col-auto px-lg-1 g-0 dark-7 rounded-end my-auto text-center scaled-item-icon" id="leggings-img-loc">
<img id="leggings-img" class="img-fluid rounded" src="../media/items/new/generic-leggings.png"> <div id="leggings-img" class="img-fluid rounded item-display-new-toggleable" style="background-image: url('../media/items/new.png'); background-position: 63.63636363636363% 0;"></div>
</div> </div>
<div class="col-3"> <div class="col-3">
<div class="row row-cols-1 h-100 align-items-center"> <div class="row row-cols-1 h-100 align-items-center">
@ -181,9 +231,9 @@
</div> </div>
</div> </div>
<div class="col-auto order-xl-0 order-1"> <div class="col-auto order-xl-0 order-1">
<div class="row h-100 dark-shadow dark-6 rounded" id="bracelet-dropdown"> <div class="row h-100 px-1" id="bracelet-dropdown">
<div class="col-auto px-lg-1 g-0 dark-7 rounded-end my-auto text-center scaled-item-icon" id="bracelet-img-loc"> <div class="col-auto px-lg-1 g-0 dark-7 rounded-end my-auto text-center scaled-item-icon" id="bracelet-img-loc">
<img id="bracelet-img" class="img-fluid rounded" src="../media/items/new/generic-bracelet.png"> <div id="bracelet-img" class="img-fluid rounded item-display-new-toggleable" style="background-image: url('../media/items/new.png'); background-position: 90.90909090909092% 0;"></div>
</div> </div>
<div class="col-3"> <div class="col-3">
<div class="row row-cols-1 h-100 align-items-center"> <div class="row row-cols-1 h-100 align-items-center">
@ -208,9 +258,9 @@
</div> </div>
</div> </div>
<div class="col-auto order-xl-0 order-0"> <div class="col-auto order-xl-0 order-0">
<div class="row h-100 dark-shadow dark-6 rounded" id="boots-dropdown"> <div class="row h-100 px-1" id="boots-dropdown">
<div class="col-auto px-lg-1 g-0 dark-7 rounded-end my-auto text-center scaled-item-icon" id="boots-img-loc"> <div class="col-auto px-lg-1 g-0 dark-7 rounded-end my-auto text-center scaled-item-icon" id="boots-img-loc">
<img id="boots-img" class="img-fluid rounded" src="../media/items/new/generic-boots.png"> <div id="boots-img" class="img-fluid rounded item-display-new-toggleable" style="background-image: url('../media/items/new.png'); background-position: 72.72727272727272% 0;"></div>
</div> </div>
<div class="col-3"> <div class="col-3">
<div class="row row-cols-1 h-100 align-items-center"> <div class="row row-cols-1 h-100 align-items-center">
@ -235,9 +285,9 @@
</div> </div>
</div> </div>
<div class="col-auto order-xl-0 order-1"> <div class="col-auto order-xl-0 order-1">
<div class="row h-100 dark-shadow dark-6 rounded" id="necklace-dropdown"> <div class="row h-100 px-1" id="necklace-dropdown">
<div class="col-auto px-lg-1 g-0 dark-7 rounded-end my-auto text-center scaled-item-icon" id="necklace-img-loc"> <div class="col-auto px-lg-1 g-0 dark-7 rounded-end my-auto text-center scaled-item-icon" id="necklace-img-loc">
<img id="necklace-img" class="img-fluid rounded" src="../media/items/new/generic-necklace.png"> <div id="necklace-img" class="img-fluid rounded item-display-new-toggleable" style="background-image: url('../media/items/new.png'); background-position: 100% 0;"></div>
</div> </div>
<div class="col-3"> <div class="col-3">
<div class="row row-cols-1 h-100 align-items-center"> <div class="row row-cols-1 h-100 align-items-center">
@ -261,9 +311,9 @@
</div> </div>
</div> </div>
<div class="col-auto order-xl-0 order-1"> <div class="col-auto order-xl-0 order-1">
<div class="row h-100 dark-shadow dark-6 rounded" id='weapon-dropdown'> <div class="row h-auto px-1" id='weapon-dropdown'>
<div class="col-auto px-lg-1 g-0 dark-7 rounded-end my-auto text-center scaled-item-icon" id="weapon-img-loc"> <div class="col-auto px-lg-1 g-0 dark-7 rounded-end my-auto text-center scaled-item-icon" id="weapon-img-loc">
<img id="weapon-img" class="img-fluid rounded" src="../media/items/new/generic-dagger.png"> <div id="weapon-img" class="img-fluid rounded item-display-new-toggleable" style = "background-image: url('../media/items/new.png');"></div>
</div> </div>
<div class="col-3"> <div class="col-3">
<div class="row row-cols-1 h-100 align-items-center"> <div class="row row-cols-1 h-100 align-items-center">
@ -287,29 +337,25 @@
</div> </div>
</div> </div>
</div> </div>
<div class="col-auto order-xl-0 order-1"> <div class="col-auto order-xl-0 order-1 level-input">
<div class="row h-100 dark-shadow dark-6 rounded"> <div class="row h-100 px-1">
<div class="col"> <div class="col">
<div class="row align-items-center"> <div class="row align-items-center justify-content-left">
<div class="col-3 text-nowrap fw-bold scaled-font"> <div class="col-auto text-nowrap fw-bold scaled-font">
Level: Level:
</div> </div>
<div class="col d-flex justify-content-end"> <div class="col d-flex px-1">
<input class="equipment-input text-light form-control form-control-sm" id="level-choice" name="level-choice" value="106" placeholder="Build level" value="" tabindex="2"/> <input class="equipment-input text-light form-control form-control-sm" id="level-choice" name="level-choice" value="106" placeholder="Build level" value="" tabindex="2"/>
</div> </div>
<div class="col-auto px-1 text-nowrap scaled-font"> <div class="col-auto px-1 scaled-font">
<button class="button fw-bold text-light dark-5 scaled-font rounded" id="reset-button" onclick="resetFields()">Reset</button> <button class="button py-0 fw-bold text-light dark-5 scaled-font rounded" id="reset-button" onclick="resetFields()">Reset</button>
</div>
</div>
<div class="row align-items-center justify-content-center my-1">
<div class="row align-items-center">
<div class="col-auto px-1 text-nowrap scaled-font">
<button class="border-dark text-light dark-5 scaled-font rounded" id=copy-button onclick="copyBuild()">Copy short</button>
</div>
<div class="col-auto px-1 text-nowrap scaled-font">
<button class="border-dark text-light dark-5 scaled-font rounded" id=share-button onclick="shareBuild(player_build)">Copy for sharing</button>
</div> </div>
</div> </div>
<div class="row align-items-left justify-content-left my-1">
<button class="col-auto mx-1 px-1 py-0 border-info text-light dark-5 scaled-font rounded fake-button"
id=copy-button onclick="copyBuild()">Copy short</button>
<button class="col-auto mx-1 px-1 py-0 border-info text-light dark-5 scaled-font rounded fake-button"
id=share-button onclick="shareBuild(player_build)">Copy for sharing</button>
</div> </div>
</div> </div>
</div> </div>
@ -390,12 +436,9 @@
</div> </div>
</div> </div>
</div> </div>
<div class="col-12 text-center gx-2">
<button class = "button fw-bold text-light dark-5 rounded scaled-font" id = "optimize-strdex" onclick = "optimizeStrDex()">Optimize Str/Dex</button>
</div> </div>
</div> </div>
</div> <div class="col text-center py-1">
<div class="col text-center">
<div id="summary-box"></div> <div id="summary-box"></div>
<div id="err-box"></div> <div id="err-box"></div>
<div id="stack-box"></div> <div id="stack-box"></div>
@ -407,8 +450,6 @@
</div> </div>
</div> </div>
</div> </div>
<div class="col">
<div class="row row-cols-1 gy-4">
<div class="col mb-1 text-center scaled-font dark-5 rounded dark-shadow"> <div class="col mb-1 text-center scaled-font dark-5 rounded dark-shadow">
<div class="row row-cols-1 justify-content-center"> <div class="row row-cols-1 justify-content-center">
@ -416,9 +457,6 @@
Active boosts Active boosts
</div> </div>
<div class="col"> <div class="col">
<button class="button-boost m-1 border-0 text-white dark-8u dark-shadow-sm" id="vanish-boost" onclick="update_boosts('vanish-boost')">
Vanish (+80%)
</button>
<button class="button-boost m-1 border-0 text-white dark-8u dark-shadow-sm" id="warscream-boost" onclick="update_boosts('warscream-boost')"> <button class="button-boost m-1 border-0 text-white dark-8u dark-shadow-sm" id="warscream-boost" onclick="update_boosts('warscream-boost')">
War Scream War Scream
</button> </button>
@ -446,19 +484,19 @@
<div class="col mb-1"> <div class="col mb-1">
<div class="row row-cols-1 rounded text-center dark-5 scaled-font"> <div class="row row-cols-1 rounded text-center dark-5 scaled-font">
<div class="row p-0 m-0 text-nowrap"> <div class="row p-0 m-0 text-nowrap">
<div id = "str-boost-tab" class="col eDam dark-4u fake-button elem-boost" onclick="toggle_boost_tab('str')"> <div id = "str-boost-btn" class="col eDam dark-4u fake-button elem-boost" onclick="show_tab('str-boost', ['str-boost', 'dex-boost', 'int-boost', 'def-boost', 'agi-boost'])">
Earth Earth
</div> </div>
<div id = "dex-boost-tab" class="col tDam dark-4u fake-button elem-boost" onclick="toggle_boost_tab('dex')"> <div id = "dex-boost-btn" class="col tDam dark-4u fake-button elem-boost" onclick="show_tab('dex-boost', ['str-boost', 'dex-boost', 'int-boost', 'def-boost', 'agi-boost'])">
Thunder Thunder
</div> </div>
<div id = "int-boost-tab" class="col wDam dark-4u fake-button elem-boost" onclick="toggle_boost_tab('int')"> <div id = "int-boost-btn" class="col wDam dark-4u fake-button elem-boost" onclick="show_tab('int-boost', ['str-boost', 'dex-boost', 'int-boost', 'def-boost', 'agi-boost'])">
Water Water
</div> </div>
<div id = "def-boost-tab" class="col fDam dark-4u fake-button elem-boost" onclick="toggle_boost_tab('def')"> <div id = "def-boost-btn" class="col fDam dark-4u fake-button elem-boost" onclick="show_tab('def-boost', ['str-boost', 'dex-boost', 'int-boost', 'def-boost', 'agi-boost'])">
Fire Fire
</div> </div>
<div id = "agi-boost-tab" class="col aDam dark-4u fake-button elem-boost" onclick="toggle_boost_tab('agi')"> <div id = "agi-boost-btn" class="col aDam dark-4u fake-button elem-boost" onclick="show_tab('agi-boost', ['str-boost', 'dex-boost', 'int-boost', 'def-boost', 'agi-boost'])">
Air Air
</div> </div>
</div> </div>
@ -589,6 +627,10 @@
</div> </div>
</div> </div>
</div> </div>
</div>
<div class="row row-cols-1 d-lg-flex" id="adjust-id" style="display: none;">
<div class="col">
<div class="row row-cols-1 gy-3">
<div class="col mb-1"> <div class="col mb-1">
<div class="row row-cols-1 row-cols-1 text-center scaled-font dark-5 rounded dark-shadow"> <div class="row row-cols-1 row-cols-1 text-center scaled-font dark-5 rounded dark-shadow">
<div class="col fw-bold dark-4 rounded-top"> <div class="col fw-bold dark-4 rounded-top">
@ -620,7 +662,7 @@
<div class="col-auto rounded"> <div class="col-auto rounded">
<div class="row h-100 dark-shadow rounded" id='weaponTome1-dropdown'> <div class="row h-100 dark-shadow rounded" id='weaponTome1-dropdown'>
<div class="col-auto g-0 rounded-end my-auto text-center scaled-item-icon" id="weaponTome1-img-loc"> <div class="col-auto g-0 rounded-end my-auto text-center scaled-item-icon" id="weaponTome1-img-loc">
<img id="weaponTome1-img" class="img-fluid rounded" src="../media/items/new/generic-weaponTome.png"> <div id="weaponTome1-img" class="img-fluid rounded tome-image"></div>
</div> </div>
<div class="col-3"> <div class="col-3">
<div class="row row-cols-1 h-100 align-items-center"> <div class="row row-cols-1 h-100 align-items-center">
@ -644,7 +686,7 @@
<div class="col-auto rounded"> <div class="col-auto rounded">
<div class="row h-100 dark-shadow rounded" id='weaponTome2-dropdown'> <div class="row h-100 dark-shadow rounded" id='weaponTome2-dropdown'>
<div class="col-auto g-0 rounded-end my-auto text-center scaled-item-icon" id="weaponTome2-img-loc"> <div class="col-auto g-0 rounded-end my-auto text-center scaled-item-icon" id="weaponTome2-img-loc">
<img id="weaponTome2-img" class="img-fluid rounded" src="../media/items/new/generic-weaponTome.png"> <div id="weaponTome2-img" class="img-fluid rounded tome-image"></div>
</div> </div>
<div class="col-3"> <div class="col-3">
<div class="row row-cols-1 h-100 align-items-center"> <div class="row row-cols-1 h-100 align-items-center">
@ -668,7 +710,7 @@
<div class="col-auto rounded"> <div class="col-auto rounded">
<div class="row h-100 dark-shadow rounded" id='armorTome1-dropdown'> <div class="row h-100 dark-shadow rounded" id='armorTome1-dropdown'>
<div class="col-auto g-0 rounded-end my-auto text-center scaled-item-icon" id="armorTome1-img-loc"> <div class="col-auto g-0 rounded-end my-auto text-center scaled-item-icon" id="armorTome1-img-loc">
<img id="armorTome1-img" class="img-fluid rounded" src="../media/items/new/generic-armorTome.png"> <div id="armorTome1-img" class="img-fluid rounded tome-image"></div>
</div> </div>
<div class="col-3"> <div class="col-3">
<div class="row row-cols-1 h-100 align-items-center"> <div class="row row-cols-1 h-100 align-items-center">
@ -692,7 +734,7 @@
<div class="col-auto rounded"> <div class="col-auto rounded">
<div class="row h-100 dark-shadow rounded" id='armorTome2-dropdown'> <div class="row h-100 dark-shadow rounded" id='armorTome2-dropdown'>
<div class="col-auto g-0 rounded-end my-auto text-center scaled-item-icon" id="armorTome2-img-loc"> <div class="col-auto g-0 rounded-end my-auto text-center scaled-item-icon" id="armorTome2-img-loc">
<img id="armorTome2-img" class="img-fluid rounded" src="../media/items/new/generic-armorTome.png"> <div id="armorTome2-img" class="img-fluid rounded tome-image"></div>
</div> </div>
<div class="col-3"> <div class="col-3">
<div class="row row-cols-1 h-100 align-items-center"> <div class="row row-cols-1 h-100 align-items-center">
@ -716,7 +758,7 @@
<div class="col-auto rounded"> <div class="col-auto rounded">
<div class="row h-100 dark-shadow rounded" id='armorTome3-dropdown'> <div class="row h-100 dark-shadow rounded" id='armorTome3-dropdown'>
<div class="col-auto g-0 rounded-end my-auto text-center scaled-item-icon" id="armorTome3-img-loc"> <div class="col-auto g-0 rounded-end my-auto text-center scaled-item-icon" id="armorTome3-img-loc">
<img id="armorTome3-img" class="img-fluid rounded" src="../media/items/new/generic-armorTome.png"> <div id="armorTome3-img" class="img-fluid rounded tome-image"></div>
</div> </div>
<div class="col-3"> <div class="col-3">
<div class="row row-cols-1 h-100 align-items-center"> <div class="row row-cols-1 h-100 align-items-center">
@ -740,7 +782,7 @@
<div class="col-auto rounded"> <div class="col-auto rounded">
<div class="row h-100 dark-shadow rounded" id='armorTome4-dropdown'> <div class="row h-100 dark-shadow rounded" id='armorTome4-dropdown'>
<div class="col-auto g-0 rounded-end my-auto text-center scaled-item-icon" id="armorTome4-img-loc"> <div class="col-auto g-0 rounded-end my-auto text-center scaled-item-icon" id="armorTome4-img-loc">
<img id="armorTome4-img" class="img-fluid rounded" src="../media/items/new/generic-armorTome.png"> <div id="armorTome4-img" class="img-fluid rounded tome-image"></div>
</div> </div>
<div class="col-3"> <div class="col-3">
<div class="row row-cols-1 h-100 align-items-center"> <div class="row row-cols-1 h-100 align-items-center">
@ -764,7 +806,7 @@
<div class="col-auto rounded"> <div class="col-auto rounded">
<div class="row h-100 dark-shadow rounded" id='guildTome1-dropdown'> <div class="row h-100 dark-shadow rounded" id='guildTome1-dropdown'>
<div class="col-auto g-0 rounded-end my-auto text-center scaled-item-icon" id="guildTome1-img-loc"> <div class="col-auto g-0 rounded-end my-auto text-center scaled-item-icon" id="guildTome1-img-loc">
<img id="guildTome1-img" class="img-fluid rounded" src="../media/items/new/generic-guildTome.png"> <div id="guildTome1-img" class="img-fluid rounded tome-image"></div>
</div> </div>
<div class="col-3"> <div class="col-3">
<div class="row row-cols-1 h-100 align-items-center"> <div class="row row-cols-1 h-100 align-items-center">
@ -789,7 +831,7 @@
</div> </div>
<div class = "col dark-6 rounded-bottom my-3 my-xl-1" id = "atree-dropdown" style = "display:none;"> <div class = "col dark-6 rounded-bottom my-3 my-xl-1" id = "atree-dropdown" style = "display:none;">
<div class="row row-cols-1 row-cols-xl-2"> <div class="row row-cols-1 row-cols-xl-2">
<div class="col border border-semi-light rounded dark-9 hide-scroll" id="atree-ui" style="height: 90vh; overflow-y: auto; overflow-x: hidden;"> <div class="col border border-semi-light rounded dark-9 hide-scroll" id="atree-ui" style="height: 90vh; overflow-y: auto;">
</div> </div>
<div class="col mx-auto" style="height: 90vh; overflow-y: auto;" id="atree-rhs"> <div class="col mx-auto" style="height: 90vh; overflow-y: auto;" id="atree-rhs">
@ -1131,24 +1173,20 @@
</div> </div>
</div> </div>
</div> </div>
<div class="col-xl-3 mb-3"> <div class="col-xl-3 mb-3 order-2 order-lg-0">
<div class="row row-cols-1 rounded dark-shadow dark-6 scaled-font"> <div class="row row-cols-1 rounded dark-shadow dark-6 scaled-font">
<div class="col rounded-top"> <div class="col rounded-top">
<div class="row"> <div class="row">
<div id="tab-offensive-btn" class="col-4 text-center fake-button border-bottom border-dark rounded-top dark-4u border border-2 border-dark-7" onclick="show_tab('offensive-stats')"> <div id="detailed-stats-btn" class="col text-center fake-button border-bottom border-dark rounded-top dark-4u border border-2 border-dark-7" onclick="show_tab('detailed-stats', ['detailed-stats', 'summary-stats'])">
Offense Detailed
</div> </div>
<div id="tab-defensive-btn" class="col-4 text-center fake-button border-bottom border-dark rounded-top dark-4u border border-2 border-dark-7" onclick="show_tab('defensive-stats')"> <div id="summary-stats-btn" class="col text-center fake-button border-bottom border-dark rounded-top dark-4u border border-2 border-dark-7 selected-btn" onclick="show_tab('summary-stats', ['detailed-stats', 'summary-stats'])">
Defense Summary
</div>
<div id="tab-overall-btn" class="col-4 text-center fake-button border-bottom border-dark rounded-top dark-4u border border-2 border-dark-7 selected-btn" onclick="show_tab('overall-stats')">
Overall
</div> </div>
</div> </div>
</div> </div>
<div style="display: none;" id="offensive-stats" class="col text-nowrap"></div> <div style="display: none;" id="detailed-stats" class="col text-nowrap"></div>
<div style="display: none;" id="defensive-stats" class="col text-nowrap"></div> <div id="summary-stats" class="col text-nowrap"></div>
<div id="overall-stats" class="col text-nowrap"></div>
</div> </div>
</div> </div>
<div class="col-xl-3 mb-3 px-0"> <div class="col-xl-3 mb-3 px-0">
@ -1263,12 +1301,10 @@
<script type="text/javascript" src="../js/build_utils.js"></script> <script type="text/javascript" src="../js/build_utils.js"></script>
<script type="text/javascript" src="../js/computation_graph.js"></script> <script type="text/javascript" src="../js/computation_graph.js"></script>
<script type="text/javascript">COMPUTE_GRAPH_DEBUG=true;</script> <script type="text/javascript">COMPUTE_GRAPH_DEBUG=true;</script>
<!-- <script type="text/javascript" src="../js/icons.js"></script> --> <script type="text/javascript" src="../js/icons.js"></script>
<script type="text/javascript" src="../js/sq2icons.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/skillpoints.js"></script> <script type="text/javascript" src="../js/skillpoints.js"></script>
<script type="text/javascript" src="../js/damage_calc.js"></script> <script type="text/javascript" src="../js/damage_calc.js"></script>
<script type="text/javascript" src="../js/atree_constants_min.js"></script>
<script type="text/javascript" src="../js/display_constants.js"></script> <script type="text/javascript" src="../js/display_constants.js"></script>
<script type="text/javascript" src="../js/display.js"></script> <script type="text/javascript" src="../js/display.js"></script>
<script type="text/javascript" src="../js/load.js"></script> <script type="text/javascript" src="../js/load.js"></script>
@ -1276,13 +1312,14 @@
<script type="text/javascript" src="../js/load_tome.js"></script> <script type="text/javascript" src="../js/load_tome.js"></script>
<script type="text/javascript" src="../js/custom.js"></script> <script type="text/javascript" src="../js/custom.js"></script>
<script type="text/javascript" src="../js/craft.js"></script> <script type="text/javascript" src="../js/craft.js"></script>
<script type="text/javascript" src="../js/build.js"></script> <script type="text/javascript" src="../js/builder/atree_constants_min.js"></script>
<script type="text/javascript" src="../js/build_constants.js"></script> <script type="text/javascript" src="../js/builder/build.js"></script>
<script type="text/javascript" src="../js/build_encode_decode.js"></script> <script type="text/javascript" src="../js/builder/builder_constants.js"></script>
<script type="text/javascript" src="../js/atree.js"></script> <script type="text/javascript" src="../js/builder/build_encode_decode.js"></script>
<script type="text/javascript" src="../js/builder.js"></script> <script type="text/javascript" src="../js/builder/atree.js"></script>
<script type="text/javascript" src="../js/builder_graph.js"></script> <script type="text/javascript" src="../js/builder/builder.js"></script>
<script type="text/javascript" src="../js/optimize.js"></script> <script type="text/javascript" src="../js/builder/builder_graph.js"></script>
<!--script type="text/javascript" src="../js/builder/optimize.js"></script-->
<div id="graph_body" style="max-width: 100%; height: 100vh"> <div id="graph_body" style="max-width: 100%; height: 100vh">
<button id="saveButton">JANKY Export SVG</button> <button id="saveButton">JANKY Export SVG</button>

File diff suppressed because one or more lines are too long

View file

@ -97,7 +97,7 @@
<div class="row row-cols-1 mb-3 gy-4" id="equipment-inputs"> <div class="row row-cols-1 mb-3 gy-4" id="equipment-inputs">
<div class="col"> <div class="col">
<div class="row row-cols-1 row-cols-xl-2 dark-shadow dark-6 justify-content-center equipment-input rounded gy-3 gy-lg-0 mt-auto"> <div class="row row-cols-1 row-cols-xl-2 dark-shadow dark-6 justify-content-center equipment-input rounded gy-3 gy-lg-0 mt-auto">
<div class="col-auto rounded order-xl-0 order-0 my-0"> <div class="col rounded order-xl-0 order-0 my-0">
<div class="row h-100 px-1" id="helmet-dropdown"> <div class="row h-100 px-1" id="helmet-dropdown">
<div class="col-auto px-lg-1 g-0 dark-7 rounded-end my-auto text-center scaled-item-icon" id="helmet-img-loc"> <div class="col-auto px-lg-1 g-0 dark-7 rounded-end my-auto text-center scaled-item-icon" id="helmet-img-loc">
<div id="helmet-img" class="img-fluid rounded item-display-new-toggleable" style="background-image: url('../media/items/new.png'); background-position: 45.45454545454546% 0;"></div> <div id="helmet-img" class="img-fluid rounded item-display-new-toggleable" style="background-image: url('../media/items/new.png'); background-position: 45.45454545454546% 0;"></div>
@ -124,7 +124,7 @@
</div> </div>
</div> </div>
</div> </div>
<div class="col-auto order-xl-0 order-1 my-0"> <div class="col order-xl-0 order-1 my-0">
<div class="row h-100 px-1" id="ring1-dropdown"> <div class="row h-100 px-1" id="ring1-dropdown">
<div class="col-auto px-lg-1 g-0 dark-7 rounded-end my-auto text-center scaled-item-icon" id="ring1-img-loc"> <div class="col-auto px-lg-1 g-0 dark-7 rounded-end my-auto text-center scaled-item-icon" id="ring1-img-loc">
<div id="ring1-img" class="img-fluid rounded item-display-new-toggleable" style="background-image: url('../media/items/new.png'); background-position: 81.81818181818181% 0;"></div> <div id="ring1-img" class="img-fluid rounded item-display-new-toggleable" style="background-image: url('../media/items/new.png'); background-position: 81.81818181818181% 0;"></div>
@ -150,7 +150,7 @@
</div> </div>
</div> </div>
</div> </div>
<div class="col-auto order-xl-0 order-0"> <div class="col order-xl-0 order-0">
<div class="row h-100 px-1" id="chestplate-dropdown"> <div class="row h-100 px-1" id="chestplate-dropdown">
<div class="col-auto px-lg-1 g-0 dark-7 rounded-end my-auto text-center scaled-item-icon" id="chestplate-img-loc"> <div class="col-auto px-lg-1 g-0 dark-7 rounded-end my-auto text-center scaled-item-icon" id="chestplate-img-loc">
<div id="chestplate-img" class="img-fluid rounded item-display-new-toggleable" style="background-image: url('../media/items/new.png'); background-position: 54.54545454545454% 0;"></div> <div id="chestplate-img" class="img-fluid rounded item-display-new-toggleable" style="background-image: url('../media/items/new.png'); background-position: 54.54545454545454% 0;"></div>
@ -177,7 +177,7 @@
</div> </div>
</div> </div>
</div> </div>
<div class="col-auto order-xl-0 order-1"> <div class="col order-xl-0 order-1">
<div class="row h-100 px-1" id="ring2-dropdown"> <div class="row h-100 px-1" id="ring2-dropdown">
<div class="col-auto px-lg-1 g-0 dark-7 rounded-end my-auto text-center scaled-item-icon" id="ring2-img-loc"> <div class="col-auto px-lg-1 g-0 dark-7 rounded-end my-auto text-center scaled-item-icon" id="ring2-img-loc">
<div id="ring2-img" class="img-fluid rounded item-display-new-toggleable" style="background-image: url('../media/items/new.png'); background-position: 81.81818181818181% 0;"></div> <div id="ring2-img" class="img-fluid rounded item-display-new-toggleable" style="background-image: url('../media/items/new.png'); background-position: 81.81818181818181% 0;"></div>
@ -203,7 +203,7 @@
</div> </div>
</div> </div>
</div> </div>
<div class="col-auto order-xl-0 order-0"> <div class="col order-xl-0 order-0">
<div class="row h-100 px-1" id="leggings-dropdown"> <div class="row h-100 px-1" id="leggings-dropdown">
<div class="col-auto px-lg-1 g-0 dark-7 rounded-end my-auto text-center scaled-item-icon" id="leggings-img-loc"> <div class="col-auto px-lg-1 g-0 dark-7 rounded-end my-auto text-center scaled-item-icon" id="leggings-img-loc">
<div id="leggings-img" class="img-fluid rounded item-display-new-toggleable" style="background-image: url('../media/items/new.png'); background-position: 63.63636363636363% 0;"></div> <div id="leggings-img" class="img-fluid rounded item-display-new-toggleable" style="background-image: url('../media/items/new.png'); background-position: 63.63636363636363% 0;"></div>
@ -230,7 +230,7 @@
</div> </div>
</div> </div>
</div> </div>
<div class="col-auto order-xl-0 order-1"> <div class="col order-xl-0 order-1">
<div class="row h-100 px-1" id="bracelet-dropdown"> <div class="row h-100 px-1" id="bracelet-dropdown">
<div class="col-auto px-lg-1 g-0 dark-7 rounded-end my-auto text-center scaled-item-icon" id="bracelet-img-loc"> <div class="col-auto px-lg-1 g-0 dark-7 rounded-end my-auto text-center scaled-item-icon" id="bracelet-img-loc">
<div id="bracelet-img" class="img-fluid rounded item-display-new-toggleable" style="background-image: url('../media/items/new.png'); background-position: 90.90909090909092% 0;"></div> <div id="bracelet-img" class="img-fluid rounded item-display-new-toggleable" style="background-image: url('../media/items/new.png'); background-position: 90.90909090909092% 0;"></div>
@ -257,7 +257,7 @@
</div> </div>
</div> </div>
</div> </div>
<div class="col-auto order-xl-0 order-0"> <div class="col order-xl-0 order-0">
<div class="row h-100 px-1" id="boots-dropdown"> <div class="row h-100 px-1" id="boots-dropdown">
<div class="col-auto px-lg-1 g-0 dark-7 rounded-end my-auto text-center scaled-item-icon" id="boots-img-loc"> <div class="col-auto px-lg-1 g-0 dark-7 rounded-end my-auto text-center scaled-item-icon" id="boots-img-loc">
<div id="boots-img" class="img-fluid rounded item-display-new-toggleable" style="background-image: url('../media/items/new.png'); background-position: 72.72727272727272% 0;"></div> <div id="boots-img" class="img-fluid rounded item-display-new-toggleable" style="background-image: url('../media/items/new.png'); background-position: 72.72727272727272% 0;"></div>
@ -284,7 +284,7 @@
</div> </div>
</div> </div>
</div> </div>
<div class="col-auto order-xl-0 order-1"> <div class="col order-xl-0 order-1">
<div class="row h-100 px-1" id="necklace-dropdown"> <div class="row h-100 px-1" id="necklace-dropdown">
<div class="col-auto px-lg-1 g-0 dark-7 rounded-end my-auto text-center scaled-item-icon" id="necklace-img-loc"> <div class="col-auto px-lg-1 g-0 dark-7 rounded-end my-auto text-center scaled-item-icon" id="necklace-img-loc">
<div id="necklace-img" class="img-fluid rounded item-display-new-toggleable" style="background-image: url('../media/items/new.png'); background-position: 100% 0;"></div> <div id="necklace-img" class="img-fluid rounded item-display-new-toggleable" style="background-image: url('../media/items/new.png'); background-position: 100% 0;"></div>
@ -310,7 +310,7 @@
</div> </div>
</div> </div>
</div> </div>
<div class="col-auto order-xl-0 order-1"> <div class="col order-xl-0 order-1">
<div class="row h-auto px-1" id='weapon-dropdown'> <div class="row h-auto px-1" id='weapon-dropdown'>
<div class="col-auto px-lg-1 g-0 dark-7 rounded-end my-auto text-center scaled-item-icon" id="weapon-img-loc"> <div class="col-auto px-lg-1 g-0 dark-7 rounded-end my-auto text-center scaled-item-icon" id="weapon-img-loc">
<div id="weapon-img" class="img-fluid rounded item-display-new-toggleable" style = "background-image: url('../media/items/new.png');"></div> <div id="weapon-img" class="img-fluid rounded item-display-new-toggleable" style = "background-image: url('../media/items/new.png');"></div>
@ -337,7 +337,7 @@
</div> </div>
</div> </div>
</div> </div>
<div class="col-auto order-xl-0 order-1 level-input"> <div class="col order-xl-0 order-1 level-input">
<div class="row h-100 px-1"> <div class="row h-100 px-1">
<div class="col"> <div class="col">
<div class="row align-items-center justify-content-left"> <div class="row align-items-center justify-content-left">
@ -463,11 +463,8 @@
<button class="button-boost m-1 border-0 text-white dark-8u dark-shadow-sm" id="ragnarokkr-boost" onclick="update_boosts('ragnarokkr-boost')"> <button class="button-boost m-1 border-0 text-white dark-8u dark-shadow-sm" id="ragnarokkr-boost" onclick="update_boosts('ragnarokkr-boost')">
Ragnarokkr (+30%) Ragnarokkr (+30%)
</button> </button>
<button class="button-boost m-1 border-0 text-white dark-8u dark-shadow-sm" id="yourtotem-boost" onclick="update_boosts('yourtotem-boost')"> <button class="button-boost m-1 border-0 text-white dark-8u dark-shadow-sm" id="totem-boost" onclick="update_boosts('totem-boost')">
Your Totem (+35%) Vengeful Spirit (+20%)
</button>
<button class="button-boost m-1 border-0 text-white dark-8u dark-shadow-sm" id="allytotem-boost" onclick="update_boosts('allytotem-boost')">
Ally Totem (+15%)
</button> </button>
<button class="button-boost m-1 border-0 text-white dark-8u dark-shadow-sm" id="fortitude-boost" onclick="update_boosts('fortitude-boost')"> <button class="button-boost m-1 border-0 text-white dark-8u dark-shadow-sm" id="fortitude-boost" onclick="update_boosts('fortitude-boost')">
Fortitude (+60%) Fortitude (+60%)
@ -837,6 +834,8 @@
<div class="col mx-auto" style="height: 90vh; overflow-y: auto;" id="atree-rhs"> <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 class="col mx-auto" style="height: 2em; overflow-y: auto;" id="atree-header">
</div> </div>
<div class="col mx-auto" style="" id="atree-warning">
</div>
<div class="col mx-auto" style="overflow-y: auto;" id="atree-active"> <div class="col mx-auto" style="overflow-y: auto;" id="atree-active">
</div> </div>
</div> </div>
@ -1304,7 +1303,6 @@
<script type="text/javascript" src="../js/powders.js"></script> <script type="text/javascript" src="../js/powders.js"></script>
<script type="text/javascript" src="../js/skillpoints.js"></script> <script type="text/javascript" src="../js/skillpoints.js"></script>
<script type="text/javascript" src="../js/damage_calc.js"></script> <script type="text/javascript" src="../js/damage_calc.js"></script>
<script type="text/javascript" src="../js/atree_constants_min.js"></script>
<script type="text/javascript" src="../js/display_constants.js"></script> <script type="text/javascript" src="../js/display_constants.js"></script>
<script type="text/javascript" src="../js/display.js"></script> <script type="text/javascript" src="../js/display.js"></script>
<script type="text/javascript" src="../js/load.js"></script> <script type="text/javascript" src="../js/load.js"></script>
@ -1312,13 +1310,13 @@
<script type="text/javascript" src="../js/load_tome.js"></script> <script type="text/javascript" src="../js/load_tome.js"></script>
<script type="text/javascript" src="../js/custom.js"></script> <script type="text/javascript" src="../js/custom.js"></script>
<script type="text/javascript" src="../js/craft.js"></script> <script type="text/javascript" src="../js/craft.js"></script>
<script type="text/javascript" src="../js/build.js"></script> <script type="text/javascript" src="../js/builder/atree_constants_min.js"></script>
<script type="text/javascript" src="../js/build_constants.js"></script> <script type="text/javascript" src="../js/builder/build.js"></script>
<script type="text/javascript" src="../js/build_encode_decode.js"></script> <script type="text/javascript" src="../js/builder/builder_constants.js"></script>
<script type="text/javascript" src="../js/atree.js"></script> <script type="text/javascript" src="../js/builder/build_encode_decode.js"></script>
<script type="text/javascript" src="../js/builder.js"></script> <script type="text/javascript" src="../js/builder/atree.js"></script>
<script type="text/javascript" src="../js/builder_graph.js"></script> <script type="text/javascript" src="../js/builder/builder.js"></script>
<script type="text/javascript" src="../js/optimize.js"></script> <script type="text/javascript" src="../js/builder/builder_graph.js"></script>
<!--script type="text/javascript" src="../js/builder/optimize.js"></script-->
</body> </body>
</html> </html>

File diff suppressed because it is too large Load diff

View file

@ -19,9 +19,9 @@
"mr": 10, "mr": 10,
"int": 15, "int": 15,
"def": -10, "def": -10,
"wDamPct": 30,
"aDamPct": 35, "aDamPct": 35,
"tDamPct": -40, "tDamPct": -40,
"wDefPct": 30,
"spRaw4": -4, "spRaw4": -4,
"id": 3579 "id": 3579
}, },
@ -65,7 +65,7 @@
"lvl": 104, "lvl": 104,
"strReq": 60, "strReq": 60,
"agiReq": 60, "agiReq": 60,
"mr": 8, "mr": 10,
"ref": 48, "ref": 48,
"atkTier": -1, "atkTier": -1,
"aDamPct": 32, "aDamPct": 32,
@ -973,7 +973,6 @@
"ms": 30, "ms": 30,
"xpb": 30, "xpb": 30,
"ref": 20, "ref": 20,
"spRaw3": 6,
"id": 1711 "id": 1711
}, },
{ {
@ -2334,7 +2333,7 @@
"aDamPct": 30, "aDamPct": 30,
"aDefPct": 20, "aDefPct": 20,
"fixID": true, "fixID": true,
"spRaw1": -5, "spRaw1": -3,
"id": 2510 "id": 2510
}, },
{ {
@ -3187,10 +3186,10 @@
"intReq": 23, "intReq": 23,
"agiReq": 23, "agiReq": 23,
"defReq": 23, "defReq": 23,
"mr": 5, "mr": 9,
"sdPct": 15, "sdPct": 15,
"mdPct": 15, "mdPct": 15,
"ms": 5, "ms": 9,
"str": 17, "str": 17,
"dex": 17, "dex": 17,
"int": 17, "int": 17,
@ -3211,6 +3210,7 @@
"quest": "The Qira Hive", "quest": "The Qira Hive",
"category": "armor", "category": "armor",
"displayName": "Anima-Infused Cuirass", "displayName": "Anima-Infused Cuirass",
"set": "Master Hive",
"slots": 2, "slots": 2,
"hp": 3800, "hp": 3800,
"fDef": 200, "fDef": 200,
@ -17497,7 +17497,7 @@
"aDefPct": -25, "aDefPct": -25,
"fixID": true, "fixID": true,
"spPct4": 28, "spPct4": 28,
"rainbowRaw": 1275, "rSdRaw": 1275,
"id": 720 "id": 720
}, },
{ {

File diff suppressed because one or more lines are too long

View file

@ -63,6 +63,7 @@
<script type="text/javascript" src="/js/load_ing.js"></script> <script type="text/javascript" src="/js/load_ing.js"></script>
<script type="text/javascript" src="/js/display_constants.js"></script> <script type="text/javascript" src="/js/display_constants.js"></script>
<script type="text/javascript" src="/js/display.js"></script> <script type="text/javascript" src="/js/display.js"></script>
<script type="text/javascript" src="/js/item_display.js"></script>
<script type="text/javascript" src="/js/item.js"></script> <script type="text/javascript" src="/js/item.js"></script>
</body> </body>
</html> </html>

View file

@ -16,7 +16,7 @@
<link rel="stylesheet" href="../css/sq2bs.css"> <link rel="stylesheet" href="../css/sq2bs.css">
<link rel="stylesheet" href="../css/items_2.css"> <link rel="stylesheet" href="../css/items_adv.css">
<link rel="stylesheet" href="../css/sidebar.css"> <link rel="stylesheet" href="../css/sidebar.css">
<link rel="stylesheet" href="../css/wynnstyles.css"> <link rel="stylesheet" href="../css/wynnstyles.css">
</head> </head>
@ -39,7 +39,7 @@
<a href="../credits.txt" class="link">Additional credits</a> <a href="../credits.txt" class="link">Additional credits</a>
</div> </div>
<div class = "col text-center" id = "help"> <div class = "col text-center" id = "help">
<a href="items_2_help.html" class="link" target="_blank">Search Guide</a> <a href="items_adv_help.html" class="link" target="_blank">Search Guide</a>
</div> </div>
<div class = "col text-end"> <div class = "col text-end">
<a href = "../items/">Basic Item Search</a> <a href = "../items/">Basic Item Search</a>
@ -77,12 +77,13 @@
<script type="text/javascript" src="/js/utils.js"></script> <script type="text/javascript" src="/js/utils.js"></script>
<script type="text/javascript" src="/js/build_utils.js"></script> <script type="text/javascript" src="/js/build_utils.js"></script>
<script type="text/javascript" src="/js/icons.js"></script> <script type="text/javascript" src="/js/icons.js"></script>
<script type="text/javascript" src="/js/powders.js"></script>
<script type="text/javascript" src="/js/damage_calc.js"></script> <script type="text/javascript" src="/js/damage_calc.js"></script>
<script type="text/javascript" src="/js/display_constants.js"></script> <script type="text/javascript" src="/js/display_constants.js"></script>
<script type="text/javascript" src="/js/display.js"></script> <script type="text/javascript" src="/js/display.js"></script>
<script type="text/javascript" src="/js/query.js"></script> <script type="text/javascript" src="/js/query.js"></script>
<script type="text/javascript" src="/js/expr_parser.js"></script> <script type="text/javascript" src="/js/expr_parser.js"></script>
<script type="text/javascript" src="/js/load.js"></script> <script type="text/javascript" src="/js/load.js"></script>
<script type="text/javascript" src="/js/items_2.js"></script> <script type="text/javascript" src="/js/items_adv.js"></script>
</body> </body>
</html> </html>

View file

@ -1,6 +0,0 @@
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

File diff suppressed because one or more lines are too long

View file

@ -12,7 +12,7 @@ function skillPointsToPercentage(skp){
skp = 150; skp = 150;
} }
const r = 0.9908; const r = 0.9908;
return ((1 - Math.pow(r, skp + 1)) / (1 - r) - 1) / 100.0; return (r/(1-r)*(1 - Math.pow(r, skp))) / 100.0;
//return (-0.0000000066695* Math.pow(Math.E, -0.00924033 * skp + 18.9) + 1.0771); //return (-0.0000000066695* Math.pow(Math.E, -0.00924033 * skp + 18.9) + 1.0771);
//return(-0.0000000066695* Math.pow(Math.E, -0.00924033 * skp + 18.9) + 1.0771).toFixed(3); //return(-0.0000000066695* Math.pow(Math.E, -0.00924033 * skp + 18.9) + 1.0771).toFixed(3);
//return Math.min(Math.max(0.00,(-0.0000000066695* Math.pow(Math.E, -0.00924033 * skp + 18.9) + 1.0771)),.808); //return Math.min(Math.max(0.00,(-0.0000000066695* Math.pow(Math.E, -0.00924033 * skp + 18.9) + 1.0771)),.808);
@ -86,7 +86,8 @@ let item_fields = [ "name", "displayName", "lore", "color", "tier", "set", "slot
"nMdPct","nMdRaw","nSdPct","nSdRaw","nDamPct","nDamRaw","nDamAddMin","nDamAddMax", // neutral which is now an element "nMdPct","nMdRaw","nSdPct","nSdRaw","nDamPct","nDamRaw","nDamAddMin","nDamAddMax", // neutral which is now an element
/*"mdPct","mdRaw","sdPct","sdRaw",*/"damPct","damRaw","damAddMin","damAddMax", // These are the old ids. Become proportional. /*"mdPct","mdRaw","sdPct","sdRaw",*/"damPct","damRaw","damAddMin","damAddMax", // These are the old ids. Become proportional.
"rMdPct","rMdRaw","rSdPct",/*"rSdRaw",*/"rDamPct","rDamRaw","rDamAddMin","rDamAddMax", // rainbow (the "element" of all minus neutral). rSdRaw is rainraw "rMdPct","rMdRaw","rSdPct",/*"rSdRaw",*/"rDamPct","rDamRaw","rDamAddMin","rDamAddMax", // rainbow (the "element" of all minus neutral). rSdRaw is rainraw
"critDamPct" "critDamPct",
"spPct1Final", "spPct2Final", "spPct3Final", "spPct4Final"
]; ];
// Extra fake IDs (reserved for use in spell damage calculation) : damMult, defMult, poisonPct, activeMajorIDs // Extra fake IDs (reserved for use in spell damage calculation) : damMult, defMult, poisonPct, activeMajorIDs
let str_item_fields = [ "name", "displayName", "lore", "color", "tier", "set", "type", "material", "drop", "quest", "restrict", "category", "atkSpd" ] let str_item_fields = [ "name", "displayName", "lore", "color", "tier", "set", "type", "material", "drop", "quest", "restrict", "category", "atkSpd" ]
@ -127,16 +128,7 @@ let nonRolledIDs = [
"nDam_", "fDam_", "wDam_", "aDam_", "tDam_", "eDam_", "nDam_", "fDam_", "wDam_", "aDam_", "tDam_", "eDam_",
"majorIds", "majorIds",
"damMobs", "damMobs",
"defMobs", "defMobs"
// wynn2 damages.
"eDamAddMin","eDamAddMax",
"tDamAddMin","tDamAddMax",
"wDamAddMin","wDamAddMax",
"fDamAddMin","fDamAddMax",
"aDamAddMin","aDamAddMax",
"nDamAddMin","nDamAddMax", // neutral which is now an element
"damAddMin","damAddMax", // all
"rDamAddMin","rDamAddMax" // rainbow (the "element" of all minus neutral).
]; ];
let rolledIDs = [ let rolledIDs = [
"hprPct", "hprPct",
@ -165,7 +157,7 @@ let rolledIDs = [
"spPct2", "spRaw2", "spPct2", "spRaw2",
"spPct3", "spRaw3", "spPct3", "spRaw3",
"spPct4", "spRaw4", "spPct4", "spRaw4",
"pDamRaw", "rSdRaw",
"sprint", "sprint",
"sprintReg", "sprintReg",
"jh", "jh",
@ -180,7 +172,8 @@ let rolledIDs = [
"aMdPct","aMdRaw","aSdPct","aSdRaw",/*"aDamPct,"*/"aDamRaw","aDamAddMin","aDamAddMax", "aMdPct","aMdRaw","aSdPct","aSdRaw",/*"aDamPct,"*/"aDamRaw","aDamAddMin","aDamAddMax",
"nMdPct","nMdRaw","nSdPct","nSdRaw","nDamPct","nDamRaw","nDamAddMin","nDamAddMax", // neutral which is now an element "nMdPct","nMdRaw","nSdPct","nSdRaw","nDamPct","nDamRaw","nDamAddMin","nDamAddMax", // neutral which is now an element
/*"mdPct","mdRaw","sdPct","sdRaw",*/"damPct","damRaw","damAddMin","damAddMax", // These are the old ids. Become proportional. /*"mdPct","mdRaw","sdPct","sdRaw",*/"damPct","damRaw","damAddMin","damAddMax", // These are the old ids. Become proportional.
"rMdPct","rMdRaw","rSdPct",/*"rSdRaw",*/"rDamPct","rDamRaw","rDamAddMin","rDamAddMax" // rainbow (the "element" of all minus neutral). rSdRaw is rainraw "rMdPct","rMdRaw","rSdPct",/*"rSdRaw",*/"rDamPct","rDamRaw","rDamAddMin","rDamAddMax", // rainbow (the "element" of all minus neutral). rSdRaw is rainraw
"spPct1Final", "spPct2Final", "spPct3Final", "spPct4Final"
]; ];
let reversedIDs = [ "spPct1", "spRaw1", "spPct2", "spRaw2", "spPct3", "spRaw3", "spPct4", "spRaw4" ]; let reversedIDs = [ "spPct1", "spRaw1", "spPct2", "spRaw2", "spPct3", "spRaw3", "spPct4", "spRaw4" ];

View file

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

View file

@ -50,7 +50,10 @@ add_spell_prop: {
cost: Optional[int] // change to spellcost. If the spell is not spell 1-4, this must be left empty. cost: Optional[int] // change to spellcost. If the spell is not spell 1-4, this must be left empty.
multipliers: Optional[array[float, 6]] // Additive changes to spellmult (for damage spell) multipliers: Optional[array[float, 6]] // Additive changes to spellmult (for damage spell)
power: Optional[float] // Additive change to healing power (for heal spell) power: Optional[float] // Additive change to healing power (for heal spell)
hits: Optional[Map[str, float]] // Additive changes to hits (for total entry)
hits: Optional[Map[str, Union[str, float]]] // Additive changes to hits (for total entry)
// Can either be a raw value number, or a reference
// of the format <ability_id>.propname
display: Optional[str] // Optional change to the displayed entry. Replaces old display: Optional[str] // Optional change to the displayed entry. Replaces old
} }
@ -191,8 +194,8 @@ const atree_node = new (class extends ComputeNode {
atree_topo_sort.push(node); atree_topo_sort.push(node);
} }
} }
console.log("Approximate topological order ability tree:"); //console.log("Approximate topological order ability tree:");
console.log(atree_topo_sort); //console.log(atree_topo_sort);
return atree_topo_sort; return atree_topo_sort;
} }
})(); })();
@ -238,71 +241,6 @@ const atree_state_node = new (class extends ComputeNode {
} }
})().link_to(atree_render, 'atree-render'); })().link_to(atree_render, 'atree-render');
/**
* Collect abilities and condense them into a list of "final abils".
* This is just for rendering purposes, and for collecting things that modify spells into one chunk.
* I stg if wynn makes abils that modify multiple spells
* ... well we can extend this by making `base_abil` a list instead but annoy
*
* Signature: AbilityTreeMergeNode(player-class: WeaponType, atree: ATree, atree-state: RenderedATree) => Map[id, Ability]
*/
const atree_merge = new (class extends ComputeNode {
constructor() { super('builder-atree-merge'); }
compute_func(input_map) {
const player_class = input_map.get('player-class');
const atree_state = input_map.get('atree-state');
const atree_order = input_map.get('atree');
let abils_merged = new Map();
for (const abil of default_abils[player_class]) {
let tmp_abil = deepcopy(abil);
if (!('desc' in tmp_abil)) {
tmp_abil.desc = [];
}
else if (!Array.isArray(tmp_abil.desc)) {
tmp_abil.desc = [tmp_abil.desc];
}
tmp_abil.subparts = [abil.id];
abils_merged.set(abil.id, tmp_abil);
}
for (const node of atree_order) {
const abil_id = node.ability.id;
if (!atree_state.get(abil_id).active) {
continue;
}
const abil = node.ability;
if ('base_abil' in abil) {
if (abils_merged.has(abil.base_abil)) {
// Merge abilities.
// TODO: What if there is more than one base abil?
let base_abil = abils_merged.get(abil.base_abil);
if (Array.isArray(abil.desc)) { base_abil.desc = base_abil.desc.concat(abil.desc); }
else { base_abil.desc.push(abil.desc); }
base_abil.subparts.push(abil.id);
base_abil.effects = base_abil.effects.concat(abil.effects);
for (let propname in abil.properties) {
base_abil[propname] = abil[propname];
}
}
// do nothing otherwise.
}
else {
let tmp_abil = deepcopy(abil);
if (!Array.isArray(tmp_abil.desc)) {
tmp_abil.desc = [tmp_abil.desc];
}
tmp_abil.subparts = [abil.id];
abils_merged.set(abil_id, tmp_abil);
}
}
return abils_merged;
}
})().link_to(atree_node, 'atree').link_to(atree_state_node, 'atree-state');
/** /**
* Check if an atree node can be activated. * Check if an atree node can be activated.
* *
@ -377,11 +315,11 @@ const atree_validate = new (class extends ComputeNode {
const abil = node.ability; const abil = node.ability;
if (atree_state.get(abil.id).active) { if (atree_state.get(abil.id).active) {
atree_to_add.push([node, 'not reachable', false]); atree_to_add.push([node, 'not reachable', false]);
drawAtlasImage(atree_state.get(abil.id).img, atreeNodeAtlasImg, [atreeNodeAtlasPositions[abil.display.icon], 2], atreeNodeTileSize); draw_atlas_image(atree_state.get(abil.id).img, atree_node_atlas_img, [atree_node_atlas_positions[abil.display.icon], 2], atree_node_tile_size);
} }
else { else {
atree_not_present.push(abil.id); atree_not_present.push(abil.id);
drawAtlasImage(atree_state.get(abil.id).img, atreeNodeAtlasImg, [atreeNodeAtlasPositions[abil.display.icon], 0], atreeNodeTileSize); draw_atlas_image(atree_state.get(abil.id).img, atree_node_atlas_img, [atree_node_atlas_positions[abil.display.icon], 0], atree_node_tile_size);
} }
} }
@ -430,7 +368,7 @@ const atree_validate = new (class extends ComputeNode {
const node = atree_state.get(node_id); const node = atree_state.get(node_id);
const [success, hard_error, reason] = abil_can_activate(node, atree_state, reachable, archetype_count, ap_left); const [success, hard_error, reason] = abil_can_activate(node, atree_state, reachable, archetype_count, ap_left);
if (success) { if (success) {
drawAtlasImage(node.img, atreeNodeAtlasImg, [atreeNodeAtlasPositions[node.ability.display.icon], 1], atreeNodeTileSize); draw_atlas_image(node.img, atree_node_atlas_img, [atree_node_atlas_positions[node.ability.display.icon], 1], atree_node_tile_size);
} }
} }
@ -449,176 +387,74 @@ const atree_validate = new (class extends ComputeNode {
})().link_to(atree_node, 'atree').link_to(atree_state_node, 'atree-state'); })().link_to(atree_node, 'atree').link_to(atree_state_node, 'atree-state');
/** /**
* Render ability tree. * Collect abilities and condense them into a list of "final abils".
* Return map of id -> corresponding html element. * This is just for rendering purposes, and for collecting things that modify spells into one chunk.
* I stg if wynn makes abils that modify multiple spells
* ... well we can extend this by making `base_abil` a list instead but annoy
* *
* Signature: AbilityTreeRenderActiveNode(atree-merged: MergedATree, atree-order: ATree, atree-errors: List[str]) => Map[int, ATreeNode] * Signature: AbilityTreeMergeNode(player-class: WeaponType, atree: ATree, atree-state: RenderedATree) => Map[id, Ability]
*/ */
const atree_render_active = new (class extends ComputeNode { const atree_merge = new (class extends ComputeNode {
constructor() { constructor() { super('builder-atree-merge'); }
super('atree-render-active');
this.list_elem = document.getElementById("atree-active");
}
compute_func(input_map) { compute_func(input_map) {
const merged_abils = input_map.get('atree-merged');
const atree_order = input_map.get('atree-order');
const [hard_error, _errors] = input_map.get('atree-errors');
const errors = deepcopy(_errors);
this.list_elem.innerHTML = ""; //reset all atree actives - should be done in a more general way later
// TODO: move to display?
if (errors.length > 0) {
const errorbox = make_elem('div', ['rounded-bottom', 'dark-4', 'border', 'p-0', 'mx-2', 'my-4', 'dark-shadow']);
this.list_elem.append(errorbox);
const error_title = make_elem('b', ['warning', 'scaled-font'], { innerHTML: "ATree Error!" });
errorbox.append(error_title);
for (let i = 0; i < 5 && i < errors.length; ++i) {
errorbox.append(make_elem("p", ["warning", "small-text"], {textContent: errors[i]}));
}
if (errors.length > 5) {
const error = '... ' + (errors.length-5) + ' errors not shown';
errorbox.append(make_elem("p", ["warning", "small-text"], {textContent: error}));
}
}
const ret_map = new Map();
const to_render_id = [999, 998];
for (const node of atree_order) {
if (!merged_abils.has(node.ability.id)) {
continue;
}
to_render_id.push(node.ability.id);
}
for (const id of to_render_id) {
const abil = merged_abils.get(id);
const active_tooltip = make_elem('div', ['rounded-bottom', 'dark-4', 'border', 'p-0', 'mx-2', 'my-4', 'dark-shadow']);
active_tooltip.append(make_elem('b', ['scaled-font'], { innerHTML: abil.display_name }));
for (const desc of abil.desc) {
active_tooltip.append(make_elem('p', ['scaled-font-sm', 'my-0', 'mx-1', 'text-wrap'], { textContent: desc }));
}
ret_map.set(abil.id, active_tooltip);
this.list_elem.append(active_tooltip);
}
return ret_map;
}
})().link_to(atree_node, 'atree-order').link_to(atree_merge, 'atree-merged').link_to(atree_validate, 'atree-errors');
/**
* Collect spells from abilities.
*
* Signature: AbilityCollectSpellsNode(atree-merged: Map[id, Ability]) => List[Spell]
*/
const atree_collect_spells = new (class extends ComputeNode {
constructor() { super('atree-spell-collector'); }
compute_func(input_map) {
const atree_merged = input_map.get('atree-merged');
const [hard_error, errors] = input_map.get('atree-errors'); const [hard_error, errors] = input_map.get('atree-errors');
if (hard_error) { return []; } if (hard_error) { return null; }
const player_class = input_map.get('player-class');
const atree_state = input_map.get('atree-state');
const atree_order = input_map.get('atree');
let ret_spells = new Map(); let abils_merged = new Map();
for (const [abil_id, abil] of atree_merged.entries()) { for (const abil of default_abils[player_class]) {
// TODO: Possibly, make a better way for detecting "spell abilities"? let tmp_abil = deepcopy(abil);
for (const effect of abil.effects) { if (!('desc' in tmp_abil)) {
if (effect.type === 'replace_spell') { tmp_abil.desc = [];
// replace_spell just replaces all (defined) aspects.
const ret_spell = ret_spells.get(effect.base_spell);
if (ret_spell) {
// NOTE: do not mutate results of previous steps!
for (const key in effect) {
ret_spell[key] = deepcopy(effect[key]);
} }
else if (!Array.isArray(tmp_abil.desc)) {
tmp_abil.desc = [tmp_abil.desc];
}
tmp_abil.subparts = [abil.id];
abils_merged.set(abil.id, tmp_abil);
}
for (const node of atree_order) {
const abil_id = node.ability.id;
if (!atree_state.get(abil_id).active) {
continue;
}
const abil = node.ability;
if ('base_abil' in abil) {
if (abils_merged.has(abil.base_abil)) {
// Merge abilities.
// TODO: What if there is more than one base abil?
let base_abil = abils_merged.get(abil.base_abil);
if (Array.isArray(abil.desc)) { base_abil.desc = base_abil.desc.concat(abil.desc); }
else { base_abil.desc.push(abil.desc); }
base_abil.subparts.push(abil.id);
base_abil.effects = base_abil.effects.concat(abil.effects);
for (let propname in abil.properties) {
if (propname in base_abil.properties) {
base_abil.properties[propname] += abil.properties[propname];
}
else { base_abil.properties[propname] = abil.properties[propname]; }
}
}
// do nothing otherwise.
} }
else { else {
ret_spells.set(effect.base_spell, deepcopy(effect)); let tmp_abil = deepcopy(abil);
if (!Array.isArray(tmp_abil.desc)) {
tmp_abil.desc = [tmp_abil.desc];
}
tmp_abil.subparts = [abil.id];
abils_merged.set(abil_id, tmp_abil);
} }
} }
return abils_merged;
} }
} })().link_to(atree_node, 'atree').link_to(atree_state_node, 'atree-state').link_to(atree_validate, 'atree-errors');
for (const [abil_id, abil] of atree_merged.entries()) {
for (const effect of abil.effects) {
switch (effect.type) {
case 'replace_spell':
// Already handled above.
continue;
case 'add_spell_prop': {
const { base_spell, target_part = null, cost = 0, behavior = 'merge'} = effect;
const ret_spell = ret_spells.get(base_spell);
// TODO: unjankify this...
if ('cost' in ret_spell) { ret_spell.cost += cost; }
if (target_part === null) {
continue;
}
let found_part = false;
for (let part of ret_spell.parts) { // TODO: replace with Map? to avoid this linear search... idk prolly good since its not more verbose to type in json
if (part.name !== target_part) {
continue;
}
if ('multipliers' in effect) {
for (const [idx, v] of effect.multipliers.entries()) { // python: enumerate()
part.multipliers[idx] += v;
}
}
else if ('power' in effect) {
part.power += effect.power;
}
else if ('hits' in effect) {
for (const [idx, v] of Object.entries(effect.hits)) { // looks kinda similar to multipliers case... hmm... can we unify all of these three? (make healpower a list)
if (idx in part.hits) { part.hits[idx] += v; }
else { part.hits[idx] = v; }
}
}
else {
throw "uhh invalid spell add effect";
}
found_part = true;
break;
}
if (!found_part && behavior === 'merge') { // add part. if behavior is merge
let spell_part = deepcopy(effect);
spell_part.name = target_part; // has some extra fields but whatever
ret_spell.parts.push(spell_part);
}
if ('display' in effect) {
ret_spell.display = effect.display;
}
continue;
}
case 'convert_spell_conv':
const { base_spell, target_part, conversion } = effect;
const ret_spell = ret_spells.get(base_spell);
const elem_idx = damageClasses.indexOf(conversion);
let filter = target_part === 'all';
for (let part of ret_spell.parts) { // TODO: replace with Map? to avoid this linear search... idk prolly good since its not more verbose to type in json
if (filter || part.name === target_part) {
if ('multipliers' in part) {
let total_conv = 0;
for (let i = 1; i < 6; ++i) { // skip neutral
total_conv += part.multipliers[i];
}
let new_conv = [part.multipliers[0], 0, 0, 0, 0, 0];
new_conv[elem_idx] = total_conv;
part.multipliers = new_conv;
}
}
}
continue;
}
}
}
return ret_spells;
}
})().link_to(atree_merge, 'atree-merged').link_to(atree_validate, 'atree-errors');
/** /**
* Make interactive elements (sliders, buttons) * Make interactive elements (sliders, buttons)
@ -635,10 +471,11 @@ const atree_make_interactives = new (class extends ComputeNode {
compute_func(input_map) { compute_func(input_map) {
const merged_abils = input_map.get('atree-merged'); const merged_abils = input_map.get('atree-merged');
const atree_order = input_map.get('atree-order'); const atree_order = input_map.get('atree-order');
const atree_html = input_map.get('atree-elements');
document.getElementById("boost-sliders").innerHTML = ""; const boost_slider_parent = document.getElementById("boost-sliders");
document.getElementById("boost-toggles").innerHTML = ""; const boost_toggle_parent = document.getElementById("boost-toggles");
boost_slider_parent.innerHTML = "";
boost_toggle_parent.innerHTML = "";
/** /**
* slider_info * slider_info
@ -687,7 +524,7 @@ const atree_make_interactives = new (class extends ComputeNode {
// next, render the sliders and toggles onto the abilities. // next, render the sliders and toggles onto the abilities.
for (const [slider_name, slider_info] of slider_map.entries()) { for (const [slider_name, slider_info] of slider_map.entries()) {
let slider_container = gen_slider_labeled(slider_info); let slider_container = gen_slider_labeled(slider_info);
document.getElementById("boost-sliders").appendChild(slider_container); boost_slider_parent.appendChild(slider_container);
slider_info.slider = document.getElementById(slider_info.id); slider_info.slider = document.getElementById(slider_info.id);
slider_info.slider.addEventListener("change", (e) => atree_scaling.mark_dirty().update()); slider_info.slider.addEventListener("change", (e) => atree_scaling.mark_dirty().update());
} }
@ -705,18 +542,18 @@ const atree_make_interactives = new (class extends ComputeNode {
atree_scaling.mark_dirty().update() atree_scaling.mark_dirty().update()
}); });
button_info.button = button; button_info.button = button;
document.getElementById("boost-toggles").appendChild(button); boost_toggle_parent.appendChild(button);
} }
return [slider_map, button_map]; return [slider_map, button_map];
} }
})().link_to(atree_node, 'atree-order').link_to(atree_merge, 'atree-merged').link_to(atree_render_active, 'atree-elements'); })().link_to(atree_node, 'atree-order').link_to(atree_merge, 'atree-merged');
/** /**
* Scaling stats from ability tree. * Scaling stats from ability tree.
* Return StatMap of added stats, * Return StatMap of added stats,
* *
* Signature: AbilityTreeScalingNode(atree-merged: MergedATree, scale-scats: StatMap, * Signature: AbilityTreeScalingNode(atree-merged: MergedATree, scale-scats: StatMap,
* atree-interactive: [Map<str, slider_info>, Map<str, button_info>]) => StatMap * atree-interactive: [Map<str, slider_info>, Map<str, button_info>]) => (ATree, StatMap)
*/ */
const atree_scaling = new (class extends ComputeNode { const atree_scaling = new (class extends ComputeNode {
constructor() { super('atree-scaling-collector'); } constructor() { super('atree-scaling-collector'); }
@ -726,23 +563,41 @@ const atree_scaling = new (class extends ComputeNode {
const pre_scale_stats = input_map.get('scale-stats'); const pre_scale_stats = input_map.get('scale-stats');
const [slider_map, button_map] = input_map.get('atree-interactive'); const [slider_map, button_map] = input_map.get('atree-interactive');
const atree_edit = new Map();
for (const [abil_id, abil] of atree_merged.entries()) {
atree_edit.set(abil_id, deepcopy(abil));
}
let ret_effects = new Map(); let ret_effects = new Map();
// Apply a stat bonus.
function apply_bonus(bonus_info, value) {
const { type, name, abil = null} = bonus_info;
if (type === 'stat') {
merge_stat(ret_effects, name, value);
} else if (type === 'prop') {
const merge_abil = atree_edit.get(abil);
if (merge_abil) {
merge_abil.properties[name] += value;
}
}
}
for (const [abil_id, abil] of atree_merged.entries()) { for (const [abil_id, abil] of atree_merged.entries()) {
if (abil.effects.length == 0) { continue; } if (abil.effects.length == 0) { continue; }
for (const effect of abil.effects) { for (const effect of abil.effects) {
switch (effect.type) { switch (effect.type) {
case 'raw_stat': case 'raw_stat':
// TODO: toggles...
if (effect.toggle) { if (effect.toggle) {
const button = button_map.get(effect.toggle).button; const button = button_map.get(effect.toggle).button;
if (!button.classList.contains("toggleOn")) { continue; } if (!button.classList.contains("toggleOn")) { continue; }
for (const bonus of effect.bonuses) { for (const bonus of effect.bonuses) {
const { type, name, abil = "", value } = bonus; apply_bonus(bonus, bonus.value);
// TODO: prop
if (type === "stat") {
merge_stat(ret_effects, name, value);
} }
} else {
for (const bonus of effect.bonuses) {
// Stat was applied earlier...
if (bonus.type === 'stat') { continue; }
apply_bonus(bonus, bonus.value);
} }
} }
continue; continue;
@ -769,14 +624,242 @@ const atree_scaling = new (class extends ComputeNode {
if ('max' in effect && total > effect.max) { total = effect.max; } if ('max' in effect && total > effect.max) { total = effect.max; }
if (Array.isArray(effect.output)) { if (Array.isArray(effect.output)) {
for (const output of effect.output) { for (const output of effect.output) {
if (output.type === 'stat') { // TODO: prop apply_bonus(output, total);
merge_stat(ret_effects, output.name, total);
}
} }
} }
else { else {
if (effect.output.type === 'stat') { apply_bonus(effect.output, total);
merge_stat(ret_effects, effect.output.name, total); }
}
continue;
}
}
}
return [atree_edit, ret_effects];
}
})().link_to(atree_merge, 'atree-merged').link_to(atree_make_interactives, 'atree-interactive');
/**
* These following two nodes are just boilerplate that breaks down the scaling node.
*/
const atree_scaling_tree = new (class extends ComputeNode {
constructor() { super('atree-scaling-tree'); }
compute_func(input_map) {
const [[tree, stats]] = input_map.values();
return tree;
}
})().link_to(atree_scaling, 'atree-scaling');
const atree_scaling_stats = new (class extends ComputeNode {
constructor() { super('atree-scaling-stats'); }
compute_func(input_map) {
const [[tree, stats]] = input_map.values();
return stats;
}
})().link_to(atree_scaling, 'atree-scaling');
const atree_render_errors = new (class extends ComputeNode {
constructor() {
super('atree-render-errors');
this.list_elem = document.getElementById("atree-warning");
}
compute_func(input_map) {
const [hard_error, errors] = input_map.get('atree-errors');
this.list_elem.innerHTML = ""; //reset all atree actives - should be done in a more general way later
// TODO: move to display?
if (errors.length > 0) {
const errorbox = make_elem('div', ['rounded-bottom', 'dark-4', 'border', 'p-0', 'mx-2', 'mb-0', 'mt-4', 'dark-shadow']);
this.list_elem.append(errorbox);
const error_title = make_elem('b', ['warning', 'scaled-font'], { innerHTML: "ATree Error!" });
errorbox.append(error_title);
for (let i = 0; i < 5 && i < errors.length; ++i) {
errorbox.append(make_elem("p", ["warning", "small-text"], {textContent: errors[i]}));
}
if (errors.length > 5) {
const error = '... ' + (errors.length-5) + ' errors not shown';
errorbox.append(make_elem("p", ["warning", "small-text"], {textContent: error}));
}
}
}
})().link_to(atree_validate, 'atree-errors');
/**
* Render ability tree.
* Return map of id -> corresponding html element.
*
* Signature: AbilityTreeRenderActiveNode(atree-merged: MergedATree, atree-order: ATree, atree-errors: List[str]) => Map[int, ATreeNode]
*/
const atree_render_active = new (class extends ComputeNode {
constructor() {
super('atree-render-active');
this.list_elem = document.getElementById("atree-active");
}
compute_func(input_map) {
console.log("boop");
const merged_abils = input_map.get('atree-merged');
const atree_order = input_map.get('atree-order');
this.list_elem.innerHTML = ""; //reset all atree actives - should be done in a more general way later
const ret_map = new Map();
const to_render_id = [999, 998];
for (const node of atree_order) {
if (!merged_abils.has(node.ability.id)) {
continue;
}
to_render_id.push(node.ability.id);
}
for (const id of to_render_id) {
const abil = merged_abils.get(id);
const active_tooltip = make_elem('div', ['rounded-bottom', 'dark-4', 'border', 'p-0', 'mx-2', 'my-4', 'dark-shadow']);
active_tooltip.append(make_elem('b', ['scaled-font'], { innerHTML: abil.display_name }));
for (const desc of abil.desc) {
active_tooltip.append(make_elem('p', ['scaled-font-sm', 'my-0', 'mx-1', 'text-wrap'], { textContent: desc }));
}
ret_map.set(abil.id, active_tooltip);
this.list_elem.append(active_tooltip);
}
return ret_map;
}
})().link_to(atree_node, 'atree-order').link_to(atree_scaling_tree, 'atree-merged');
/**
* Collect spells from abilities.
*
* Signature: AbilityCollectSpellsNode(atree-merged: Map[id, Ability]) => List[Spell]
*/
const atree_collect_spells = new (class extends ComputeNode {
constructor() { super('atree-spell-collector'); }
compute_func(input_map) {
const atree_merged = input_map.get('atree-merged');
/**
* Parse out "parametrized entries".
* Straight replace.
*
* Format: ability_id.propname
*/
function translate(v) {
if (typeof v === 'string') {
const [id_str, propname] = v.split('.');
const id = parseInt(id_str);
const ret = atree_merged.get(id).properties[propname];
return ret;
}
return v;
}
let ret_spells = new Map();
for (const [abil_id, abil] of atree_merged.entries()) {
// TODO: Possibly, make a better way for detecting "spell abilities"?
for (const effect of abil.effects) {
if (effect.type === 'replace_spell') {
// replace_spell just replaces all (defined) aspects.
let ret_spell = ret_spells.get(effect.base_spell);
if (ret_spell) {
// NOTE: do not mutate results of previous steps!
for (const key in effect) {
ret_spell[key] = deepcopy(effect[key]);
}
}
else {
ret_spell = deepcopy(effect);
ret_spells.set(effect.base_spell, ret_spell);
}
for (const part of ret_spell.parts) {
if ('hits' in part) {
for (const idx in part.hits) {
part.hits[idx] = translate(part.hits[idx]);
}
}
}
}
}
}
for (const [abil_id, abil] of atree_merged.entries()) {
for (const effect of abil.effects) {
switch (effect.type) {
case 'replace_spell':
// Already handled above.
continue;
case 'add_spell_prop': {
const { base_spell, target_part = null, cost = 0, behavior = 'merge'} = effect;
const ret_spell = ret_spells.get(base_spell);
// TODO: unjankify this...
if ('cost' in ret_spell) { ret_spell.cost += cost; }
if (target_part === null) {
continue;
}
let found_part = false;
for (let part of ret_spell.parts) { // TODO: replace with Map? to avoid this linear search... idk prolly good since its not more verbose to type in json
if (part.name !== target_part) {
continue;
}
if ('multipliers' in effect) {
for (const [idx, v] of effect.multipliers.entries()) { // python: enumerate()
part.multipliers[idx] += v;
}
}
else if ('power' in effect) {
part.power += effect.power;
}
else if ('hits' in effect) {
for (const [idx, _v] of Object.entries(effect.hits)) { // looks kinda similar to multipliers case... hmm... can we unify all of these three? (make healpower a list)
let v = translate(_v);
if (idx in part.hits) { part.hits[idx] += v; }
else { part.hits[idx] = v; }
}
}
else {
throw "uhh invalid spell add effect";
}
found_part = true;
break;
}
if (!found_part && behavior === 'merge') { // add part. if behavior is merge
let spell_part = deepcopy(effect);
spell_part.name = target_part; // has some extra fields but whatever
if ('hits' in spell_part) {
for (const idx in spell_part.hits) {
spell_part.hits[idx] = translate(spell_part.hits[idx]);
}
}
ret_spell.parts.push(spell_part);
}
if ('display' in effect) {
ret_spell.display = effect.display;
}
continue;
}
case 'convert_spell_conv':
const { base_spell, target_part, conversion } = effect;
const ret_spell = ret_spells.get(base_spell);
const elem_idx = damageClasses.indexOf(conversion);
let filter = target_part === 'all';
for (let part of ret_spell.parts) { // TODO: replace with Map? to avoid this linear search... idk prolly good since its not more verbose to type in json
if (filter || part.name === target_part) {
if ('multipliers' in part) {
let total_conv = 0;
for (let i = 1; i < 6; ++i) { // skip neutral
total_conv += part.multipliers[i];
}
let new_conv = [part.multipliers[0], 0, 0, 0, 0, 0];
new_conv[elem_idx] = total_conv;
part.multipliers = new_conv;
} }
} }
} }
@ -784,18 +867,18 @@ const atree_scaling = new (class extends ComputeNode {
} }
} }
} }
return ret_effects; return ret_spells;
} }
})().link_to(atree_merge, 'atree-merged').link_to(atree_make_interactives, 'atree-interactive'); })().link_to(atree_scaling_tree, 'atree-merged');
/** /**
* Collect stats from ability tree. * Collect raw stats from ability tree.
* Return StatMap of added stats. * Return StatMap of added stats.
* *
* Signature: AbilityTreeStatsNode(atree-merged: MergedATree) => StatMap * Signature: AbilityTreeStatsNode(atree-merged: MergedATree) => StatMap
*/ */
const atree_stats = new (class extends ComputeNode { const atree_raw_stats = new (class extends ComputeNode {
constructor() { super('atree-stats-collector'); } constructor() { super('atree-raw-stats-collector'); }
compute_func(input_map) { compute_func(input_map) {
const atree_merged = input_map.get('atree-merged'); const atree_merged = input_map.get('atree-merged');
@ -1269,11 +1352,11 @@ function atree_set_state(node_wrapper, new_state) {
} }
if (new_state) { if (new_state) {
node_wrapper.active = true; node_wrapper.active = true;
drawAtlasImage(node_wrapper.img, atreeNodeAtlasImg, [atreeNodeAtlasPositions[icon], 2], atreeNodeTileSize); draw_atlas_image(node_wrapper.img, atree_node_atlas_img, [atree_node_atlas_positions[icon], 2], atree_node_tile_size);
} }
else { else {
node_wrapper.active = false; node_wrapper.active = false;
drawAtlasImage(node_wrapper.img, atreeNodeAtlasImg, [atreeNodeAtlasPositions[icon], 1], atreeNodeTileSize); draw_atlas_image(node_wrapper.img, atree_node_atlas_img, [atree_node_atlas_positions[icon], 1], atree_node_tile_size);
} }
let atree_connectors_map = node_wrapper.all_connectors_ref; let atree_connectors_map = node_wrapper.all_connectors_ref;
for (const parent of node_wrapper.parents) { for (const parent of node_wrapper.parents) {
@ -1291,7 +1374,7 @@ function atree_set_state(node_wrapper, new_state) {
// atlas vars // atlas vars
// first key is connector type, second key is highlight, then [x, y] pair of 0-index positions in the tile atlas // first key is connector type, second key is highlight, then [x, y] pair of 0-index positions in the tile atlas
const atreeConnectorAtlasPositions = { const atree_connector_atlas_positions = {
"1100": {"0000": [0, 0], "1100": [1, 0]}, "1100": {"0000": [0, 0], "1100": [1, 0]},
"1010": {"0000": [2, 0], "1010": [3, 0]}, "1010": {"0000": [2, 0], "1010": [3, 0]},
"0110": {"0000": [4, 0], "0110": [5, 0]}, "0110": {"0000": [4, 0], "0110": [5, 0]},
@ -1304,11 +1387,18 @@ const atreeConnectorAtlasPositions = {
"1011": {"0000": [5, 2], "1011": [6, 2], "1010": [7, 2], "1001": [8, 2], "0011": [9, 2]}, "1011": {"0000": [5, 2], "1011": [6, 2], "1010": [7, 2], "1001": [8, 2], "0011": [9, 2]},
"1111": {"0000": [0, 3], "1111": [1, 3], "1110": [2, 3], "1101": [3, 3], "1100": [4, 3], "1011": [5, 3], "1010": [6, 3], "1001": [7, 3], "0111": [8, 3], "0110": [9, 3], "0101": [10, 3], "0011": [11, 3]} "1111": {"0000": [0, 3], "1111": [1, 3], "1110": [2, 3], "1101": [3, 3], "1100": [4, 3], "1011": [5, 3], "1010": [6, 3], "1001": [7, 3], "0111": [8, 3], "0110": [9, 3], "0101": [10, 3], "0011": [11, 3]}
} }
const atreeConnectorTileSize = 18; const atree_connector_tile_size = 18;
const atreeConnectorAtlasImg = make_elem("img", [], {src: "../media/atree/connectors.png"}); const atree_connector_atlas_img = make_elem("img", [], {src: "../media/atree/connectors.png", loaded: false});
atree_connector_atlas_img.addEventListener("load", () => {
atree_connector_atlas_img.loaded = true;
for (const to_draw of atlas_to_draw.get(atree_connector_atlas_img)) {
draw_atlas_image(to_draw[0], atree_connector_atlas_img, to_draw[1], to_draw[2]);
}
atlas_to_draw.set(atree_connector_atlas_img, []);
});
// just has the x position, y is based on state // just has the x position, y is based on state
const atreeNodeAtlasPositions = { const atree_node_atlas_positions = {
"node_0": 0, "node_0": 0,
"node_1": 1, "node_1": 1,
"node_2": 2, "node_2": 2,
@ -1319,13 +1409,27 @@ const atreeNodeAtlasPositions = {
"node_assassin": 7, "node_assassin": 7,
"node_shaman": 8 "node_shaman": 8
} }
const atreeNodeTileSize = 32; const atree_node_tile_size = 32;
const atreeNodeAtlasImg = make_elem("img", [], {src: "../media/atree/icons.png"}); const atree_node_atlas_img = make_elem("img", [], {src: "../media/atree/icons.png", loaded: false});
atree_node_atlas_img.addEventListener("load", () => {
atree_node_atlas_img.loaded = true;
for (const to_draw of atlas_to_draw.get(atree_node_atlas_img)) {
draw_atlas_image(to_draw[0], atree_node_atlas_img, to_draw[1], to_draw[2]);
}
atlas_to_draw.set(atree_node_atlas_img, []);
});
function drawAtlasImage(canvas, img, pos, tileSize) { const atlas_to_draw = new Map();
atlas_to_draw.set(atree_connector_atlas_img, []);
atlas_to_draw.set(atree_node_atlas_img, []);
function draw_atlas_image(canvas, img, pos, tile_size) {
if (!img.loaded) {
atlas_to_draw.get(img).push([canvas, pos, tile_size]);
return;
}
let ctx = canvas.getContext("2d"); let ctx = canvas.getContext("2d");
ctx.clearRect(0, 0, tileSize, tileSize); ctx.clearRect(0, 0, tile_size, tile_size);
ctx.drawImage(img, tileSize * pos[0], tileSize * pos[1], tileSize, tileSize, 0, 0, tileSize, tileSize); ctx.drawImage(img, tile_size * pos[0], tile_size * pos[1], tile_size, tile_size, 0, 0, tile_size, tile_size);
} }
// draw the connector onto the screen // draw the connector onto the screen
@ -1335,7 +1439,7 @@ function atree_render_connection(atree_connectors_map) {
let connector_elem = connector_info.connector; let connector_elem = connector_info.connector;
set_connector_type(connector_info); set_connector_type(connector_info);
connector_info.highlight = [0, 0, 0, 0]; connector_info.highlight = [0, 0, 0, 0];
drawAtlasImage(connector_elem, atreeConnectorAtlasImg, atreeConnectorAtlasPositions[connector_info.type]["0000"], atreeConnectorTileSize); draw_atlas_image(connector_elem, atree_connector_atlas_img, atree_connector_atlas_positions[connector_info.type]["0000"], atree_connector_tile_size);
let target_elem = document.getElementById("atree-row-" + i.split(",")[0]).children[i.split(",")[1]]; let target_elem = document.getElementById("atree-row-" + i.split(",")[0]).children[i.split(",")[1]];
if (target_elem.children.length != 0) { if (target_elem.children.length != 0) {
// janky special case... sometimes the ability tree tries to draw a link on top of a node... // janky special case... sometimes the ability tree tries to draw a link on top of a node...
@ -1387,16 +1491,15 @@ function atree_set_edge(atree_connectors_map, parent, child, state) {
for (let i = 0; i < 4; i++) { for (let i = 0; i < 4; i++) {
render += highlight_state[i] === 0 ? "0" : "1"; render += highlight_state[i] === 0 ? "0" : "1";
} }
drawAtlasImage(connector_elem, atreeConnectorAtlasImg, atreeConnectorAtlasPositions[ctype][render], atreeConnectorTileSize); draw_atlas_image(connector_elem, atree_connector_atlas_img, atree_connector_atlas_positions[ctype][render], atree_connector_tile_size);
// connector_elem.style.backgroundPosition = atlasBGPositionCalc(atreeConnectorAtlasPositions[ctype][render], atreeConnectorAtlasSize);
continue; continue;
} else { } else {
// lol bad overloading, [0] is just the whole state // lol bad overloading, [0] is just the whole state
highlight_state[0] += state_delta; highlight_state[0] += state_delta;
if (highlight_state[0] > 0) { if (highlight_state[0] > 0) {
drawAtlasImage(connector_elem, atreeConnectorAtlasImg, atreeConnectorAtlasPositions[ctype][ctype], atreeConnectorTileSize); draw_atlas_image(connector_elem, atree_connector_atlas_img, atree_connector_atlas_positions[ctype][ctype], atree_connector_tile_size);
} else { } else {
drawAtlasImage(connector_elem, atreeConnectorAtlasImg, atreeConnectorAtlasPositions[ctype]["0000"], atreeConnectorTileSize); draw_atlas_image(connector_elem, atree_connector_atlas_img, atree_connector_atlas_positions[ctype]["0000"], atree_connector_tile_size);
} }
} }
} }

File diff suppressed because it is too large Load diff

File diff suppressed because one or more lines are too long

View file

@ -17,6 +17,8 @@ let armor_powder_node = new (class extends ComputeNode {
} }
})(); })();
const damageMultipliers = new Map([ ["totem", .2], ["warscream", 0.0], ["ragnarokkr", 0.30], ["fortitude", 0.60] ]);
let boosts_node = new (class extends ComputeNode { let boosts_node = new (class extends ComputeNode {
constructor() { super('builder-boost-input'); } constructor() { super('builder-boost-input'); }
@ -601,8 +603,9 @@ class SpellDamageCalcNode extends ComputeNode {
// TODO: move preprocessing to separate node/node chain // TODO: move preprocessing to separate node/node chain
for (const part of spell_parts) { for (const part of spell_parts) {
let spell_result; let spell_result;
const part_id = spell.base_spell + '.' + part.name
if ('multipliers' in part) { // damage type spell if ('multipliers' in part) { // damage type spell
let results = calculateSpellDamage(stats, weapon, part.multipliers, use_spell, !use_speed, spell.base_spell + '.' + part.name); let results = calculateSpellDamage(stats, weapon, part.multipliers, use_spell, !use_speed, part_id);
spell_result = { spell_result = {
type: "damage", type: "damage",
normal_min: results[2].map(x => x[0]), normal_min: results[2].map(x => x[0]),
@ -615,6 +618,9 @@ class SpellDamageCalcNode extends ComputeNode {
} else if ('power' in part) { } else if ('power' in part) {
// TODO: wynn2 formula // TODO: wynn2 formula
let _heal_amount = (part.power * getDefenseStats(stats)[0] * (stats.get('healPct')/100)); let _heal_amount = (part.power * getDefenseStats(stats)[0] * (stats.get('healPct')/100));
if (stats.has('healPct:'+part_id)) {
_heal_amount *= 1+(stats.get('healPct:'+part_id)/100);
}
spell_result = { spell_result = {
type: "heal", type: "heal",
heal_amount: _heal_amount heal_amount: _heal_amount
@ -715,7 +721,7 @@ class BuildDisplayNode extends ComputeNode {
// TODO: move weapon out? // TODO: move weapon out?
// displayDefenseStats(document.getElementById("defensive-stats"), stats); // displayDefenseStats(document.getElementById("defensive-stats"), stats);
displayPoisonDamage(document.getElementById("build-poison-stats"), build); displayPoisonDamage(document.getElementById("build-poison-stats"), stats);
displayEquipOrder(document.getElementById("build-order"), build.equip_order); displayEquipOrder(document.getElementById("build-order"), build.equip_order);
} }
} }
@ -887,6 +893,17 @@ class EditableIDSetterNode extends ComputeNode {
} }
} }
/**
* Overriding this to bridge the transparent gap.
*/
mark_dirty(dirty_state=2) {
super.mark_dirty(dirty_state);
for (const node of this.notify_nodes) {
node.mark_dirty(dirty_state);
}
return this;
}
notify() { notify() {
this.mark_dirty(); this.mark_dirty();
this.update(); this.update();
@ -1065,13 +1082,13 @@ function builder_graph_init() {
// Phase 3/3: Set up atree stuff. // Phase 3/3: Set up atree stuff.
let class_node = new PlayerClassNode('builder-class').link_to(build_node); let class_node = new PlayerClassNode('builder-class').link_to(build_node);
// These two are defined in `atree.js` // These two are defined in `builder/atree.js`
atree_node.link_to(class_node, 'player-class'); atree_node.link_to(class_node, 'player-class');
atree_merge.link_to(class_node, 'player-class'); atree_merge.link_to(class_node, 'player-class');
pre_scale_agg_node.link_to(atree_stats, 'atree-raw-stats'); pre_scale_agg_node.link_to(atree_raw_stats, 'atree-raw-stats');
atree_scaling.link_to(pre_scale_agg_node, 'scale-stats'); atree_scaling.link_to(pre_scale_agg_node, 'scale-stats');
stat_agg_node.link_to(pre_scale_agg_node, 'pre-scaling'); stat_agg_node.link_to(pre_scale_agg_node, 'pre-scaling');
stat_agg_node.link_to(atree_scaling, 'atree-scaling'); stat_agg_node.link_to(atree_scaling_stats, 'atree-scaling');
build_encode_node.link_to(atree_node, 'atree').link_to(atree_state_node, 'atree-state'); build_encode_node.link_to(atree_node, 'atree').link_to(atree_state_node, 'atree-state');

View file

@ -1,6 +1,6 @@
let all_nodes = new Set(); let all_nodes = new Set();
let node_debug_stack = []; let node_debug_stack = [];
let COMPUTE_GRAPH_DEBUG = false; let COMPUTE_GRAPH_DEBUG = true;
class ComputeNode { class ComputeNode {
/** /**
* Make a generic compute node. * Make a generic compute node.
@ -15,7 +15,7 @@ class ComputeNode {
this.value = null; this.value = null;
this.name = name; this.name = name;
this.update_task = null; this.update_task = null;
this.fail_cb = false; // Set to true to force updates even if parent failed. this.fail_cb = false; // Set to true to force updates even if parent failed
this.dirty = 2; // 3 states: this.dirty = 2; // 3 states:
// 2: dirty // 2: dirty
// 1: possibly dirty // 1: possibly dirty
@ -39,6 +39,13 @@ class ComputeNode {
if (this.dirty == 2) { if (this.dirty == 2) {
let calc_inputs = new Map(); let calc_inputs = new Map();
for (const input of this.inputs) { for (const input of this.inputs) {
if (input.dirty) {
if (COMPUTE_GRAPH_DEBUG) {
console.log(node_debug_stack);
console.log(this);
}
throw "Invalid compute graph state!";
}
calc_inputs.set(this.input_translation.get(input.name), input.value); calc_inputs.set(this.input_translation.get(input.name), input.value);
} }
this.value = this.compute_func(calc_inputs); this.value = this.compute_func(calc_inputs);
@ -213,7 +220,7 @@ class PrintNode extends ComputeNode {
* *
* Signature: InputNode() => str * Signature: InputNode() => str
*/ */
class InputNode extends ComputeNode { class InputNode extends ValueCheckComputeNode {
constructor(name, input_field) { constructor(name, input_field) {
super(name); super(name);
this.input_field = input_field; this.input_field = input_field;

View file

@ -188,7 +188,7 @@ function getCustomFromHash(hash) {
/** An object representing a Custom Item. Mostly for vanity purposes. /** An object representing a Custom Item. Mostly for vanity purposes.
* @dep Requires the use of nonRolledIDs and rolledIDs from display_constants.js. * @dep Requires the use of nonRolledIDs and rolledIDs from display_constants.js.
* @dep Requires the use of attackSpeeds from build.js. * @dep Requires the use of attackSpeeds from `builder/build.js`.
*/ */
class Custom { class Custom {
/** /**

View file

@ -2,8 +2,6 @@
* File implementing core damage calculation logic. * File implementing core damage calculation logic.
*/ */
const damageMultipliers = new Map([ ["allytotem", .15], ["yourtotem", .35], ["warscream", 0.00], ["ragnarokkr", 0.30], ["fortitude", 0.60] ]);
function get_base_dps(item) { function get_base_dps(item) {
const attack_speed_mult = baseDamageMultiplier[attackSpeeds.indexOf(item.get("atkSpd"))]; const attack_speed_mult = baseDamageMultiplier[attackSpeeds.indexOf(item.get("atkSpd"))];
//SUPER JANK @HPP PLS FIX //SUPER JANK @HPP PLS FIX
@ -126,15 +124,18 @@ function calculateSpellDamage(stats, weapon, _conversions, use_spell_damage, ign
// These do not count raw damage. I think. Easy enough to change // These do not count raw damage. I think. Easy enough to change
let total_min = 0; let total_min = 0;
let total_max = 0; let total_max = 0;
let save_prop = [];
for (let i in damage_elements) { for (let i in damage_elements) {
save_prop.push(damages[i].slice());
total_min += damages[i][0];
total_max += damages[i][1];
let damage_specific = damage_elements[i] + specific_boost_str + 'Pct'; let damage_specific = damage_elements[i] + specific_boost_str + 'Pct';
let damageBoost = 1 + skill_boost[i] + static_boost let damageBoost = 1 + skill_boost[i] + static_boost
+ ((stats.get(damage_specific) + stats.get(damage_elements[i]+'DamPct')) /100); + ((stats.get(damage_specific) + stats.get(damage_elements[i]+'DamPct')) /100);
damages[i][0] *= Math.max(damageBoost, 0); damages[i][0] *= Math.max(damageBoost, 0);
damages[i][1] *= Math.max(damageBoost, 0); damages[i][1] *= Math.max(damageBoost, 0);
// Collect total damage post %boost // Collect total damage post %boost
total_min += damages[i][0];
total_max += damages[i][1];
} }
let total_elem_min = total_min - damages[0][0]; let total_elem_min = total_min - damages[0][0];
@ -144,6 +145,7 @@ function calculateSpellDamage(stats, weapon, _conversions, use_spell_damage, ign
let prop_raw = stats.get(specific_boost_str.toLowerCase()+'Raw') + stats.get('damRaw'); let prop_raw = stats.get(specific_boost_str.toLowerCase()+'Raw') + stats.get('damRaw');
let rainbow_raw = stats.get('r'+specific_boost_str+'Raw') + stats.get('rDamRaw'); let rainbow_raw = stats.get('r'+specific_boost_str+'Raw') + stats.get('rDamRaw');
for (let i in damages) { for (let i in damages) {
let save_obj = save_prop[i];
let damages_obj = damages[i]; let damages_obj = damages[i];
let damage_prefix = damage_elements[i] + specific_boost_str; let damage_prefix = damage_elements[i] + specific_boost_str;
// Normie raw // Normie raw
@ -157,22 +159,22 @@ function calculateSpellDamage(stats, weapon, _conversions, use_spell_damage, ign
if (total_max > 0) { // TODO: what about total negative all raw? if (total_max > 0) { // TODO: what about total negative all raw?
// TODO: compute actual chance of 0 damage. For now we just copy max ratio // TODO: compute actual chance of 0 damage. For now we just copy max ratio
if (total_min === 0) { if (total_min === 0) {
min_boost += (damages_obj[1] / total_max) * prop_raw; min_boost += (save_obj[1] / total_max) * prop_raw;
} }
else { else {
min_boost += (damages_obj[0] / total_min) * prop_raw; min_boost += (save_obj[0] / total_min) * prop_raw;
} }
max_boost += (damages_obj[1] / total_max) * prop_raw; max_boost += (save_obj[1] / total_max) * prop_raw;
} }
if (i != 0 && total_elem_max > 0) { // rainraw TODO above if (i != 0 && total_elem_max > 0) { // rainraw TODO above
// TODO: compute actual chance of 0 damage. For now we just copy max ratio // TODO: compute actual chance of 0 damage. For now we just copy max ratio
if (total_elem_min === 0) { if (total_elem_min === 0) {
min_boost += (damages_obj[1] / total_elem_max) * rainbow_raw; min_boost += (save_obj[1] / total_elem_max) * rainbow_raw;
} }
else { else {
min_boost += (damages_obj[0] / total_elem_min) * rainbow_raw; min_boost += (save_obj[0] / total_elem_min) * rainbow_raw;
} }
max_boost += (damages_obj[1] / total_elem_max) * rainbow_raw; max_boost += (save_obj[1] / total_elem_max) * rainbow_raw;
} }
damages_obj[0] += min_boost * total_convert; damages_obj[0] += min_boost * total_convert;
damages_obj[1] += max_boost * total_convert; damages_obj[1] += max_boost * total_convert;
@ -256,8 +258,9 @@ spell_heal: {
spell_total: { spell_total: {
name: str != "total" Name of the part. name: str != "total" Name of the part.
type: "total" [TODO: DEPRECATED/REMOVE] flag signaling what type of part it is. Can infer from fields type: "total" [TODO: DEPRECATED/REMOVE] flag signaling what type of part it is. Can infer from fields
hits: Map[str, num] Keys are other part names, numbers are the multipliers. Undefined behavior if subparts hits: Map[str, Union[str, num]] Keys are other part names, numbers are the multipliers. Undefined behavior if subparts
are not the same type of spell. Can only pull from spells defined before it. are not the same type of spell. Can only pull from spells defined before it.
Alternatively, a property reference of the format <ability_id>.propname
} }

View file

@ -72,7 +72,8 @@ function displayBuildStats(parent_id,build,command_group,stats){
let active_elem; let active_elem;
let elemental_format = false; let elemental_format = false;
//TODO this is put here for readability, consolidate with definition in build.js //TODO this is put here for readability, consolidate with definition in `builder/build.js`
// TODO amend: uuhhhhh these two constants have diverged too far...
let staticIDs = ["hp", "eDef", "tDef", "wDef", "fDef", "aDef"]; let staticIDs = ["hp", "eDef", "tDef", "wDef", "fDef", "aDef"];
for (const command of display_commands) { for (const command of display_commands) {
@ -997,9 +998,9 @@ function displayFixedID(active, id, value, elemental_format, style) {
} }
} }
function displayPoisonDamage(overallparent_elem, build) { function displayPoisonDamage(overallparent_elem, statMap) {
overallparent_elem.textContent = ""; overallparent_elem.textContent = "";
if (build.statMap.get('poison') <= 0) { if (statMap.get('poison') <= 0) {
overallparent_elem.style = "display: none"; overallparent_elem.style = "display: none";
return; return;
} }
@ -1013,7 +1014,7 @@ function displayPoisonDamage(overallparent_elem, build) {
title_elemavg.append(make_elem('span', [], { textContent: "Poison Stats" })); title_elemavg.append(make_elem('span', [], { textContent: "Poison Stats" }));
spell_summary.append(title_elemavg); spell_summary.append(title_elemavg);
let poison_tick = Math.ceil(build.statMap.get("poison") * (1+skillPointsToPercentage(build.total_skillpoints[0])) * (build.statMap.get("poisonPct"))/100 /3); let poison_tick = Math.ceil(statMap.get("poison") * (1+skillPointsToPercentage(statMap.get('str'))) * (statMap.get("poisonPct"))/100 /3);
let overallpoisonDamage = make_elem("p"); let overallpoisonDamage = make_elem("p");
overallpoisonDamage.append( overallpoisonDamage.append(
@ -1392,7 +1393,7 @@ function displayPowderSpecials(parent_elem, powderSpecials, stats, weapon, overa
} }
function getSpellCost(stats, spell) { function getSpellCost(stats, spell) {
return Math.max(1, getBaseSpellCost(stats, spell)); return Math.max(1, getBaseSpellCost(stats, spell) * (1 + stats.get('spPct'+spell.base_spell+'Final')/100));
} }
function getBaseSpellCost(stats, spell) { function getBaseSpellCost(stats, spell) {
@ -1521,417 +1522,6 @@ function displaySpellDamage(parent_elem, _overallparent_elem, stats, spell, spel
_overallparent_elem.append(overallparent_elem); _overallparent_elem.append(overallparent_elem);
} }
/** Displays the ID costs of an item
*
* @param {String} elemID - the id of the parent element.
* @param {Map} item - the statMap of an item.
*/
function displayIDCosts(elemID, item) {
let parent_elem = document.getElementById(elemID);
let tier = item.get("tier");
if ( (item.has("fixID") && item.get("fixID")) || ["Normal","Crafted","Custom","none", " ",].includes(item.get("tier"))) {
return;
} else {
/** Returns the number of inventory slots minimum an amount of emeralds would take up + the configuration of doing so.
* Returns an array of [invSpace, E, EB, LE, Stx LE]
*
* @param {number} ems - the total numerical value of emeralds to compact.
*/
function emsToInvSpace(ems) {
let stx = Math.floor(ems/262144);
ems -= stx*4096*64;
let LE = Math.floor(ems/4096);
ems -= LE*4096;
let EB = Math.floor(ems/64);
ems -= EB*64;
let e = ems;
return [ stx + Math.ceil(LE/64) + Math.ceil(EB/64) + Math.ceil(e/64) , e, EB, LE, stx];
}
/**
*
* @param {String} tier - item tier
* @param {Number} lvl - item level
*/
function getIDCost(tier, lvl) {
switch (tier) {
case "Unique":
return Math.round(0.5*lvl + 3);
case "Rare":
return Math.round(1.2*lvl + 8);
case "Legendary":
return Math.round(4.5*lvl + 12);
case "Fabled":
return Math.round(12*lvl + 26);
case "Mythic":
return Math.round(18*lvl + 90);
case "Set":
return Math.round(1.5*lvl + 8)
default:
return -1;
}
}
parent_elem.style = "display: visible";
let lvl = item.get("lvl");
if (typeof(lvl) === "string") { lvl = parseFloat(lvl); }
let title_elem = document.createElement("p");
title_elem.classList.add("smalltitle");
title_elem.style.color = "white";
title_elem.textContent = "Identification Costs";
parent_elem.appendChild(title_elem);
parent_elem.appendChild(document.createElement("br"));
let grid_item = document.createElement("div");
grid_item.style.display = "flex";
grid_item.style.flexDirection = "rows";
grid_item.style.flexWrap = "wrap";
grid_item.style.gap = "5px";
parent_elem.appendChild(grid_item);
let IDcost = getIDCost(tier, lvl);
let initIDcost = IDcost;
let invSpace = emsToInvSpace(IDcost);
let rerolls = 0;
while(invSpace[0] <= 28 && IDcost > 0) {
let container = document.createElement("div");
container.classList.add("container");
container.style = "grid-item-" + (rerolls+1);
container.style.maxWidth = "max(120px, 15%)";
let container_title = document.createElement("p");
container_title.style.color = "white";
if (rerolls == 0) {
container_title.textContent = "Initial ID Cost: ";
} else {
container_title.textContent = "Reroll to [" + (rerolls+1) + "] Cost:";
}
container.appendChild(container_title);
let total_cost_container = document.createElement("p");
let total_cost_number = document.createElement("b");
total_cost_number.classList.add("Set");
total_cost_number.textContent = IDcost + " ";
let total_cost_suffix = document.createElement("b");
total_cost_suffix.textContent = "emeralds."
total_cost_container.appendChild(total_cost_number);
total_cost_container.appendChild(total_cost_suffix);
container.appendChild(total_cost_container);
let OR = document.createElement("p");
OR.classList.add("center");
OR.textContent = "OR";
container.appendChild(OR);
let esuffixes = ["", "emeralds.", "EB.", "LE.", "stacks of LE."];
for (let i = 4; i > 0; i--) {
let n_container = document.createElement("p");
let n_number = document.createElement("b");
n_number.classList.add("Set");
n_number.textContent = invSpace[i] + " ";
let n_suffix = document.createElement("b");
n_suffix.textContent = esuffixes[i];
n_container.appendChild(n_number);
n_container.appendChild(n_suffix);
container.appendChild(n_container);
}
grid_item.appendChild(container);
rerolls += 1;
IDcost = Math.round(initIDcost * (5 ** rerolls));
invSpace = emsToInvSpace(IDcost);
}
}
}
/** Displays Additional Info for
*
* @param {String} elemID - the parent element's id
* @param {Map} item - the statMap of the item
* @returns
*/
function displayAdditionalInfo(elemID, item) {
let parent_elem = document.getElementById(elemID);
parent_elem.classList.add("left");
let droptype_elem = document.createElement("div");
droptype_elem.classList.add("container");
droptype_elem.style.marginBottom = "5px";
droptype_elem.textContent = "Drop type: " + (item.has("drop") ? item.get("drop"): "NEVER");
parent_elem.appendChild(droptype_elem);
let warning_elem = document.createElement("div");
warning_elem.classList.add("container");
warning_elem.style.marginBottom ="5px";
warning_elem.textContent = "This page is incomplete. Will work on it later.";
parent_elem.appendChild(warning_elem);
return;
}
/** Displays the individual probabilities of each possible value of each rollable ID for this item.
*
* @param {String} parent_id the document id of the parent element
* @param {String} item expandedItem object
* @param {String} amp the level of corkian amplifier used. 0 means no amp, 1 means Corkian Amplifier I, etc. [0,3]
*/
function displayIDProbabilities(parent_id, item, amp) {
if (item.has("fixID") && item.get("fixID")) {return}
let parent_elem = document.getElementById(parent_id);
parent_elem.style.display = "";
parent_elem.innerHTML = "";
let title_elem = document.createElement("p");
title_elem.textContent = "Identification Probabilities";
title_elem.id = "ID_PROB_TITLE";
title_elem.classList.add("Legendary");
title_elem.classList.add("title");
parent_elem.appendChild(title_elem);
let disclaimer_elem = document.createElement("p");
disclaimer_elem.textContent = "IDs are rolled on a uniform distribution. A chance of 0% means that either the minimum or maximum possible multiplier must be rolled to get this value."
parent_elem.appendChild(disclaimer_elem);
let amp_row = document.createElement("p");
amp_row.id = "amp_row";
let amp_text = document.createElement("b");
amp_text.textContent = "Corkian Amplifier Used: "
amp_row.appendChild(amp_text);
let amp_1 = document.createElement("button");
amp_1.id = "cork_amp_1";
amp_1.textContent = "I";
amp_row.appendChild(amp_1);
let amp_2 = document.createElement("button");
amp_2.id = "cork_amp_2";
amp_2.textContent = "II";
amp_row.appendChild(amp_2);
let amp_3 = document.createElement("button");
amp_3.id = "cork_amp_3";
amp_3.textContent = "III";
amp_row.appendChild(amp_3);
amp_1.addEventListener("click", (event) => {toggleAmps(1)});
amp_2.addEventListener("click", (event) => {toggleAmps(2)});
amp_3.addEventListener("click", (event) => {toggleAmps(3)});
parent_elem.appendChild(amp_row);
if (amp != 0) {toggleButton("cork_amp_" + amp)}
let item_name = item.get("displayName");
console.log(itemMap.get(item_name))
let table_elem = document.createElement("table");
parent_elem.appendChild(table_elem);
for (const [id,val] of Object.entries(itemMap.get(item_name))) {
if (rolledIDs.includes(id)) {
if (!item.get("maxRolls").get(id)) { continue; }
let min = item.get("minRolls").get(id);
let max = item.get("maxRolls").get(id);
//Apply corkian amps
if (val > 0) {
let base = itemMap.get(item_name)[id];
if (reversedIDs.includes(id)) {max = Math.max( Math.round((0.3 + 0.05*amp) * base), 1)}
else {min = Math.max( Math.round((0.3 + 0.05*amp) * base), 1)}
}
let row_title = document.createElement("tr");
//row_title.style.textAlign = "left";
let title_left = document.createElement("td");
let left_elem = document.createElement("p");
let left_val_title = document.createElement("b");
let left_val_elem = document.createElement("b");
title_left.style.textAlign = "left";
left_val_title.textContent = idPrefixes[id] + "Base ";
left_val_elem.textContent = val + idSuffixes[id];
if (val > 0 == !reversedIDs.includes(id)) {
left_val_elem.classList.add("positive");
} else if (val > 0 == reversedIDs.includes(id)) {
left_val_elem.classList.add("negative");
}
left_elem.appendChild(left_val_title);
left_elem.appendChild(left_val_elem);
title_left.appendChild(left_elem);
row_title.appendChild(title_left);
let title_right = document.createElement("td");
let title_right_text = document.createElement("b");
title_right.style.textAlign = "left";
title_right_text.textContent = "[ " + min + idSuffixes[id] + ", " + max + idSuffixes[id] + " ]";
if ( (min > 0 && max > 0 && !reversedIDs.includes(id)) || (min < 0 && max < 0 && reversedIDs.includes(id)) ) {
title_right_text.classList.add("positive");
} else if ( (min < 0 && max < 0 && !reversedIDs.includes(id)) || (min > 0 && max > 0 && reversedIDs.includes(id)) ) {
title_right_text.classList.add("negative");
}
title_right.appendChild(title_right_text);
let title_input = document.createElement("td");
let title_input_slider = document.createElement("input");
title_input_slider.type = "range";
title_input_slider.id = id+"-slider";
if (!reversedIDs.includes(id)) {
title_input_slider.step = 1;
title_input_slider.min = `${min}`;
title_input_slider.max = `${max}`;
title_input_slider.value = `${max}`;
} else {
title_input_slider.step = 1;
title_input_slider.min = `${-1*min}`;
title_input_slider.max = `${-1*max}`;
title_input_slider.value = `${-1*max}`;
}
let title_input_textbox = document.createElement("input");
title_input_textbox.type = "text";
title_input_textbox.value = `${max}`;
title_input_textbox.id = id+"-textbox";
title_input_textbox.classList.add("small-input");
title_input.appendChild(title_input_slider);
title_input.appendChild(title_input_textbox);
row_title.appendChild(title_left);
row_title.appendChild(title_right);
row_title.appendChild(title_input);
let row_chances = document.createElement("tr");
let chance_cdf = document.createElement("td");
let chance_pdf = document.createElement("td");
let cdf_p = document.createElement("p");
cdf_p.id = id+"-cdf";
let pdf_p = document.createElement("p");
pdf_p.id = id+"-pdf";
chance_cdf.appendChild(cdf_p);
chance_pdf.appendChild(pdf_p);
row_chances.appendChild(chance_cdf);
row_chances.appendChild(chance_pdf);
table_elem.appendChild(row_title);
table_elem.appendChild(row_chances);
stringPDF(id, max, val, amp); //val is base roll
stringCDF(id, max, val, amp); //val is base roll
title_input_slider.addEventListener("change", (event) => {
let id_name = event.target.id.split("-")[0];
let textbox_elem = document.getElementById(id_name+"-textbox");
if (reversedIDs.includes(id_name)) {
if (event.target.value < -1*min) { event.target.value = -1*min}
if (event.target.value > -1*max) { event.target.value = -1*max}
stringPDF(id_name, -1*event.target.value, val, amp); //val is base roll
stringCDF(id_name, -1*event.target.value, val, amp); //val is base roll
} else {
if (event.target.value < min) { event.target.value = min}
if (event.target.value > max) { event.target.value = max}
stringPDF(id_name, 1*event.target.value, val, amp); //val is base roll
stringCDF(id_name, 1*event.target.value, val, amp); //val is base roll
}
if (textbox_elem && textbox_elem.value !== event.target.value) {
if (reversedIDs.includes(id_name)) {
textbox_elem.value = -event.target.value;
} else {
textbox_elem.value = event.target.value;
}
}
});
title_input_textbox.addEventListener("change", (event) => {
let id_name = event.target.id.split("-")[0];
if (reversedIDs.includes(id_name)) {
if (event.target.value > min) { event.target.value = min}
if (event.target.value < max) { event.target.value = max}
} else {
if (event.target.value < min) { event.target.value = min}
if (event.target.value > max) { event.target.value = max}
}
let slider_elem = document.getElementById(id_name+"-slider");
if (slider_elem.value !== event.target.value) {
slider_elem.value = -event.target.value;
}
stringPDF(id_name, 1*event.target.value, val, amp);
stringCDF(id_name, 1*event.target.value, val, amp);
});
}
}
}
//helper functions. id - the string of the id's name, val - the value of the id, base - the base value of the item for this id
function stringPDF(id,val,base,amp) {
/** [0.3b,1.3b] positive normal
* [1.3b,0.3b] positive reversed
* [1.3b,0.7b] negative normal
* [0.7b,1.3b] negative reversed
*
* [0.3, 1.3] minr, maxr [0.3b, 1.3b] min, max
* the minr/maxr decimal roll that corresponds to val -> minround, maxround
*/
let p; let min; let max; let minr; let maxr; let minround; let maxround;
if (base > 0) {
minr = 0.3 + 0.05*amp; maxr = 1.3;
min = Math.max(1, Math.round(minr*base)); max = Math.max(1, Math.round(maxr*base));
minround = (min == max) ? (minr) : ( Math.max(minr, (val-0.5) / base) );
maxround = (min == max) ? (maxr) : ( Math.min(maxr, (val+0.5) / base) );
} else {
minr = 1.3; maxr = 0.7;
min = Math.min(-1, Math.round(minr*base)); max = Math.min(-1, Math.round(maxr*base));
minround = (min == max) ? (minr) : ( Math.min(minr, (val-0.5) / base) );
maxround = (min == max) ? (maxr) : ( Math.max(maxr, (val+0.5) / base) );
}
p = Math.abs(maxround-minround)/Math.abs(maxr-minr)*100;
p = p.toFixed(3);
let b1 = document.createElement("b");
b1.textContent = "Roll exactly ";
let b2 = document.createElement("b");
b2.textContent = val + idSuffixes[id];
if (val > 0 == !reversedIDs.includes(id)) {b2.classList.add("positive")}
if (val > 0 == reversedIDs.includes(id)) {b2.classList.add("negative")}
let b3 = document.createElement("b");
b3.textContent = ": " + p + "%";
document.getElementById(id + "-pdf").innerHTML = "";
document.getElementById(id + "-pdf").appendChild(b1);
document.getElementById(id + "-pdf").appendChild(b2);
document.getElementById(id + "-pdf").appendChild(b3);
}
function stringCDF(id,val,base,amp) {
let p; let min; let max; let minr; let maxr; let minround; let maxround;
if (base > 0) {
minr = 0.3 + 0.05*amp; maxr = 1.3;
min = Math.max(1, Math.round(minr*base)); max = Math.max(1, Math.round(maxr*base));
minround = (min == max) ? (minr) : ( Math.max(minr, (val-0.5) / base) );
maxround = (min == max) ? (maxr) : ( Math.min(maxr, (val+0.5) / base) );
} else {
minr = 1.3; maxr = 0.7;
min = Math.min(-1, Math.round(minr*base)); max = Math.min(-1, Math.round(maxr*base));
minround = (min == max) ? (minr) : ( Math.min(minr, (val-0.5) / base) );
maxround = (min == max) ? (maxr) : ( Math.max(maxr, (val+0.5) / base) );
}
if (reversedIDs.includes(id)) {
p = Math.abs(minr-maxround)/Math.abs(maxr-minr)*100;
} else {
p = Math.abs(maxr-minround)/Math.abs(maxr-minr)*100;
}
p = p.toFixed(3);
let b1 = document.createElement("b");
b1.textContent = "Roll ";
let b2 = document.createElement("b");
b2.textContent = val + idSuffixes[id];
if (val > 0 == !reversedIDs.includes(id)) {b2.classList.add("positive")}
if (val > 0 == reversedIDs.includes(id)) {b2.classList.add("negative")}
let b3 = document.createElement("b");
b3.textContent= " or better: " + p + "%";
document.getElementById(id + "-cdf").innerHTML = "";
document.getElementById(id + "-cdf").appendChild(b1);
document.getElementById(id + "-cdf").appendChild(b2);
document.getElementById(id + "-cdf").appendChild(b3);
}
function addClickableArrow(elem, target) { function addClickableArrow(elem, target) {
//up and down arrow - done ugly //up and down arrow - done ugly
let arrow = make_elem("img", [], { id: "arrow_" + elem.id, src: "../media/icons/" + (newIcons ? "new" : "old") + "/toggle_down.png" }); let arrow = make_elem("img", [], { id: "arrow_" + elem.id, src: "../media/icons/" + (newIcons ? "new" : "old") + "/toggle_down.png" });

View file

@ -40,6 +40,11 @@ let idPrefixes = {"displayName": "",
"hprRaw":"Health Regen Raw: ", "hprRaw":"Health Regen Raw: ",
"hprPct":"Health Regen %: ", "hprPct":"Health Regen %: ",
"sdRaw":"Raw Spell Damage: ", "sdRaw":"Raw Spell Damage: ",
"eSdRaw":"Raw Earth Spell Damage: ",
"tSdRaw":"Raw Thunder Spell Damage: ",
"wSdRaw":"Raw Water Spell Damage: ",
"fSdRaw":"Raw Fire Spell Damage: ",
"aSdRaw":"Raw Air Spell Damage: ",
"sdPct":"Spell Damage %: ", "sdPct":"Spell Damage %: ",
"mdRaw":"Raw Melee Damage: ", "mdRaw":"Raw Melee Damage: ",
"mdPct":"Melee Damage %: ", "mdPct":"Melee Damage %: ",
@ -70,7 +75,7 @@ let idPrefixes = {"displayName": "",
"spRaw3":"3rd Spell Cost Raw: ", "spRaw3":"3rd Spell Cost Raw: ",
"spPct4":"4th Spell Cost %: ", "spPct4":"4th Spell Cost %: ",
"spRaw4":"4th Spell Cost Raw: ", "spRaw4":"4th Spell Cost Raw: ",
"rainbowRaw":"Rainbow Spell Damage Raw: ", "rSdRaw":"Rainbow Spell Damage Raw: ",
"sprint":"Sprint Bonus: ", "sprint":"Sprint Bonus: ",
"sprintReg":"Sprint Regen Bonus: ", "sprintReg":"Sprint Regen Bonus: ",
"jh":"Jump Height: ", "jh":"Jump Height: ",
@ -117,6 +122,11 @@ let idSuffixes = {"displayName": "",
"hprRaw":"", "hprRaw":"",
"hprPct":"%", "hprPct":"%",
"sdRaw":"", "sdRaw":"",
"eSdRaw":"",
"tSdRaw":"",
"wSdRaw":"",
"fSdRaw":"",
"aSdRaw":"",
"sdPct":"%", "sdPct":"%",
"mdRaw":"", "mdRaw":"",
"mdPct":"%", "mdPct":"%",
@ -309,7 +319,8 @@ let sq2_item_display_commands = [
"str", "dex", "int", "def", "agi", "str", "dex", "int", "def", "agi",
"hpBonus", "hpBonus",
"hprRaw", "hprPct", "hprRaw", "hprPct",
"sdRaw", "sdPct", "sdRaw", "eSdRaw", "tSdRaw", "wSdRaw", "fSdRaw", "aSdRaw",
"sdPct",
"mdRaw", "mdPct", "mdRaw", "mdPct",
"mr", "ms", "mr", "ms",
"ref", "thorns", "ref", "thorns",
@ -323,7 +334,7 @@ let sq2_item_display_commands = [
"fDefPct", "wDefPct", "aDefPct", "tDefPct", "eDefPct", "fDefPct", "wDefPct", "aDefPct", "tDefPct", "eDefPct",
"!elemental", "!elemental",
"spPct1", "spRaw1", "spPct2", "spRaw2", "spPct3", "spRaw3", "spPct4", "spRaw4", "spPct1", "spRaw1", "spPct2", "spRaw2", "spPct3", "spRaw3", "spPct4", "spRaw4",
"rainbowRaw", "rSdRaw",
"sprint", "sprintReg", "sprint", "sprintReg",
"jh", "jh",
"xpb", "lb", "lq", "xpb", "lb", "lq",

View file

@ -234,7 +234,7 @@ function stringify(v) {
return typeof v === 'number' ? (Math.round(v * 100) / 100).toString() : v; return typeof v === 'number' ? (Math.round(v * 100) / 100).toString() : v;
} }
function init_items2() { function init_items_adv() {
const itemList = document.getElementById('item-list'); const itemList = document.getElementById('item-list');
const itemListFooter = document.getElementById('item-list-footer'); const itemListFooter = document.getElementById('item-list-footer');
@ -328,7 +328,11 @@ function init_items2() {
for (let i = 0; i < searchMax; i++) { for (let i = 0; i < searchMax; i++) {
const result = searchResults[i]; const result = searchResults[i];
itemEntries[i].classList.add('visible'); itemEntries[i].classList.add('visible');
displaysq2ExpandedItem(result.itemExp, `item-entry-${i}`); result.itemExp.set("powders", []);
if (result.itemExp.get("category") == "weapon") {
apply_weapon_powders(result.itemExp);
}
displayExpandedItem(result.itemExp, `item-entry-${i}`);
if (result.sortKeys.length > 0) { if (result.sortKeys.length > 0) {
const sortKeyListContainer = document.createElement('div'); const sortKeyListContainer = document.createElement('div');
sortKeyListContainer.classList.add('row'); sortKeyListContainer.classList.add('row');
@ -391,4 +395,7 @@ function init_items2() {
.addEventListener('mousedown', e => scrollTo({ top: 0, behavior: 'smooth' })); .addEventListener('mousedown', e => scrollTo({ top: 0, behavior: 'smooth' }));
} }
load_init(init_items2); (async function() {
await Promise.resolve(load_init());
init_items_adv();
})();

View file

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

View file

@ -39,7 +39,25 @@ def translate_id(id_data, atree_data):
for bonus in effect["bonuses"]: for bonus in effect["bonuses"]:
if "abil" in bonus and bonus["abil"] in id_data[_class]: if "abil" in bonus and bonus["abil"] in id_data[_class]:
bonus["abil"] = id_data[_class][bonus["abil"]] bonus["abil"] = id_data[_class][bonus["abil"]]
elif effect["type"] == "replace_spell":
for part in effect['parts']:
if 'hits' in part: # Translate parametrized hits...
hits_mapping = part['hits']
keys = list(hits_mapping.keys())
for k in keys:
v = hits_mapping[k]
if isinstance(v, str):
abil_id, propname = v.split('.')
hits_mapping[k] = str(id_data[_class][abil_id])+'.'+propname
elif effect["type"] == "add_spell_prop":
if 'hits' in effect: # Translate parametrized hits...
hits_mapping = effect['hits']
keys = list(hits_mapping.keys())
for k in keys:
v = hits_mapping[k]
if isinstance(v, str):
abil_id, propname = v.split('.')
hits_mapping[k] = str(id_data[_class][abil_id])+'.'+propname
elif effect["type"] == "stat_scaling": elif effect["type"] == "stat_scaling":
if "inputs" in effect: # Might not exist for sliders if "inputs" in effect: # Might not exist for sliders
for _input in effect["inputs"]: for _input in effect["inputs"]:

View file

@ -18,7 +18,7 @@
"category": "armor", "category": "armor",
"displayName": "Keratoconus", "displayName": "Keratoconus",
"bonusThunderDamage": -40, "bonusThunderDamage": -40,
"bonusWaterDamage": 30, "bonusWaterDefense": 30,
"bonusAirDamage": 35, "bonusAirDamage": 35,
"healthRegen": -50, "healthRegen": -50,
"manaRegen": 10, "manaRegen": 10,
@ -67,7 +67,7 @@
"bonusEarthDamage": 24, "bonusEarthDamage": 24,
"bonusAirDamage": 32, "bonusAirDamage": 32,
"attackSpeedBonus": -1, "attackSpeedBonus": -1,
"manaRegen": 8, "manaRegen": 10,
"reflection": 48, "reflection": 48,
"spellCostRaw1": -3, "spellCostRaw1": -3,
"identified": false, "identified": false,
@ -967,7 +967,6 @@
"spellDamage": 400, "spellDamage": 400,
"manaSteal": 30, "manaSteal": 30,
"reflection": 20, "reflection": 20,
"spellCostRaw3": 6,
"xpBonus": 30, "xpBonus": 30,
"identified": false "identified": false
}, },
@ -2323,7 +2322,7 @@
"bonusAirDefense": 20, "bonusAirDefense": 20,
"speed": 30, "speed": 30,
"sprint": 15, "sprint": 15,
"spellCostRaw1": -5, "spellCostRaw1": -3,
"xpBonus": 10, "xpBonus": 10,
"identified": true "identified": true
}, },
@ -2942,7 +2941,7 @@
{"name":"Infused Hive Relik","type":"relik","level":100,"tier":"Legendary","sockets":5,"majorIds":[],"quest":"The Qira Hive","damage":"260-290","earthDamage":"0-0","thunderDamage":"0-0","waterDamage":"0-0","fireDamage":"0-0","airDamage":"0-0","attackSpeed":"FAST","category":"weapon","displayName":"Infused Hive Relik","bonusEarthDamage":20,"bonusThunderDamage":20,"bonusWaterDamage":20,"bonusFireDamage":20,"bonusAirDamage":20,"manaRegen":5,"manaSteal":5,"identified":true}, {"name":"Infused Hive Relik","type":"relik","level":100,"tier":"Legendary","sockets":5,"majorIds":[],"quest":"The Qira Hive","damage":"260-290","earthDamage":"0-0","thunderDamage":"0-0","waterDamage":"0-0","fireDamage":"0-0","airDamage":"0-0","attackSpeed":"FAST","category":"weapon","displayName":"Infused Hive Relik","bonusEarthDamage":20,"bonusThunderDamage":20,"bonusWaterDamage":20,"bonusFireDamage":20,"bonusAirDamage":20,"manaRegen":5,"manaSteal":5,"identified":true},
{"name":"Tragedy","type":"wand","level":74,"tier":"Rare","sockets":2,"majorIds":[],"intelligence":25,"strengthPoints":-10,"damage":"50-65","earthDamage":"0-0","thunderDamage":"0-0","waterDamage":"40-85","fireDamage":"0-0","airDamage":"0-0","attackSpeed":"NORMAL","category":"weapon","displayName":"Tragedy","bonusWaterDamage":50,"healthBonus":-100,"manaRegen":-5,"manaSteal":-5,"identified":true}, {"name":"Tragedy","type":"wand","level":74,"tier":"Rare","sockets":2,"majorIds":[],"intelligence":25,"strengthPoints":-10,"damage":"50-65","earthDamage":"0-0","thunderDamage":"0-0","waterDamage":"40-85","fireDamage":"0-0","airDamage":"0-0","attackSpeed":"NORMAL","category":"weapon","displayName":"Tragedy","bonusWaterDamage":50,"healthBonus":-100,"manaRegen":-5,"manaSteal":-5,"identified":true},
{"name":"Scytodidae","type":"bow","level":77,"tier":"Rare","sockets":2,"majorIds":[],"intelligence":40,"defensePoints":-20,"damage":"180-230","earthDamage":"0-0","thunderDamage":"0-0","waterDamage":"130-175","fireDamage":"0-0","airDamage":"0-0","attackSpeed":"SLOW","category":"weapon","displayName":"Scytodidae","spellDamageRaw":130,"bonusFireDefense":-10,"manaRegen":10,"manaSteal":10,"identified":true}, {"name":"Scytodidae","type":"bow","level":77,"tier":"Rare","sockets":2,"majorIds":[],"intelligence":40,"defensePoints":-20,"damage":"180-230","earthDamage":"0-0","thunderDamage":"0-0","waterDamage":"130-175","fireDamage":"0-0","airDamage":"0-0","attackSpeed":"SLOW","category":"weapon","displayName":"Scytodidae","spellDamageRaw":130,"bonusFireDefense":-10,"manaRegen":10,"manaSteal":10,"identified":true},
{"name":"Hard Light","type":"relik","level":96,"tier":"Rare","sockets":3,"majorIds":[],"strength":23,"dexterity":23,"intelligence":23,"defense":23,"agility":23,"strengthPoints":17,"dexterityPoints":17,"intelligencePoints":17,"defensePoints":17,"agilityPoints":17,"damage":"0-0","earthDamage":"51-57","thunderDamage":"51-57","waterDamage":"51-57","fireDamage":"51-57","airDamage":"51-57","attackSpeed":"FAST","category":"weapon","displayName":"Hard Light","damageBonus":15,"spellDamage":15,"bonusEarthDefense":-25,"bonusThunderDefense":-25,"bonusWaterDefense":-25,"bonusFireDefense":-25,"bonusAirDefense":-25,"manaRegen":5,"manaSteal":5,"identified":false}, {"name":"Hard Light","type":"relik","level":96,"tier":"Rare","sockets":3,"majorIds":[],"strength":23,"dexterity":23,"intelligence":23,"defense":23,"agility":23,"strengthPoints":17,"dexterityPoints":17,"intelligencePoints":17,"defensePoints":17,"agilityPoints":17,"damage":"0-0","earthDamage":"51-57","thunderDamage":"51-57","waterDamage":"51-57","fireDamage":"51-57","airDamage":"51-57","attackSpeed":"FAST","category":"weapon","displayName":"Hard Light","damageBonus":15,"spellDamage":15,"bonusEarthDefense":-25,"bonusThunderDefense":-25,"bonusWaterDefense":-25,"bonusFireDefense":-25,"bonusAirDefense":-25,"manaRegen":9,"manaSteal":9,"identified":false},
{"name":"Boreal-Patterned Aegis","type":"chestplate","level":100,"tier":"Legendary","sockets":2,"majorIds":[],"quest":"The Qira Hive","dexterity":40,"intelligence":40,"defense":40,"strengthPoints":-30,"agilityPoints":-30,"health":3800,"thunderDefense":200,"waterDefense":200,"fireDefense":200,"category":"armor","displayName":"Anima-Infused Cuirass","bonusThunderDamage":20,"bonusWaterDamage":20,"bonusFireDamage":20,"bonusThunderDefense":15,"bonusWaterDefense":15,"bonusFireDefense":15,"manaRegen":10,"spellCostRaw1":-5,"spellCostRaw3":-5,"spellCostRaw4":-5,"identified":true} {"name":"Boreal-Patterned Aegis","type":"chestplate","level":100,"tier":"Legendary","sockets":2,"majorIds":[],"quest":"The Qira Hive","dexterity":40,"intelligence":40,"defense":40,"strengthPoints":-30,"agilityPoints":-30,"health":3800,"thunderDefense":200,"waterDefense":200,"fireDefense":200,"category":"armor","displayName":"Anima-Infused Cuirass","bonusThunderDamage":20,"bonusWaterDamage":20,"bonusFireDamage":20,"bonusThunderDefense":15,"bonusWaterDefense":15,"bonusFireDefense":15,"manaRegen":10,"spellCostRaw1":-5,"spellCostRaw3":-5,"spellCostRaw4":-5,"identified":true, "set": "Master Hive"}
] ]
} }

View file

@ -79,8 +79,6 @@ for item in old_items:
if rem >= 5: if rem >= 5:
val += 1 val += 1
item[k] = val item[k] = val
if item['name'] == "Gale's Sight":
print(item)
items.append(item) items.append(item)
#print(f'Unknown old item: {item["name"]}!!!') #print(f'Unknown old item: {item["name"]}!!!')
#old_items_map[item["name"]] = item #old_items_map[item["name"]] = item