merge conflict
17
README.md
|
@ -1,7 +1,7 @@
|
||||||
# WynnBuilder
|
# WynnBuilder
|
||||||
Wynncraft class building calculator & general utility site
|
Wynncraft class building calculator & general utility site
|
||||||
|
|
||||||
![builder screenshot](https://user-images.githubusercontent.com/16601189/111013491-9cc8a080-836d-11eb-86fc-2e6413d0e493.png)
|
![Builder Screenshot](https://user-images.githubusercontent.com/110062564/192047798-d8583fe1-b188-4bc4-85a9-0eecbf10aeef.PNG)
|
||||||
|
|
||||||
## Features
|
## Features
|
||||||
|
|
||||||
|
@ -14,6 +14,9 @@ Takes a build's items as input and returns all relevant information
|
||||||
- Skillpoints required & left over
|
- Skillpoints required & left over
|
||||||
- Defensive stats (EHP, EleDefs, etc.)
|
- Defensive stats (EHP, EleDefs, etc.)
|
||||||
|
|
||||||
|
It also features an ability tree!
|
||||||
|
![wynnbuilder ability tree](https://user-images.githubusercontent.com/110062564/192048561-2ec91ba7-1793-4d4f-b4d5-6d7c05cfae99.PNG)
|
||||||
|
|
||||||
Boosts and Powder specials
|
Boosts and Powder specials
|
||||||
- Spell boosts, such as Vanish and War Scream
|
- Spell boosts, such as Vanish and War Scream
|
||||||
- Powder special buffs
|
- Powder special buffs
|
||||||
|
@ -22,12 +25,18 @@ Boosts and Powder specials
|
||||||
and more...
|
and more...
|
||||||
|
|
||||||
### WynnCrafter
|
### WynnCrafter
|
||||||
|
![wynncrafter screenshot](https://user-images.githubusercontent.com/110062564/192048366-5112d334-f44b-4853-b337-4184628e505e.PNG)
|
||||||
Crafting recipe calculator
|
Crafting recipe calculator
|
||||||
|
|
||||||
### WynnAtlas
|
|
||||||
|
|
||||||
Fully featured item search
|
### WynnAtlas
|
||||||
|
![wynnatlas screenshot](https://user-images.githubusercontent.com/110062564/192048258-23bc0dd7-b417-4c0c-9437-4392315bf85d.PNG)
|
||||||
|
Fully featured item search!
|
||||||
|
Use different filters based on:
|
||||||
|
- Name
|
||||||
|
- Rarity
|
||||||
|
- IDs
|
||||||
|
And more, to find what item suits your build best!
|
||||||
|
|
||||||
### WynnCustom
|
### WynnCustom
|
||||||
|
|
||||||
|
|
230
builder/doc.html
|
@ -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">
|
||||||
|
<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 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 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 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">
|
||||||
|
@ -127,10 +177,10 @@
|
||||||
</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 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">
|
||||||
|
@ -153,10 +203,10 @@
|
||||||
</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 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">
|
||||||
|
@ -180,10 +230,10 @@
|
||||||
</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 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">
|
||||||
|
@ -207,10 +257,10 @@
|
||||||
</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 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">
|
||||||
|
@ -234,10 +284,10 @@
|
||||||
</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 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">
|
||||||
|
@ -260,10 +310,10 @@
|
||||||
</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 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 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,8 +457,8 @@
|
||||||
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')">
|
<button class="button-boost m-1 border-0 text-white dark-8u dark-shadow-sm" id="radiance-boost" onclick="update_radiance()">
|
||||||
Vanish (+80%)
|
Radiance
|
||||||
</button>
|
</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
|
||||||
|
@ -425,11 +466,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%)
|
||||||
|
@ -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,12 +831,14 @@
|
||||||
</div>
|
</div>
|
||||||
<div class = "col dark-6 rounded-bottom my-3 my-xl-1" id = "atree-dropdown" style = "display:none;">
|
<div class = "col dark-6 rounded-bottom my-3 my-xl-1" id = "atree-dropdown" style = "display:none;">
|
||||||
<div class="row row-cols-1 row-cols-xl-2">
|
<div class="row row-cols-1 row-cols-xl-2">
|
||||||
<div class="col border border-semi-light rounded dark-9 hide-scroll" id="atree-ui" style="height: 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">
|
||||||
<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>
|
||||||
|
@ -1131,24 +1175,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">
|
||||||
|
@ -1262,13 +1302,11 @@
|
||||||
<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/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 +1314,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>
|
||||||
|
|
||||||
<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>
|
||||||
|
|
|
@ -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%;">
|
<div id="mobile-navbar" class="navbar dark-5 dark-shadow fixed-top d-lg-none pb-0">
|
||||||
|
<div class="container-fluid scaled-font justify-content-center" style="height: 5vh;">
|
||||||
|
<div class="navbar-brand mx-auto scaled-font" style="height: 100%;">
|
||||||
|
<img src="../media/icons/new/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;">
|
||||||
<!-- 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 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 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 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">
|
||||||
|
@ -127,10 +177,10 @@
|
||||||
</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 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">
|
||||||
|
@ -153,10 +203,10 @@
|
||||||
</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 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">
|
||||||
|
@ -180,10 +230,10 @@
|
||||||
</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 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">
|
||||||
|
@ -207,10 +257,10 @@
|
||||||
</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 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">
|
||||||
|
@ -234,10 +284,10 @@
|
||||||
</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 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">
|
||||||
|
@ -260,10 +310,10 @@
|
||||||
</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 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 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,8 +457,8 @@
|
||||||
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')">
|
<button class="button-boost m-1 border-0 text-white dark-8u dark-shadow-sm" id="radiance-boost" onclick="update_radiance()">
|
||||||
Vanish (+80%)
|
Radiance
|
||||||
</button>
|
</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
|
||||||
|
@ -425,11 +466,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%)
|
||||||
|
@ -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>
|
||||||
|
@ -468,19 +506,19 @@
|
||||||
</div>
|
</div>
|
||||||
<div class="col skp-tooltip dark-6 rounded-bottom my-3 my-xl-1" >
|
<div class="col skp-tooltip dark-6 rounded-bottom my-3 my-xl-1" >
|
||||||
<button class = "button-boost m-1 border-0 text-white dark-8u dark-shadow-sm" id = "Quake-1" onclick = "updatePowderSpecials('Quake-1')">
|
<button class = "button-boost m-1 border-0 text-white dark-8u dark-shadow-sm" id = "Quake-1" onclick = "updatePowderSpecials('Quake-1')">
|
||||||
Lv.4 [e4e4]
|
Lv.1
|
||||||
</button>
|
</button>
|
||||||
<button class = "button-boost m-1 border-0 text-white dark-8u dark-shadow-sm" id = "Quake-2" onclick = "updatePowderSpecials('Quake-2')">
|
<button class = "button-boost m-1 border-0 text-white dark-8u dark-shadow-sm" id = "Quake-2" onclick = "updatePowderSpecials('Quake-2')">
|
||||||
Lv.4.5 [e5e4]
|
Lv.2
|
||||||
</button>
|
</button>
|
||||||
<button class = "button-boost m-1 border-0 text-white dark-8u dark-shadow-sm" id = "Quake-3" onclick = "updatePowderSpecials('Quake-3')">
|
<button class = "button-boost m-1 border-0 text-white dark-8u dark-shadow-sm" id = "Quake-3" onclick = "updatePowderSpecials('Quake-3')">
|
||||||
Lv.5 [e5e5]
|
Lv.3
|
||||||
</button>
|
</button>
|
||||||
<button class = "button-boost m-1 border-0 text-white dark-8u dark-shadow-sm" id = "Quake-4" onclick = "updatePowderSpecials('Quake-4')">
|
<button class = "button-boost m-1 border-0 text-white dark-8u dark-shadow-sm" id = "Quake-4" onclick = "updatePowderSpecials('Quake-4')">
|
||||||
Lv.5.5 [e6e5]
|
Lv.4
|
||||||
</button>
|
</button>
|
||||||
<button class = "button-boost m-1 border-0 text-white dark-8u dark-shadow-sm" id = "Quake-5" onclick = "updatePowderSpecials('Quake-5')">
|
<button class = "button-boost m-1 border-0 text-white dark-8u dark-shadow-sm" id = "Quake-5" onclick = "updatePowderSpecials('Quake-5')">
|
||||||
Lv.6 [e6e6]
|
Lv.5
|
||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
<div class="col eDam">
|
<div class="col eDam">
|
||||||
|
@ -493,19 +531,19 @@
|
||||||
</div>
|
</div>
|
||||||
<div class="col skp-tooltip dark-6 rounded-bottom my-3 my-xl-1">
|
<div class="col skp-tooltip dark-6 rounded-bottom my-3 my-xl-1">
|
||||||
<button class = "button-boost m-1 border-0 text-white dark-8u dark-shadow-sm" id = "Chain_Lightning-1" onclick = "updatePowderSpecials('Chain_Lightning-1')">
|
<button class = "button-boost m-1 border-0 text-white dark-8u dark-shadow-sm" id = "Chain_Lightning-1" onclick = "updatePowderSpecials('Chain_Lightning-1')">
|
||||||
Lv.4 [t4t4]
|
Lv.1
|
||||||
</button>
|
</button>
|
||||||
<button class = "button-boost m-1 border-0 text-white dark-8u dark-shadow-sm" id = "Chain_Lightning-2" onclick = "updatePowderSpecials('Chain_Lightning-2')">
|
<button class = "button-boost m-1 border-0 text-white dark-8u dark-shadow-sm" id = "Chain_Lightning-2" onclick = "updatePowderSpecials('Chain_Lightning-2')">
|
||||||
Lv.4.5 [t5t4]
|
Lv.2
|
||||||
</button>
|
</button>
|
||||||
<button class = "button-boost m-1 border-0 text-white dark-8u dark-shadow-sm" id = "Chain_Lightning-3" onclick = "updatePowderSpecials('Chain_Lightning-3')">
|
<button class = "button-boost m-1 border-0 text-white dark-8u dark-shadow-sm" id = "Chain_Lightning-3" onclick = "updatePowderSpecials('Chain_Lightning-3')">
|
||||||
Lv.5 [t5t5]
|
Lv.3
|
||||||
</button>
|
</button>
|
||||||
<button class = "button-boost m-1 border-0 text-white dark-8u dark-shadow-sm" id = "Chain_Lightning-4" onclick = "updatePowderSpecials('Chain_Lightning-4')">
|
<button class = "button-boost m-1 border-0 text-white dark-8u dark-shadow-sm" id = "Chain_Lightning-4" onclick = "updatePowderSpecials('Chain_Lightning-4')">
|
||||||
Lv.5.5 [t6t5]
|
Lv.4
|
||||||
</button>
|
</button>
|
||||||
<button class = "button-boost m-1 border-0 text-white dark-8u dark-shadow-sm" id = "Chain_Lightning-5" onclick = "updatePowderSpecials('Chain_Lightning-5')">
|
<button class = "button-boost m-1 border-0 text-white dark-8u dark-shadow-sm" id = "Chain_Lightning-5" onclick = "updatePowderSpecials('Chain_Lightning-5')">
|
||||||
Lv.6 [t6t6]
|
Lv.5
|
||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
<div class="col tDam">
|
<div class="col tDam">
|
||||||
|
@ -518,19 +556,19 @@
|
||||||
</div>
|
</div>
|
||||||
<div class="col skp-tooltip dark-6 rounded-bottom my-3 my-xl-1">
|
<div class="col skp-tooltip dark-6 rounded-bottom my-3 my-xl-1">
|
||||||
<button class = "button-boost m-1 border-0 text-white dark-8u dark-shadow-sm" id = "Curse-1" onclick = "updatePowderSpecials('Curse-1')">
|
<button class = "button-boost m-1 border-0 text-white dark-8u dark-shadow-sm" id = "Curse-1" onclick = "updatePowderSpecials('Curse-1')">
|
||||||
Lv.4 [w4w4]
|
Lv.1
|
||||||
</button>
|
</button>
|
||||||
<button class = "button-boost m-1 border-0 text-white dark-8u dark-shadow-sm" id = "Curse-2" onclick = "updatePowderSpecials('Curse-2')">
|
<button class = "button-boost m-1 border-0 text-white dark-8u dark-shadow-sm" id = "Curse-2" onclick = "updatePowderSpecials('Curse-2')">
|
||||||
Lv.4.5 [w5w4]
|
Lv.2
|
||||||
</button>
|
</button>
|
||||||
<button class = "button-boost m-1 border-0 text-white dark-8u dark-shadow-sm" id = "Curse-3" onclick = "updatePowderSpecials('Curse-3')">
|
<button class = "button-boost m-1 border-0 text-white dark-8u dark-shadow-sm" id = "Curse-3" onclick = "updatePowderSpecials('Curse-3')">
|
||||||
Lv.5 [w5w5]
|
Lv.3
|
||||||
</button>
|
</button>
|
||||||
<button class = "button-boost m-1 border-0 text-white dark-8u dark-shadow-sm" id = "Curse-4" onclick = "updatePowderSpecials('Curse-4')">
|
<button class = "button-boost m-1 border-0 text-white dark-8u dark-shadow-sm" id = "Curse-4" onclick = "updatePowderSpecials('Curse-4')">
|
||||||
Lv.5.5 [w6w5]
|
Lv.4
|
||||||
</button>
|
</button>
|
||||||
<button class = "button-boost m-1 border-0 text-white dark-8u dark-shadow-sm" id = "Curse-5" onclick = "updatePowderSpecials('Curse-5')">
|
<button class = "button-boost m-1 border-0 text-white dark-8u dark-shadow-sm" id = "Curse-5" onclick = "updatePowderSpecials('Curse-5')">
|
||||||
Lv.6 [w6w6]
|
Lv.5
|
||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
<div class="col wDam">
|
<div class="col wDam">
|
||||||
|
@ -543,19 +581,19 @@
|
||||||
</div>
|
</div>
|
||||||
<div class="col skp-tooltip dark-6 rounded-bottom my-3 my-xl-1">
|
<div class="col skp-tooltip dark-6 rounded-bottom my-3 my-xl-1">
|
||||||
<button class = "button-boost m-1 border-0 text-white dark-8u dark-shadow-sm" id = "Courage-1" onclick = "updatePowderSpecials('Courage-1')">
|
<button class = "button-boost m-1 border-0 text-white dark-8u dark-shadow-sm" id = "Courage-1" onclick = "updatePowderSpecials('Courage-1')">
|
||||||
Lv.4 [f4f4]
|
Lv.1
|
||||||
</button>
|
</button>
|
||||||
<button class = "button-boost m-1 border-0 text-white dark-8u dark-shadow-sm" id = "Courage-2" onclick = "updatePowderSpecials('Courage-2')">
|
<button class = "button-boost m-1 border-0 text-white dark-8u dark-shadow-sm" id = "Courage-2" onclick = "updatePowderSpecials('Courage-2')">
|
||||||
Lv.4.5 [f5f4]
|
Lv.2
|
||||||
</button>
|
</button>
|
||||||
<button class = "button-boost m-1 border-0 text-white dark-8u dark-shadow-sm" id = "Courage-3" onclick = "updatePowderSpecials('Courage-3')">
|
<button class = "button-boost m-1 border-0 text-white dark-8u dark-shadow-sm" id = "Courage-3" onclick = "updatePowderSpecials('Courage-3')">
|
||||||
Lv.5 [f5f5]
|
Lv.3
|
||||||
</button>
|
</button>
|
||||||
<button class = "button-boost m-1 border-0 text-white dark-8u dark-shadow-sm" id = "Courage-4" onclick = "updatePowderSpecials('Courage-4')">
|
<button class = "button-boost m-1 border-0 text-white dark-8u dark-shadow-sm" id = "Courage-4" onclick = "updatePowderSpecials('Courage-4')">
|
||||||
Lv.5.5 [f6f5]
|
Lv.4
|
||||||
</button>
|
</button>
|
||||||
<button class = "button-boost m-1 border-0 text-white dark-8u dark-shadow-sm" id = "Courage-5" onclick = "updatePowderSpecials('Courage-5')">
|
<button class = "button-boost m-1 border-0 text-white dark-8u dark-shadow-sm" id = "Courage-5" onclick = "updatePowderSpecials('Courage-5')">
|
||||||
Lv.6 [f6f6]
|
Lv.5
|
||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
<div class="col fDam">
|
<div class="col fDam">
|
||||||
|
@ -568,19 +606,19 @@
|
||||||
</div>
|
</div>
|
||||||
<div class="col skp-tooltip dark-6 rounded-bottom my-3 my-xl-1">
|
<div class="col skp-tooltip dark-6 rounded-bottom my-3 my-xl-1">
|
||||||
<button class = "button-boost m-1 border-0 text-white dark-8u dark-shadow-sm" id = "Wind_Prison-1" onclick = "updatePowderSpecials('Wind_Prison-1')">
|
<button class = "button-boost m-1 border-0 text-white dark-8u dark-shadow-sm" id = "Wind_Prison-1" onclick = "updatePowderSpecials('Wind_Prison-1')">
|
||||||
Lv.4 [a4a4]
|
Lv.1
|
||||||
</button>
|
</button>
|
||||||
<button class = "button-boost m-1 border-0 text-white dark-8u dark-shadow-sm" id = "Wind_Prison-2" onclick = "updatePowderSpecials('Wind_Prison-2')">
|
<button class = "button-boost m-1 border-0 text-white dark-8u dark-shadow-sm" id = "Wind_Prison-2" onclick = "updatePowderSpecials('Wind_Prison-2')">
|
||||||
Lv.4.5 [a5a4]
|
Lv.2
|
||||||
</button>
|
</button>
|
||||||
<button class = "button-boost m-1 border-0 text-white dark-8u dark-shadow-sm" id = "Wind_Prison-3" onclick = "updatePowderSpecials('Wind_Prison-3')">
|
<button class = "button-boost m-1 border-0 text-white dark-8u dark-shadow-sm" id = "Wind_Prison-3" onclick = "updatePowderSpecials('Wind_Prison-3')">
|
||||||
Lv.5 [a5a5]
|
Lv.3
|
||||||
</button>
|
</button>
|
||||||
<button class = "button-boost m-1 border-0 text-white dark-8u dark-shadow-sm" id = "Wind_Prison-4" onclick = "updatePowderSpecials('Wind_Prison-4')">
|
<button class = "button-boost m-1 border-0 text-white dark-8u dark-shadow-sm" id = "Wind_Prison-4" onclick = "updatePowderSpecials('Wind_Prison-4')">
|
||||||
Lv.5.5 [a6a5]
|
Lv.4
|
||||||
</button>
|
</button>
|
||||||
<button class = "button-boost m-1 border-0 text-white dark-8u dark-shadow-sm" id = "Wind_Prison-5" onclick = "updatePowderSpecials('Wind_Prison-5')">
|
<button class = "button-boost m-1 border-0 text-white dark-8u dark-shadow-sm" id = "Wind_Prison-5" onclick = "updatePowderSpecials('Wind_Prison-5')">
|
||||||
Lv.6 [a6a6]
|
Lv.5
|
||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
<div class="col aDam">
|
<div class="col aDam">
|
||||||
|
@ -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,12 +831,14 @@
|
||||||
</div>
|
</div>
|
||||||
<div class = "col dark-6 rounded-bottom my-3 my-xl-1" id = "atree-dropdown" style = "display:none;">
|
<div class = "col dark-6 rounded-bottom my-3 my-xl-1" id = "atree-dropdown" style = "display:none;">
|
||||||
<div class="row row-cols-1 row-cols-xl-2">
|
<div class="row row-cols-1 row-cols-xl-2">
|
||||||
<div class="col border border-semi-light rounded dark-9 hide-scroll" id="atree-ui" style="height: 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">
|
||||||
<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>
|
||||||
|
@ -1131,24 +1175,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">
|
||||||
|
@ -1195,7 +1235,7 @@
|
||||||
<div class="col-12 dark-5 scaled-font">
|
<div class="col-12 dark-5 scaled-font">
|
||||||
<footer class="text-center">
|
<footer class="text-center">
|
||||||
<div id="header2">
|
<div id="header2">
|
||||||
<p>Made by <b class = "hppeng">hppeng</b>, <b class = "ferricles">ferricles</b>, and <b>reschan</b> with <a href = "../atlas" target = "_blank" class = "atlas link">Atlas Inc</a> (JavaScript required to function, nothing works without js)</p>
|
<p>Made by <b class = "hppeng">hppeng</b>, <b class = "ferricles">ferricles</b>, <b>reschan</b>, and <b>blankman</b> with <a href = "../atlas" target = "_blank" class = "atlas link">Atlas Inc</a> (JavaScript required to function, nothing works without js)</p>
|
||||||
<p>Hard refresh the page (Ctrl+Shift+R on windows/chrome) if it isn't updating correctly.</p>
|
<p>Hard refresh the page (Ctrl+Shift+R on windows/chrome) if it isn't updating correctly.</p>
|
||||||
</div>
|
</div>
|
||||||
<div id="credits">
|
<div id="credits">
|
||||||
|
@ -1262,11 +1302,10 @@
|
||||||
<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/computation_graph.js"></script>
|
<script type="text/javascript" src="../js/computation_graph.js"></script>
|
||||||
<script type="text/javascript" src="../js/sq2icons.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/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>
|
||||||
|
@ -1274,13 +1313,12 @@
|
||||||
<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/build.js"></script>
|
||||||
<script type="text/javascript" src="../js/build_constants.js"></script>
|
<script type="text/javascript" src="../js/builder/builder_constants.js"></script>
|
||||||
<script type="text/javascript" src="../js/build_encode_decode.js"></script>
|
<script type="text/javascript" src="../js/builder/build_encode_decode.js"></script>
|
||||||
<script type="text/javascript" src="../js/atree.js"></script>
|
<script type="text/javascript" src="../js/builder/atree.js"></script>
|
||||||
<script type="text/javascript" src="../js/builder.js"></script>
|
<script type="text/javascript" src="../js/builder/builder_graph.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/optimize.js"></script-->
|
||||||
|
|
||||||
</body>
|
</body>
|
||||||
</html>
|
</html>
|
||||||
|
|
1001
builder2.html
74202
clean.json
|
@ -31,7 +31,50 @@
|
||||||
<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 mt-5">
|
<div id="mobile-navbar" class="navbar dark-5 dark-shadow fixed-top d-lg-none pb-0">
|
||||||
|
<div class="container-fluid scaled-font justify-content-center" style="height: 5vh;">
|
||||||
|
<div class="navbar-brand mx-auto scaled-font" style="height: 100%;">
|
||||||
|
<img src="../media/icons/new/crafter.png" alt="" style="height: 100%;">
|
||||||
|
<span>WynnCrafter</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 mt-lg-2" style="margin-top: 6vh;">
|
||||||
<div class="row row-cols-1 row-cols-lg-3 gy-5">
|
<div class="row row-cols-1 row-cols-lg-3 gy-5">
|
||||||
<div class="col col-lg-5">
|
<div class="col col-lg-5">
|
||||||
<!--crafter ui-->
|
<!--crafter ui-->
|
||||||
|
@ -39,7 +82,7 @@
|
||||||
<div class="col" id="recipe-dropdown">
|
<div class="col" id="recipe-dropdown">
|
||||||
<div class="row dark-shadow dark-5 rounded">
|
<div class="row dark-shadow dark-5 rounded">
|
||||||
<div id = "recipe-img-loc" class = "col-auto px-lg-1 g-0 dark-7 rounded-end my-auto text-center scaled-item-icon">
|
<div id = "recipe-img-loc" class = "col-auto px-lg-1 g-0 dark-7 rounded-end my-auto text-center scaled-item-icon">
|
||||||
<img id = "recipe-img" class = "img-fluid rounded Crafted-shadow" src = "../media/items/new/generic-potion.png">
|
<div id = "recipe-img" class = "img-fluid rounded Crafted-shadow" style = "background-image: url('../media/items/common.png'); background-size: 500% 100%; image-rendering: pixelated; background-position: 25% 0; aspect-ratio: 1/1;"></div>
|
||||||
</div>
|
</div>
|
||||||
<div class = "col ps-3">
|
<div class = "col ps-3">
|
||||||
<div class = "row row-cols-2 align-items-center">
|
<div class = "row row-cols-2 align-items-center">
|
||||||
|
@ -279,11 +322,9 @@
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<script type="text/javascript" src="../js/query.js"></script>
|
|
||||||
<script type="text/javascript" src="../js/query_2.js"></script>
|
|
||||||
<script type="text/javascript" src="../js/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/sq2icons.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/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>
|
||||||
|
@ -293,6 +334,5 @@
|
||||||
<script type="text/javascript" src="../js/load.js"></script>
|
<script type="text/javascript" src="../js/load.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/crafter.js"></script>
|
<script type="text/javascript" src="../js/crafter.js"></script>
|
||||||
<script type="text/javascript" src="../js/expr_parser.js"></script>
|
|
||||||
</body>
|
</body>
|
||||||
</html>
|
</html>
|
||||||
|
|
121
css/items.css
|
@ -1,32 +1,105 @@
|
||||||
.searchbox {
|
/* type selectors */
|
||||||
grid-column: 1;
|
|
||||||
padding: 0%;
|
#type-box {
|
||||||
display: grid;
|
cursor: pointer;
|
||||||
grid-template-columns: repeat(4, 1fr);
|
overflow: auto;
|
||||||
width: 100%;
|
}
|
||||||
gap: 5px;
|
#type-box > div {
|
||||||
|
display: inline-block;
|
||||||
|
width: calc(100% / 12);
|
||||||
|
float: left;
|
||||||
}
|
}
|
||||||
|
|
||||||
.items {
|
.type-selected {
|
||||||
grid-column: 1;
|
background-color: #0a0;
|
||||||
padding: 0%;
|
|
||||||
display: grid;
|
|
||||||
grid-template-columns: repeat(auto-fit, minmax(250px, 1fr));
|
|
||||||
width: 100%;
|
|
||||||
gap: 5px;
|
|
||||||
grid-template-rows: masonry;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
.itemsearch {
|
/* rarity selectors */
|
||||||
padding: 0%;
|
|
||||||
display: grid;
|
#rarity-box {
|
||||||
grid-template-columns: 1fr;
|
cursor: pointer;
|
||||||
width: 100%;
|
width: 58.33%;
|
||||||
gap: 5px;
|
text-align: center;
|
||||||
|
}
|
||||||
|
#rarity-box > div {
|
||||||
|
width: calc(100% / 7);
|
||||||
|
aspect-ratio: 1/1;
|
||||||
|
position: relative;
|
||||||
|
display: inline-block;
|
||||||
|
}
|
||||||
|
#rarity-box > div > b {
|
||||||
|
position: absolute;
|
||||||
|
top: 50%;
|
||||||
|
left: 50%;
|
||||||
|
transform: translate(-50%, -50%);
|
||||||
|
}
|
||||||
|
#rarity-box > div.rarity-selected > b {
|
||||||
|
color: black;
|
||||||
}
|
}
|
||||||
|
|
||||||
.searchinput {
|
#rarity-normal { color: #FFFFFF; }
|
||||||
width: 100%;
|
#rarity-normal.rarity-selected { background-color: #FFFFFF; }
|
||||||
max-width: 200px;
|
#rarity-unique { color: #FFFF55; }
|
||||||
|
#rarity-unique.rarity-selected { background-color: #FFFF55; }
|
||||||
|
#rarity-set { color: #55FF55; }
|
||||||
|
#rarity-set.rarity-selected { background-color: #55FF55; }
|
||||||
|
#rarity-rare { color: #FF55FF; }
|
||||||
|
#rarity-rare.rarity-selected { background-color: #FF55FF; }
|
||||||
|
#rarity-legendary { color: #55FFFF; }
|
||||||
|
#rarity-legendary.rarity-selected { background-color: #55FFFF; }
|
||||||
|
#rarity-fabled { color: #FF5555; }
|
||||||
|
#rarity-fabled.rarity-selected { background-color: #FF5555; }
|
||||||
|
#rarity-mythic { color: #AA00AA; }
|
||||||
|
#rarity-mythic.rarity-selected { background-color: #AA00AA; }
|
||||||
|
|
||||||
|
/* filters */
|
||||||
|
.filter-row {
|
||||||
|
border: 1px solid #121212;
|
||||||
|
}
|
||||||
|
.filter-dragged-over {
|
||||||
|
border: 1px solid white;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.reorder-filter {
|
||||||
|
height: 2ch;
|
||||||
|
cursor: pointer;
|
||||||
|
}
|
||||||
|
|
||||||
|
input.filter-input {
|
||||||
|
width: 27ch!important;
|
||||||
|
max-width: 90%;
|
||||||
|
display: inline-block;
|
||||||
|
}
|
||||||
|
|
||||||
|
.asc-icon {
|
||||||
|
opacity: 0.25;
|
||||||
|
width: 1.75ch;
|
||||||
|
}
|
||||||
|
.desc-icon {
|
||||||
|
opacity: 0.25;
|
||||||
|
width: 1.75ch;
|
||||||
|
transform: rotate(180deg);
|
||||||
|
}
|
||||||
|
img.asc-sel {
|
||||||
|
opacity: 0.85;
|
||||||
|
}
|
||||||
|
|
||||||
|
input.min-max-input {
|
||||||
|
width: 6ch!important;
|
||||||
|
display: inline-block;
|
||||||
|
}
|
||||||
|
|
||||||
|
.delete-filter {
|
||||||
|
cursor: pointer;
|
||||||
|
}
|
||||||
|
|
||||||
|
#filter-container > div > div > *, #exclude-container > div > div > * {
|
||||||
|
margin: 0 2px;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* item display */
|
||||||
|
@media (min-width: 576px) and (max-width: 991px) {
|
||||||
|
div.col-sm-6 {
|
||||||
|
width: 100%;
|
||||||
|
}
|
||||||
|
}
|
122
css/sq2bs.css
|
@ -7,7 +7,6 @@
|
||||||
}
|
}
|
||||||
/* builder containers */
|
/* builder containers */
|
||||||
|
|
||||||
|
|
||||||
.slider {
|
.slider {
|
||||||
-webkit-appearance: none;
|
-webkit-appearance: none;
|
||||||
background: #AAAAAA;
|
background: #AAAAAA;
|
||||||
|
@ -46,7 +45,6 @@ input[type=range]:focus {
|
||||||
outline: none; /* Removes the border. */
|
outline: none; /* Removes the border. */
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/* equipment field specifics */
|
/* equipment field specifics */
|
||||||
/* inputs and dropdowns */
|
/* inputs and dropdowns */
|
||||||
.form-control {
|
.form-control {
|
||||||
|
@ -63,6 +61,7 @@ ul.search-box {
|
||||||
position: absolute;
|
position: absolute;
|
||||||
padding: 0;
|
padding: 0;
|
||||||
overflow: auto;
|
overflow: auto;
|
||||||
|
z-index: 10;
|
||||||
}
|
}
|
||||||
|
|
||||||
li.search-item {
|
li.search-item {
|
||||||
|
@ -102,10 +101,15 @@ input.equipment-input {
|
||||||
font-weight: bold;
|
font-weight: bold;
|
||||||
background-color: hsl(0, 0%, 21%) !important;
|
background-color: hsl(0, 0%, 21%) !important;
|
||||||
border-radius: 0.375rem !important;
|
border-radius: 0.375rem !important;
|
||||||
border-color: rgba(33, 37, 41, 1) !important;
|
|
||||||
min-height: calc(1.2 * var(--scaled-fontsize) + 2px);
|
min-height: calc(1.2 * var(--scaled-fontsize) + 2px);
|
||||||
padding: 0rem 0.5rem;
|
padding: 0rem 0.5rem;
|
||||||
font-size: var(--scaled-fontsize);
|
font-size: var(--scaled-fontsize);
|
||||||
|
--bs-gutter-y: 1rem;
|
||||||
|
--bs-gutter-x: 3rem
|
||||||
|
}
|
||||||
|
|
||||||
|
input.equipment-input:not(.is-invalid) {
|
||||||
|
border-color: rgba(33, 37, 41, 1) !important;
|
||||||
}
|
}
|
||||||
|
|
||||||
.my-container {
|
.my-container {
|
||||||
|
@ -174,11 +178,11 @@ input.equipment-input {
|
||||||
}
|
}
|
||||||
|
|
||||||
.scaled-item-icon {
|
.scaled-item-icon {
|
||||||
width: 8rem;
|
width: 6rem;
|
||||||
}
|
}
|
||||||
|
|
||||||
.scaled-item-icon img {
|
.scaled-item-icon img {
|
||||||
width: 6.5rem;
|
width: 6rem;
|
||||||
}
|
}
|
||||||
|
|
||||||
.scaled-bckgrd {
|
.scaled-bckgrd {
|
||||||
|
@ -187,15 +191,19 @@ input.equipment-input {
|
||||||
}
|
}
|
||||||
|
|
||||||
.scaled-bckgrd img {
|
.scaled-bckgrd img {
|
||||||
width: 6.5rem;
|
width: 7rem;
|
||||||
}
|
}
|
||||||
|
|
||||||
@media screen and (min-width: 1200px) and (max-width: 1400px) {
|
.overall-box {
|
||||||
|
max-width: 95%;
|
||||||
|
}
|
||||||
|
|
||||||
|
@media screen and (orientation: landscape) and (max-width: 1199px) {
|
||||||
:root {
|
:root {
|
||||||
--scaled-fontsize: 1rem;
|
--scaled-fontsize: max(1rem, 16px);
|
||||||
}
|
}
|
||||||
.scaled-font {
|
.scaled-font {
|
||||||
font-size: 1rem;
|
font-size: max(1rem, 16px);
|
||||||
}
|
}
|
||||||
|
|
||||||
.box-title {
|
.box-title {
|
||||||
|
@ -211,7 +219,7 @@ input.equipment-input {
|
||||||
}
|
}
|
||||||
|
|
||||||
.skp-tooltip {
|
.skp-tooltip {
|
||||||
font-size: .625rem;
|
font-size: 1rem;
|
||||||
}
|
}
|
||||||
|
|
||||||
.spellcost-tooltip b {
|
.spellcost-tooltip b {
|
||||||
|
@ -244,10 +252,86 @@ input.equipment-input {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@media screen and (min-width: 1200px) and (max-width: 1400px) {
|
||||||
|
:root {
|
||||||
|
--scaled-fontsize: 1rem;
|
||||||
|
}
|
||||||
|
.overall-box {
|
||||||
|
padding-left: var(--sidebar-width);
|
||||||
|
max-width: 100%;
|
||||||
|
}
|
||||||
|
.equipment-input {
|
||||||
|
--bs-gutter-y: 0.5rem;
|
||||||
|
--bs-gutter-x: 1.5rem;
|
||||||
|
}
|
||||||
|
.level-input {
|
||||||
|
margin-top: 0
|
||||||
|
}
|
||||||
|
.scaled-font {
|
||||||
|
font-size: 1rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.box-title {
|
||||||
|
font-size: 1rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.item-title {
|
||||||
|
font-size: 1.2rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.big-title {
|
||||||
|
font-size: 1.5rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.skp-tooltip {
|
||||||
|
font-size: .625rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.spellcost-tooltip b {
|
||||||
|
font-size: .625rem !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.scaled-item-icon {
|
||||||
|
width: 2.6rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.scaled-item-icon img {
|
||||||
|
width: 2.2rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.scaled-bckgrd {
|
||||||
|
width: 4rem;
|
||||||
|
height: 4rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.scaled-bckgrd img {
|
||||||
|
width: 2.8rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.warning {
|
||||||
|
font-size: .7rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.spell-display b {
|
||||||
|
font-size: 1rem;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@media screen and (min-width: 1400px) {
|
@media screen and (min-width: 1400px) {
|
||||||
:root {
|
:root {
|
||||||
--scaled-fontsize: 1rem;
|
--scaled-fontsize: 1rem;
|
||||||
}
|
}
|
||||||
|
.overall-box {
|
||||||
|
padding-left: var(--sidebar-width);
|
||||||
|
max-width: 100%;
|
||||||
|
}
|
||||||
|
.equipment-input {
|
||||||
|
--bs-gutter-y: 0.5rem;
|
||||||
|
--bs-gutter-x: 1.5rem
|
||||||
|
}
|
||||||
|
.level-input {
|
||||||
|
margin-top: 0
|
||||||
|
}
|
||||||
.scaled-font {
|
.scaled-font {
|
||||||
font-size: 1rem;
|
font-size: 1rem;
|
||||||
}
|
}
|
||||||
|
@ -273,11 +357,11 @@ input.equipment-input {
|
||||||
}
|
}
|
||||||
|
|
||||||
.scaled-item-icon {
|
.scaled-item-icon {
|
||||||
width: 4rem;
|
width: 3.2rem;
|
||||||
}
|
}
|
||||||
|
|
||||||
.scaled-item-icon img {
|
.scaled-item-icon img {
|
||||||
width: 3.5rem;
|
width: 2.7rem;
|
||||||
}
|
}
|
||||||
|
|
||||||
.scaled-bckgrd {
|
.scaled-bckgrd {
|
||||||
|
@ -289,7 +373,6 @@ input.equipment-input {
|
||||||
width: 3.5rem;
|
width: 3.5rem;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
.warning {
|
.warning {
|
||||||
font-size: .8rem;
|
font-size: .8rem;
|
||||||
}
|
}
|
||||||
|
@ -460,3 +543,16 @@ a:hover {
|
||||||
.ferricles{
|
.ferricles{
|
||||||
color: #5be553;
|
color: #5be553;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.item-display-new-toggleable {
|
||||||
|
image-rendering: pixelated;
|
||||||
|
background-size: 1200% 100%;
|
||||||
|
aspect-ratio: 1/1;
|
||||||
|
}
|
||||||
|
.tome-image {
|
||||||
|
background-image: url('../media/items/common.png');
|
||||||
|
image-rendering: pixelated;
|
||||||
|
background-size: 500% 100%;
|
||||||
|
background-position: 100% 0;
|
||||||
|
aspect-ratio: 1/1;
|
||||||
|
}
|
||||||
|
|
|
@ -33,7 +33,50 @@
|
||||||
<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 row py-5 vh-100 mx-0 mx-lg-auto scaled-font">
|
<div id="mobile-navbar" class="navbar dark-5 dark-shadow fixed-top d-lg-none pb-0">
|
||||||
|
<div class="container-fluid scaled-font justify-content-center" style="height: 5vh;">
|
||||||
|
<div class="navbar-brand mx-auto scaled-font" style="height: 100%;">
|
||||||
|
<img src="../media/icons/new/custom.png" alt="" style="height: 100%;">
|
||||||
|
<span>WynnCustom</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 row py-5 vh-100 mx-0 mx-lg-auto scaled-font mt-lg-2" style="margin-top: 6vh;">
|
||||||
<div class = "col-lg-3 col-sm-12">
|
<div class = "col-lg-3 col-sm-12">
|
||||||
<div class = "col px-1">
|
<div class = "col px-1">
|
||||||
<div class = "row border border-dark border-3 mb-1 p-1 rounded dark-7">
|
<div class = "row border border-dark border-3 mb-1 p-1 rounded dark-7">
|
||||||
|
|
1
data/2.0.1.1/atree.json
Normal file
1
data/2.0.1.1/ingreds.json
Normal file
1
data/2.0.1.1/items.json
Normal file
809
data/2.0.1.1/tomes.json
Normal file
|
@ -0,0 +1,809 @@
|
||||||
|
{
|
||||||
|
"tomes": [
|
||||||
|
{
|
||||||
|
"name": "Retaliating Tome of Armour Mastery I",
|
||||||
|
"tier": "Fabled",
|
||||||
|
"type": "armorTome",
|
||||||
|
"category": "tome",
|
||||||
|
"drop": "never",
|
||||||
|
"restrict": "Soulbound Item",
|
||||||
|
"lvl": 60,
|
||||||
|
"defmobs": 3,
|
||||||
|
"thorns": 6,
|
||||||
|
"ref": 6,
|
||||||
|
"hpBonus": 120,
|
||||||
|
"fixID": false,
|
||||||
|
"id": 0,
|
||||||
|
"alias": "Thorns I"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "Retaliating Tome of Armour Mastery II",
|
||||||
|
"tier": "Fabled",
|
||||||
|
"type": "armorTome",
|
||||||
|
"category": "tome",
|
||||||
|
"drop": "never",
|
||||||
|
"restrict": "Soulbound Item",
|
||||||
|
"lvl": 100,
|
||||||
|
"defMobs": 5,
|
||||||
|
"thorns": 8,
|
||||||
|
"ref": 8,
|
||||||
|
"fixID": false,
|
||||||
|
"id": 1,
|
||||||
|
"alias": "Thorns II"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "Destructive Tome of Armour Mastery I",
|
||||||
|
"tier": "Fabled",
|
||||||
|
"type": "armorTome",
|
||||||
|
"category": "tome",
|
||||||
|
"drop": "never",
|
||||||
|
"restrict": "Soulbound Item",
|
||||||
|
"lvl": 60,
|
||||||
|
"defMobs": 3,
|
||||||
|
"exploding": 5,
|
||||||
|
"mdPct": 5,
|
||||||
|
"hpBonus": 120,
|
||||||
|
"fixID": false,
|
||||||
|
"id": 2,
|
||||||
|
"alias": "Melee I"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "Destructive Tome of Armour Mastery II",
|
||||||
|
"tier": "Fabled",
|
||||||
|
"type": "armorTome",
|
||||||
|
"category": "tome",
|
||||||
|
"drop": "never",
|
||||||
|
"restrict": "Soulbound Item",
|
||||||
|
"lvl": 100,
|
||||||
|
"defMobs": 5,
|
||||||
|
"exploding": 6,
|
||||||
|
"mdPct": 6,
|
||||||
|
"fixID": false,
|
||||||
|
"id": 3,
|
||||||
|
"alias": "Melee II"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "Sorcerer's Tome of Armour Mastery I",
|
||||||
|
"tier": "Fabled",
|
||||||
|
"type": "armorTome",
|
||||||
|
"category": "tome",
|
||||||
|
"drop": "never",
|
||||||
|
"restrict": "Soulbound Item",
|
||||||
|
"lvl": 60,
|
||||||
|
"defMobs": 3,
|
||||||
|
"sdPct": 5,
|
||||||
|
"hpBonus": 120,
|
||||||
|
"fixID": false,
|
||||||
|
"id": 4,
|
||||||
|
"alias": "Spell Damage I"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "Sorcerer's Tome of Armour Mastery II",
|
||||||
|
"tier": "Fabled",
|
||||||
|
"type": "armorTome",
|
||||||
|
"category": "tome",
|
||||||
|
"drop": "never",
|
||||||
|
"restrict": "Soulbound Item",
|
||||||
|
"lvl": 100,
|
||||||
|
"defMobs": 5,
|
||||||
|
"sdPct": 6,
|
||||||
|
"fixID": false,
|
||||||
|
"id": 5,
|
||||||
|
"alias": "Spell Damage II"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "Everlasting Tome of Armour Mastery I",
|
||||||
|
"tier": "Fabled",
|
||||||
|
"type": "armorTome",
|
||||||
|
"category": "tome",
|
||||||
|
"drop": "never",
|
||||||
|
"restrict": "Soulbound Item",
|
||||||
|
"lvl": 60,
|
||||||
|
"defMobs": 3,
|
||||||
|
"hprRaw": 15,
|
||||||
|
"hpBonus": 120,
|
||||||
|
"fixID": false,
|
||||||
|
"id": 6,
|
||||||
|
"alias": "Health Regen I"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "Everlasting Tome of Armour Mastery II",
|
||||||
|
"tier": "Fabled",
|
||||||
|
"type": "armorTome",
|
||||||
|
"category": "tome",
|
||||||
|
"drop": "never",
|
||||||
|
"restrict": "Soulbound Item",
|
||||||
|
"lvl": 100,
|
||||||
|
"defMobs": 5,
|
||||||
|
"hprRaw": 60,
|
||||||
|
"fixID": false,
|
||||||
|
"id": 7,
|
||||||
|
"alias": "Health Regen II"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "Vampiric Tome of Armour Mastery I",
|
||||||
|
"tier": "Fabled",
|
||||||
|
"type": "armorTome",
|
||||||
|
"category": "tome",
|
||||||
|
"drop": "never",
|
||||||
|
"restrict": "Soulbound Item",
|
||||||
|
"lvl": 60,
|
||||||
|
"defMobs": 3,
|
||||||
|
"ls": 25,
|
||||||
|
"hpBonus": 120,
|
||||||
|
"fixID": false,
|
||||||
|
"id": 8,
|
||||||
|
"alias": "Life Steal I"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "Vampiric Tome of Armour Mastery II",
|
||||||
|
"tier": "Fabled",
|
||||||
|
"type": "armorTome",
|
||||||
|
"category": "tome",
|
||||||
|
"drop": "never",
|
||||||
|
"restrict": "Soulbound Item",
|
||||||
|
"lvl": 100,
|
||||||
|
"defMobs": 5,
|
||||||
|
"ls": 85,
|
||||||
|
"fixID": false,
|
||||||
|
"id": 9,
|
||||||
|
"alias": "Life Steal II"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "Greedy Tome of Armour Mastery I",
|
||||||
|
"tier": "Fabled",
|
||||||
|
"type": "armorTome",
|
||||||
|
"category": "tome",
|
||||||
|
"drop": "never",
|
||||||
|
"restrict": "Soulbound Item",
|
||||||
|
"lvl": 60,
|
||||||
|
"defMobs": 3,
|
||||||
|
"lb": 5,
|
||||||
|
"hpBonus": 120,
|
||||||
|
"fixID": false,
|
||||||
|
"id": 10,
|
||||||
|
"alias": "Loot Bonus I"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "Greedy Tome of Armour Mastery II",
|
||||||
|
"tier": "Fabled",
|
||||||
|
"type": "armorTome",
|
||||||
|
"category": "tome",
|
||||||
|
"drop": "never",
|
||||||
|
"restrict": "Soulbound Item",
|
||||||
|
"lvl": 100,
|
||||||
|
"defMobs": 5,
|
||||||
|
"lb": 6,
|
||||||
|
"fixID": false,
|
||||||
|
"id": 11,
|
||||||
|
"alias": "Loot Bonus II"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "Weightless Tome of Armour Mastery I",
|
||||||
|
"tier": "Fabled",
|
||||||
|
"type": "armorTome",
|
||||||
|
"category": "tome",
|
||||||
|
"drop": "never",
|
||||||
|
"restrict": "Soulbound Item",
|
||||||
|
"lvl": 60,
|
||||||
|
"defMobs": 3,
|
||||||
|
"spd": 5,
|
||||||
|
"hpBonus": 120,
|
||||||
|
"fixID": false,
|
||||||
|
"id": 12,
|
||||||
|
"alias": "Walk Speed I"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "Weightless Tome of Armour Mastery II",
|
||||||
|
"tier": "Fabled",
|
||||||
|
"type": "armorTome",
|
||||||
|
"category": "tome",
|
||||||
|
"drop": "never",
|
||||||
|
"restrict": "Soulbound Item",
|
||||||
|
"lvl": 100,
|
||||||
|
"defMobs": 5,
|
||||||
|
"spd": 6,
|
||||||
|
"fixID": false,
|
||||||
|
"id": 13,
|
||||||
|
"alias": "Walk Speed II"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "Blooming Tome of Armour Mastery II",
|
||||||
|
"tier": "Mythic",
|
||||||
|
"type": "armorTome",
|
||||||
|
"category": "tome",
|
||||||
|
"drop": "never",
|
||||||
|
"restrict": "Soulbound Item",
|
||||||
|
"lvl": 100,
|
||||||
|
"defMobs": 8,
|
||||||
|
"eDefPct": 10,
|
||||||
|
"hpBonus": 150,
|
||||||
|
"fixID": false,
|
||||||
|
"id": 14,
|
||||||
|
"alias": "Earth Defense II"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "Pulsing Tome of Armour Mastery II",
|
||||||
|
"tier": "Mythic",
|
||||||
|
"type": "armorTome",
|
||||||
|
"category": "tome",
|
||||||
|
"drop": "never",
|
||||||
|
"restrict": "Soulbound Item",
|
||||||
|
"lvl": 100,
|
||||||
|
"defMobs": 8,
|
||||||
|
"tDefPct": 10,
|
||||||
|
"hpBonus": 150,
|
||||||
|
"fixID": false,
|
||||||
|
"id": 15,
|
||||||
|
"alias": "Thunder Defense II"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "Oceanic Tome of Armour Mastery II",
|
||||||
|
"tier": "Mythic",
|
||||||
|
"type": "armorTome",
|
||||||
|
"category": "tome",
|
||||||
|
"drop": "never",
|
||||||
|
"restrict": "Soulbound Item",
|
||||||
|
"lvl": 100,
|
||||||
|
"defMobs": 8,
|
||||||
|
"wDefPct": 10,
|
||||||
|
"hpBonus": 150,
|
||||||
|
"fixID": false,
|
||||||
|
"id": 16,
|
||||||
|
"alias": "Water Defense II"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "Courageous Tome of Armour Mastery II",
|
||||||
|
"tier": "Mythic",
|
||||||
|
"type": "armorTome",
|
||||||
|
"category": "tome",
|
||||||
|
"drop": "never",
|
||||||
|
"restrict": "Soulbound Item",
|
||||||
|
"lvl": 100,
|
||||||
|
"defMobs": 8,
|
||||||
|
"fDefPct": 10,
|
||||||
|
"hpBonus": 150,
|
||||||
|
"fixID": false,
|
||||||
|
"id": 17,
|
||||||
|
"alias": "Fire Defense II"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "Clouded Tome of Armour Mastery II",
|
||||||
|
"tier": "Mythic",
|
||||||
|
"type": "armorTome",
|
||||||
|
"category": "tome",
|
||||||
|
"drop": "never",
|
||||||
|
"restrict": "Soulbound Item",
|
||||||
|
"lvl": 100,
|
||||||
|
"defMobs": 8,
|
||||||
|
"aDefPct": 10,
|
||||||
|
"hpBonus": 150,
|
||||||
|
"fixID": false,
|
||||||
|
"id": 18,
|
||||||
|
"alias": "Air Defense II"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "Radiant Tome of Armour Mastery II",
|
||||||
|
"tier": "Mythic",
|
||||||
|
"type": "armorTome",
|
||||||
|
"category": "tome",
|
||||||
|
"drop": "never",
|
||||||
|
"restrict": "Soulbound Item",
|
||||||
|
"lvl": 100,
|
||||||
|
"defMobs": 8,
|
||||||
|
"eDefPct": 6,
|
||||||
|
"tDefPct": 6,
|
||||||
|
"wDefPct": 6,
|
||||||
|
"fDefPct": 6,
|
||||||
|
"aDefPct": 6,
|
||||||
|
"hpBonus": 150,
|
||||||
|
"fixID": false,
|
||||||
|
"id": 19,
|
||||||
|
"alias": "Rainbow Defense II"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "Tome of Weapon Mastery I",
|
||||||
|
"tier": "Legendary",
|
||||||
|
"type": "weaponTome",
|
||||||
|
"category": "tome",
|
||||||
|
"drop": "never",
|
||||||
|
"restrict": "Soulbound Item",
|
||||||
|
"lvl": 60,
|
||||||
|
"damMobs": 6,
|
||||||
|
"fixID": false,
|
||||||
|
"id": 20,
|
||||||
|
"alias": "Weapon Mastery I"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "Earthbound Tome of Weapon Mastery I",
|
||||||
|
"tier": "Fabled",
|
||||||
|
"type": "weaponTome",
|
||||||
|
"category": "tome",
|
||||||
|
"drop": "never",
|
||||||
|
"restrict": "Soulbound Item",
|
||||||
|
"lvl": 80,
|
||||||
|
"damMobs": 7,
|
||||||
|
"str": 3,
|
||||||
|
"fixID": false,
|
||||||
|
"id": 21,
|
||||||
|
"alias": "Strength I"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "Earthbound Tome of Weapon Mastery II",
|
||||||
|
"tier": "Fabled",
|
||||||
|
"type": "weaponTome",
|
||||||
|
"category": "tome",
|
||||||
|
"drop": "never",
|
||||||
|
"restrict": "Soulbound Item",
|
||||||
|
"lvl": 80,
|
||||||
|
"damMobs": 8,
|
||||||
|
"str": 3,
|
||||||
|
"fixID": false,
|
||||||
|
"id": 22,
|
||||||
|
"alias": "Strength II"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "Nimble Tome of Weapon Mastery I",
|
||||||
|
"tier": "Fabled",
|
||||||
|
"type": "weaponTome",
|
||||||
|
"category": "tome",
|
||||||
|
"drop": "never",
|
||||||
|
"restrict": "Soulbound Item",
|
||||||
|
"lvl": 80,
|
||||||
|
"damMobs": 7,
|
||||||
|
"dex": 3,
|
||||||
|
"fixID": false,
|
||||||
|
"id": 23,
|
||||||
|
"alias": "Dexterity I"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "Nimble Tome of Weapon Mastery II",
|
||||||
|
"tier": "Fabled",
|
||||||
|
"type": "weaponTome",
|
||||||
|
"category": "tome",
|
||||||
|
"drop": "never",
|
||||||
|
"restrict": "Soulbound Item",
|
||||||
|
"lvl": 80,
|
||||||
|
"damMobs": 8,
|
||||||
|
"dex": 3,
|
||||||
|
"fixID": false,
|
||||||
|
"id": 24,
|
||||||
|
"alias": "Dexterity II"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "Mystical Tome of Weapon Mastery I",
|
||||||
|
"tier": "Fabled",
|
||||||
|
"type": "weaponTome",
|
||||||
|
"category": "tome",
|
||||||
|
"drop": "never",
|
||||||
|
"restrict": "Soulbound Item",
|
||||||
|
"lvl": 80,
|
||||||
|
"damMobs": 7,
|
||||||
|
"int": 3,
|
||||||
|
"fixID": false,
|
||||||
|
"id": 25,
|
||||||
|
"alias": "Intelligence I"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "Mystical Tome of Weapon Mastery II",
|
||||||
|
"tier": "Fabled",
|
||||||
|
"type": "weaponTome",
|
||||||
|
"category": "tome",
|
||||||
|
"drop": "never",
|
||||||
|
"restrict": "Soulbound Item",
|
||||||
|
"lvl": 80,
|
||||||
|
"damMobs": 8,
|
||||||
|
"int": 3,
|
||||||
|
"fixID": false,
|
||||||
|
"id": 26,
|
||||||
|
"alias": "Intelligence II"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "Warding Tome of Weapon Mastery I",
|
||||||
|
"tier": "Fabled",
|
||||||
|
"type": "weaponTome",
|
||||||
|
"category": "tome",
|
||||||
|
"drop": "never",
|
||||||
|
"restrict": "Soulbound Item",
|
||||||
|
"lvl": 80,
|
||||||
|
"damMobs": 7,
|
||||||
|
"def": 3,
|
||||||
|
"fixID": false,
|
||||||
|
"id": 27,
|
||||||
|
"alias": "Defense I"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "Warding Tome of Weapon Mastery II",
|
||||||
|
"tier": "Fabled",
|
||||||
|
"type": "weaponTome",
|
||||||
|
"category": "tome",
|
||||||
|
"drop": "never",
|
||||||
|
"restrict": "Soulbound Item",
|
||||||
|
"lvl": 80,
|
||||||
|
"damMobs": 8,
|
||||||
|
"def": 3,
|
||||||
|
"fixID": false,
|
||||||
|
"id": 28,
|
||||||
|
"alias": "Defense II"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "Athletic Tome of Weapon Mastery I",
|
||||||
|
"tier": "Fabled",
|
||||||
|
"type": "weaponTome",
|
||||||
|
"category": "tome",
|
||||||
|
"drop": "never",
|
||||||
|
"restrict": "Soulbound Item",
|
||||||
|
"lvl": 80,
|
||||||
|
"damMobs": 7,
|
||||||
|
"agi": 3,
|
||||||
|
"fixID": false,
|
||||||
|
"id": 29,
|
||||||
|
"alias": "Agility I"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "Athletic Tome of Weapon Mastery II",
|
||||||
|
"tier": "Fabled",
|
||||||
|
"type": "weaponTome",
|
||||||
|
"category": "tome",
|
||||||
|
"drop": "never",
|
||||||
|
"restrict": "Soulbound Item",
|
||||||
|
"lvl": 80,
|
||||||
|
"damMobs": 8,
|
||||||
|
"agi": 3,
|
||||||
|
"fixID": false,
|
||||||
|
"id": 30,
|
||||||
|
"alias": "Agility II"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "Cosmic Tome of Weapon Mastery I",
|
||||||
|
"tier": "Fabled",
|
||||||
|
"type": "weaponTome",
|
||||||
|
"category": "tome",
|
||||||
|
"drop": "never",
|
||||||
|
"restrict": "Soulbound Item",
|
||||||
|
"lvl": 80,
|
||||||
|
"damMobs": 7,
|
||||||
|
"str": 1,
|
||||||
|
"dex": 1,
|
||||||
|
"int": 1,
|
||||||
|
"def": 1,
|
||||||
|
"agi": 1,
|
||||||
|
"fixID": false,
|
||||||
|
"id": 31,
|
||||||
|
"alias": "Rainbow Skillpoint I"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "Cosmic Tome of Weapon Mastery II",
|
||||||
|
"tier": "Fabled",
|
||||||
|
"type": "weaponTome",
|
||||||
|
"category": "tome",
|
||||||
|
"drop": "never",
|
||||||
|
"restrict": "Soulbound Item",
|
||||||
|
"lvl": 80,
|
||||||
|
"damMobs": 8,
|
||||||
|
"str": 1,
|
||||||
|
"dex": 1,
|
||||||
|
"int": 1,
|
||||||
|
"def": 1,
|
||||||
|
"agi": 1,
|
||||||
|
"fixID": false,
|
||||||
|
"id": 32,
|
||||||
|
"alias": "Rainbow Skillpoint II"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "Seismic Tome of Weapon Mastery II",
|
||||||
|
"tier": "Mythic",
|
||||||
|
"type": "weaponTome",
|
||||||
|
"category": "tome",
|
||||||
|
"drop": "never",
|
||||||
|
"restrict": "Soulbound Item",
|
||||||
|
"lvl": 80,
|
||||||
|
"damMobs": 12,
|
||||||
|
"eDamPct": 7,
|
||||||
|
"fixID": false,
|
||||||
|
"id": 33,
|
||||||
|
"alias": "Earth Damage II"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "Voltaic Tome of Weapon Mastery II",
|
||||||
|
"tier": "Mythic",
|
||||||
|
"type": "weaponTome",
|
||||||
|
"category": "tome",
|
||||||
|
"drop": "never",
|
||||||
|
"restrict": "Soulbound Item",
|
||||||
|
"lvl": 80,
|
||||||
|
"damMobs": 12,
|
||||||
|
"tDamPct": 7,
|
||||||
|
"fixID": false,
|
||||||
|
"id": 34,
|
||||||
|
"alias": "Thunder Damage II"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "Abyssal Tome of Weapon Mastery II",
|
||||||
|
"tier": "Mythic",
|
||||||
|
"type": "weaponTome",
|
||||||
|
"category": "tome",
|
||||||
|
"drop": "never",
|
||||||
|
"restrict": "Soulbound Item",
|
||||||
|
"lvl": 80,
|
||||||
|
"damMobs": 12,
|
||||||
|
"wDamPct": 7,
|
||||||
|
"fixID": false,
|
||||||
|
"id": 35,
|
||||||
|
"alias": "Water Damage II"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "Infernal Tome of Weapon Mastery II",
|
||||||
|
"tier": "Mythic",
|
||||||
|
"type": "weaponTome",
|
||||||
|
"category": "tome",
|
||||||
|
"drop": "never",
|
||||||
|
"restrict": "Soulbound Item",
|
||||||
|
"lvl": 80,
|
||||||
|
"damMobs": 12,
|
||||||
|
"fDamPct": 7,
|
||||||
|
"fixID": false,
|
||||||
|
"id": 36,
|
||||||
|
"alias": "Fire Damage II"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "Cyclonic Tome of Weapon Mastery II",
|
||||||
|
"tier": "Mythic",
|
||||||
|
"type": "weaponTome",
|
||||||
|
"category": "tome",
|
||||||
|
"drop": "never",
|
||||||
|
"restrict": "Soulbound Item",
|
||||||
|
"lvl": 80,
|
||||||
|
"damMobs": 12,
|
||||||
|
"aDamPct": 7,
|
||||||
|
"fixID": false,
|
||||||
|
"id": 37,
|
||||||
|
"alias": "Air Damage II"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "Astral Tome of Weapon Mastery II",
|
||||||
|
"tier": "Mythic",
|
||||||
|
"type": "weaponTome",
|
||||||
|
"category": "tome",
|
||||||
|
"drop": "never",
|
||||||
|
"restrict": "Soulbound Item",
|
||||||
|
"lvl": 80,
|
||||||
|
"damMobs": 12,
|
||||||
|
"eDamPct": 6,
|
||||||
|
"tDamPct": 6,
|
||||||
|
"wDamPct": 6,
|
||||||
|
"fDamPct": 6,
|
||||||
|
"aDamPct": 6,
|
||||||
|
"fixID": false,
|
||||||
|
"id": 38,
|
||||||
|
"alias": "Rainbow Damage II"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "Brute's Tome of Allegiance",
|
||||||
|
"tier": "Legendary",
|
||||||
|
"type": "guildTome",
|
||||||
|
"category": "tome",
|
||||||
|
"drop": "never",
|
||||||
|
"restrict": "Untradable",
|
||||||
|
"lvl": 100,
|
||||||
|
"str": 3,
|
||||||
|
"eDamPct": 2,
|
||||||
|
"fixID": false,
|
||||||
|
"id": 39,
|
||||||
|
"alias": "Strength"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "Sadist's Tome of Allegiance",
|
||||||
|
"tier": "Legendary",
|
||||||
|
"type": "guildTome",
|
||||||
|
"category": "tome",
|
||||||
|
"drop": "never",
|
||||||
|
"restrict": "Untradable",
|
||||||
|
"lvl": 100,
|
||||||
|
"dex": 3,
|
||||||
|
"tDamPct": 2,
|
||||||
|
"fixID": false,
|
||||||
|
"id": 40,
|
||||||
|
"alias": "Dexterity"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "Mastermind's Tome of Allegiance",
|
||||||
|
"tier": "Legendary",
|
||||||
|
"type": "guildTome",
|
||||||
|
"category": "tome",
|
||||||
|
"drop": "never",
|
||||||
|
"restrict": "Untradable",
|
||||||
|
"lvl": 100,
|
||||||
|
"int": 3,
|
||||||
|
"wDamPct": 2,
|
||||||
|
"fixID": false,
|
||||||
|
"id": 41,
|
||||||
|
"alias": "Intelligence"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "Arsonist's Tome of Allegiance",
|
||||||
|
"tier": "Legendary",
|
||||||
|
"type": "guildTome",
|
||||||
|
"category": "tome",
|
||||||
|
"drop": "never",
|
||||||
|
"restrict": "Untradable",
|
||||||
|
"lvl": 100,
|
||||||
|
"def": 3,
|
||||||
|
"fDamPct": 2,
|
||||||
|
"fixID": false,
|
||||||
|
"id": 42,
|
||||||
|
"alias": "Defense"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "Ghost's Tome of Allegiance",
|
||||||
|
"tier": "Legendary",
|
||||||
|
"type": "guildTome",
|
||||||
|
"category": "tome",
|
||||||
|
"drop": "never",
|
||||||
|
"restrict": "Untradable",
|
||||||
|
"lvl": 100,
|
||||||
|
"agi": 3,
|
||||||
|
"aDamPct": 2,
|
||||||
|
"fixID": false,
|
||||||
|
"id": 43,
|
||||||
|
"alias": "Agility"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "Psychopath's Tome of Allegiance",
|
||||||
|
"tier": "Legendary",
|
||||||
|
"type": "guildTome",
|
||||||
|
"category": "tome",
|
||||||
|
"drop": "never",
|
||||||
|
"restrict": "Untradable",
|
||||||
|
"lvl": 100,
|
||||||
|
"str": 2,
|
||||||
|
"dex": 2,
|
||||||
|
"fixID": false,
|
||||||
|
"id": 44,
|
||||||
|
"alias": "ET"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "Loner's Tome of Allegiance",
|
||||||
|
"tier": "Legendary",
|
||||||
|
"type": "guildTome",
|
||||||
|
"category": "tome",
|
||||||
|
"drop": "never",
|
||||||
|
"restrict": "Untradable",
|
||||||
|
"lvl": 100,
|
||||||
|
"str": 2,
|
||||||
|
"int": 2,
|
||||||
|
"fixID": false,
|
||||||
|
"id": 45,
|
||||||
|
"alias": "EW"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "Warlock's Tome of Allegiance",
|
||||||
|
"tier": "Legendary",
|
||||||
|
"type": "guildTome",
|
||||||
|
"category": "tome",
|
||||||
|
"drop": "never",
|
||||||
|
"restrict": "Untradable",
|
||||||
|
"lvl": 100,
|
||||||
|
"dex": 2,
|
||||||
|
"int": 2,
|
||||||
|
"fixID": false,
|
||||||
|
"id": 46,
|
||||||
|
"alias": "TW"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "Destroyer's Tome of Allegiance",
|
||||||
|
"tier": "Legendary",
|
||||||
|
"type": "guildTome",
|
||||||
|
"category": "tome",
|
||||||
|
"drop": "never",
|
||||||
|
"restrict": "Untradable",
|
||||||
|
"lvl": 100,
|
||||||
|
"str": 2,
|
||||||
|
"def": 2,
|
||||||
|
"fixID": false,
|
||||||
|
"id": 47,
|
||||||
|
"alias": "EF"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "Devil's Tome of Allegiance",
|
||||||
|
"tier": "Legendary",
|
||||||
|
"type": "guildTome",
|
||||||
|
"category": "tome",
|
||||||
|
"drop": "never",
|
||||||
|
"restrict": "Untradable",
|
||||||
|
"lvl": 100,
|
||||||
|
"dex": 2,
|
||||||
|
"def": 2,
|
||||||
|
"fixID": false,
|
||||||
|
"id": 48,
|
||||||
|
"alias": "TF"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "Alchemist's Tome of Allegiance",
|
||||||
|
"tier": "Legendary",
|
||||||
|
"type": "guildTome",
|
||||||
|
"category": "tome",
|
||||||
|
"drop": "never",
|
||||||
|
"restrict": "Untradable",
|
||||||
|
"lvl": 100,
|
||||||
|
"int": 2,
|
||||||
|
"def": 2,
|
||||||
|
"fixID": false,
|
||||||
|
"id": 49,
|
||||||
|
"alias": "WF"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "Barbarian's Tome of Allegiance",
|
||||||
|
"tier": "Legendary",
|
||||||
|
"type": "guildTome",
|
||||||
|
"category": "tome",
|
||||||
|
"drop": "never",
|
||||||
|
"restrict": "Untradable",
|
||||||
|
"lvl": 100,
|
||||||
|
"str": 2,
|
||||||
|
"agi": 2,
|
||||||
|
"fixID": false,
|
||||||
|
"id": 50,
|
||||||
|
"alias": "EA"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "Freelancer's Tome of Allegiance",
|
||||||
|
"tier": "Legendary",
|
||||||
|
"type": "guildTome",
|
||||||
|
"category": "tome",
|
||||||
|
"drop": "never",
|
||||||
|
"restrict": "Untradable",
|
||||||
|
"lvl": 100,
|
||||||
|
"dex": 2,
|
||||||
|
"agi": 2,
|
||||||
|
"fixID": false,
|
||||||
|
"id": 51,
|
||||||
|
"alias": "TA"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "Sycophant's Tome of Allegiance",
|
||||||
|
"tier": "Legendary",
|
||||||
|
"type": "guildTome",
|
||||||
|
"category": "tome",
|
||||||
|
"drop": "never",
|
||||||
|
"restrict": "Untradable",
|
||||||
|
"lvl": 100,
|
||||||
|
"int": 2,
|
||||||
|
"agi": 2,
|
||||||
|
"fixID": false,
|
||||||
|
"id": 52,
|
||||||
|
"alias": "WA"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "Fanatic's Tome of Allegiance",
|
||||||
|
"tier": "Legendary",
|
||||||
|
"type": "guildTome",
|
||||||
|
"category": "tome",
|
||||||
|
"drop": "never",
|
||||||
|
"restrict": "Untradable",
|
||||||
|
"lvl": 100,
|
||||||
|
"def": 2,
|
||||||
|
"agi": 2,
|
||||||
|
"fixID": false,
|
||||||
|
"id": 53,
|
||||||
|
"alias": "FA"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "Assimilator's Tome of Allegiance",
|
||||||
|
"tier": "Legendary",
|
||||||
|
"type": "guildTome",
|
||||||
|
"category": "tome",
|
||||||
|
"drop": "never",
|
||||||
|
"restrict": "Untradable",
|
||||||
|
"lvl": 100,
|
||||||
|
"str": 1,
|
||||||
|
"dex": 1,
|
||||||
|
"int": 1,
|
||||||
|
"def": 1,
|
||||||
|
"agi": 1,
|
||||||
|
"fixID": false,
|
||||||
|
"id": 54,
|
||||||
|
"alias": "Rainbow"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
1
data/2.0.1.2/atree.json
Normal file
1
data/2.0.1.2/ingreds.json
Normal file
1
data/2.0.1.2/items.json
Normal file
1069
data/2.0.1.2/tomes.json
Normal file
|
@ -143,11 +143,82 @@
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
<p>
|
<p>
|
||||||
All build links will end in "#[version number]_[build hash]".
|
All build links starting from Version 8 may look like "?v=[wynn version number]#[version number]_[build hash]".
|
||||||
|
The query section is optional.
|
||||||
</p>
|
</p>
|
||||||
|
<p>
|
||||||
|
All build links older than Version 8 look like "#[version number]_[build hash]".
|
||||||
|
</p>
|
||||||
|
<div class="row section" title="Version 8">
|
||||||
|
<p>
|
||||||
|
Version 8 was made to account for an oversight made when designing the tome encoding, and to signal the beginning of versions that support wynn version history. Version 8 and higher links may start with a query indicating the wynn version to use.
|
||||||
|
</p>
|
||||||
|
<p>
|
||||||
|
Additionally, Version 8 uses 2 characters instead of 1 character to encode the ID of each tome. (The IDs representing NONE tomes does not change.)
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
<div class="row section" title="Version 7">
|
||||||
|
<p>
|
||||||
|
Version 7 was made to account for ability trees in wynncraft 2.0. Version 7 introduces a new field at the end of the build hash, for ability tree data. Atree data is compressed using a depth first search algorithm into a binary blob, which is then base-64 encoded and appended to the V6 hash. The binry blob is decompressed by using the corresponding traversal.
|
||||||
|
</p>
|
||||||
|
<p>
|
||||||
|
The tree structure defining the ability tree can be found in a json file (by default, <code>js/builder/atree_constants_min.json</code>). The file defines connections between the ability tree nodes: Each node has an unordered list of parent nodes, and an ordered list of child nodes.
|
||||||
|
</p>
|
||||||
|
<p>
|
||||||
|
A reference implementation of the encoding/decoding algorithms can be found in <code>js/builder/build_encode_decode.js</code>. A pseudocode description of the algorithms is given here:
|
||||||
|
</p>
|
||||||
|
<code style="white-space: pre">
|
||||||
|
// Encode an ability tree configuration into a binary blob.
|
||||||
|
// NOTE: this algorithm only works for "connected" (valid) ability trees.
|
||||||
|
// Its behavior is not well defined otherwise.
|
||||||
|
//
|
||||||
|
// Parameters:
|
||||||
|
// tree_data: Object containing ability tree structure.
|
||||||
|
// tree_state: Object containing info about which abilities are selected.
|
||||||
|
function encode(tree_data, tree_state):
|
||||||
|
|
||||||
|
return_vector = BitVector()
|
||||||
|
visited = Set()
|
||||||
|
|
||||||
|
function recursive_traverse(head_node):
|
||||||
|
for each child of head_node, in order:
|
||||||
|
if child is not in visited:
|
||||||
|
add child to visited set
|
||||||
|
if tree_state.is_active(child):
|
||||||
|
append bit 1 to return_vector
|
||||||
|
recursive_traverse(child)
|
||||||
|
else:
|
||||||
|
append bit 0 to return_vector
|
||||||
|
|
||||||
|
recursive_traverse(tree_data.root)
|
||||||
|
return return_vector
|
||||||
|
|
||||||
|
// Decode a binary blob into an ability tree configuration
|
||||||
|
//
|
||||||
|
// Parameters:
|
||||||
|
// tree_data: Object containing ability tree structure.
|
||||||
|
// tree_state: Object containing info about which abilities are selected.
|
||||||
|
// tree_bitvector: raw binary data, accessed one bit at a time
|
||||||
|
function decode(tree_data, tree_state, tree_bitvector):
|
||||||
|
|
||||||
|
i = 0
|
||||||
|
visited = Set()
|
||||||
|
|
||||||
|
function recursive_traverse(head_node):
|
||||||
|
for each child of head_node, in order:
|
||||||
|
if child is not in visited:
|
||||||
|
add child to visited set
|
||||||
|
if tree_bitvector[i]:
|
||||||
|
child.active = True
|
||||||
|
recursive_traverse(child)
|
||||||
|
else:
|
||||||
|
child.active = False
|
||||||
|
i = i + 1
|
||||||
|
</code>
|
||||||
|
</div>
|
||||||
<div class="row section" title="Version 6">
|
<div class="row section" title="Version 6">
|
||||||
<p>
|
<p>
|
||||||
Version 6 was made to account for the desire to save tomes in a build. As of the last version of this documentation, version 6 is used for encoding whenever there are tomes in the build.
|
Version 6 was made to account for the desire to save tomes in a build.
|
||||||
</p>
|
</p>
|
||||||
<div class = "row section" title = "Example 1: With Tomes">
|
<div class = "row section" title = "Example 1: With Tomes">
|
||||||
<code class="full-width">
|
<code class="full-width">
|
||||||
|
@ -959,7 +1030,7 @@
|
||||||
</div> -->
|
</div> -->
|
||||||
</div>
|
</div>
|
||||||
<script type="text/javascript" src="../js/dev.js"></script>
|
<script type="text/javascript" src="../js/dev.js"></script>
|
||||||
<script type="text/javascript" src="../js/sq2icons.js"></script>
|
<script type="text/javascript" src="../js/icons.js"></script>
|
||||||
</body>
|
</body>
|
||||||
|
|
||||||
</html>
|
</html>
|
||||||
|
|
3496
ingreds_clean.json
|
@ -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>
|
||||||
|
|
172
items/index.html
|
@ -18,6 +18,7 @@
|
||||||
<link rel="stylesheet" href="../css/sq2bs.css">
|
<link rel="stylesheet" href="../css/sq2bs.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">
|
||||||
|
<link rel="stylesheet" href="../css/items.css">
|
||||||
</head>
|
</head>
|
||||||
<body class = "text-light d-flex justify-content-center" id = "body">
|
<body class = "text-light d-flex justify-content-center" id = "body">
|
||||||
<div id="main-sidebar" class="sidebar dark-7 dark-shadow">
|
<div id="main-sidebar" class="sidebar dark-7 dark-shadow">
|
||||||
|
@ -31,101 +32,128 @@
|
||||||
<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 id="mobile-navbar" class="navbar dark-5 dark-shadow fixed-top d-lg-none pb-0">
|
||||||
|
<div class="container-fluid scaled-font justify-content-center" style="height: 5vh;">
|
||||||
|
<div class="navbar-brand mx-auto scaled-font" style="height: 100%;">
|
||||||
|
<img src="../media/icons/new/searcher.png" alt="" style="height: 100%;">
|
||||||
|
<span>WynnAtlas</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 py-5 vh-100 mx-0 mx-lg-auto scaled-font">
|
<div class = "container py-5 vh-100 mx-0 mx-lg-auto scaled-font">
|
||||||
<div class = "col">
|
|
||||||
<div class = "row">
|
<div class = "row">
|
||||||
|
<div class = "row" style = "margin-top: 3ch;">
|
||||||
<div class = "col text-end">
|
<div class = "col text-end">
|
||||||
<a href = "../items_adv/">Advanced Item Search</a>
|
<a href = "../items_adv/">Advanced Item Search</a>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
<div class = "col-auto" style = "width: 12.5%;"></div>
|
||||||
|
<div class = "col-lg-4">
|
||||||
<div class = "row">
|
<div class = "row">
|
||||||
<div class = "row">
|
<div class = "col-lg col-sm-12">
|
||||||
<div class = "col-lg-3 col-sm-12">
|
|
||||||
<div class = "col fw-bold">Name:</div>
|
<div class = "col fw-bold">Name:</div>
|
||||||
<input class = "col border-dark text-light dark-5 rounded scaled-font form-control form-control-sm" type="text" id="item-name-choice" name="item-name-choice" placeholder="Item name (case insensitive)"/>
|
<input class = "col border-dark text-light dark-5 rounded scaled-font form-control form-control-sm" style="width: 100%!important;" type="text" id="item-name-choice" name="item-name-choice" placeholder="Item name (case insensitive)"/>
|
||||||
<p class="error col"></p>
|
|
||||||
</div>
|
|
||||||
<div class = "col-lg-3 col-sm-12">
|
|
||||||
<div class = "col fw-bold">Category:</div>
|
|
||||||
<input class="col border-dark text-light dark-5 rounded scaled-font form-control form-control-sm" id="item-category-choice" name="item-category-choice" placeholder="ALL"/>
|
|
||||||
<datalist id="category-items">
|
|
||||||
<option value="ALL">
|
|
||||||
<option value="armor">
|
|
||||||
<option value="helmet">
|
|
||||||
<option value="chestplate">
|
|
||||||
<option value="leggings">
|
|
||||||
<option value="boots">
|
|
||||||
<option value="accessory">
|
|
||||||
<option value="ring">
|
|
||||||
<option value="bracelet">
|
|
||||||
<option value="necklace">
|
|
||||||
<option value="weapon">
|
|
||||||
<option value="wand">
|
|
||||||
<option value="spear">
|
|
||||||
<option value="bow">
|
|
||||||
<option value="dagger">
|
|
||||||
<option value="relik">
|
|
||||||
</datalist>
|
|
||||||
<p class="error"></p>
|
|
||||||
</div>
|
|
||||||
<div class = "col-lg-3 col-sm-12">
|
|
||||||
<div class = "col fw-bold">Rarity:</div>
|
|
||||||
<input class = "border-dark text-light dark-5 rounded scaled-font form-control form-control-sm" id="item-rarity-choice" name="item-rarity-choice" placeholder="ANY"/>
|
|
||||||
<datalist id = "rarity-items">
|
|
||||||
<option value="ANY">
|
|
||||||
<option value="Normal">
|
|
||||||
<option value="Unique">
|
|
||||||
<option value="Set">
|
|
||||||
<option value="Rare">
|
|
||||||
<option value="Legendary">
|
|
||||||
<option value="Fabled">
|
|
||||||
<option value="Mythic">
|
|
||||||
<option value="Sane">
|
|
||||||
</datalist>
|
|
||||||
<p class="error col-auto"></p>
|
|
||||||
</div>
|
|
||||||
<div class = "col-lg-3 col-sm-12">
|
|
||||||
<div class = "col fw-bold">Level Range:</div>
|
|
||||||
<input class = "border-dark text-light dark-5 rounded scaled-font form-control form-control-sm" type="text" id="item-level-choice" name="item-level-choice" placeholder = "1-106"/>
|
|
||||||
<p class="error col-auto"></p>
|
<p class="error col-auto"></p>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class = "row">
|
<div class = "row">
|
||||||
<div class = "col-lg-3 col-sm-12">
|
<div class = "col-lg col-sm-12">
|
||||||
<div class = "col fw-bold">Filter 1:</div>
|
<div class = "col"><span class = "fw-bold">Type:</span> <span style = "cursor: pointer; float: right;"><span id = "all-types">All</span> <span id = "none-types">None</span></span></div>
|
||||||
<input class = "border-dark text-light dark-5 rounded scaled-font form-control form-control-sm" id="filter1-choice" name="filter1-choice" placeholder="ANY"/>
|
<div id = "type-box">
|
||||||
|
<div class = "item-display-new-toggleable" style = "background-image: url('../media/items/new.png'); background-position: 0 0;" id = "type-bow"></div>
|
||||||
|
<div class = "item-display-new-toggleable" style = "background-image: url('../media/items/new.png'); background-position: 9.09091% 0;" id = "type-spear"></div>
|
||||||
|
<div class = "item-display-new-toggleable" style = "background-image: url('../media/items/new.png'); background-position: 18.1818% 0;" id = "type-wand"></div>
|
||||||
|
<div class = "item-display-new-toggleable" style = "background-image: url('../media/items/new.png'); background-position: 27.2727% 0;" id = "type-dagger"></div>
|
||||||
|
<div class = "item-display-new-toggleable" style = "background-image: url('../media/items/new.png'); background-position: 36.3636% 0;" id = "type-relik"></div>
|
||||||
|
<div class = "item-display-new-toggleable" style = "background-image: url('../media/items/new.png'); background-position: 45.4545% 0;" id = "type-helmet"></div>
|
||||||
|
<div class = "item-display-new-toggleable" style = "background-image: url('../media/items/new.png'); background-position: 54.5455% 0;" id = "type-chestplate"></div>
|
||||||
|
<div class = "item-display-new-toggleable" style = "background-image: url('../media/items/new.png'); background-position: 63.6364% 0;" id = "type-leggings"></div>
|
||||||
|
<div class = "item-display-new-toggleable" style = "background-image: url('../media/items/new.png'); background-position: 72.7273% 0;" id = "type-boots"></div>
|
||||||
|
<div class = "item-display-new-toggleable" style = "background-image: url('../media/items/new.png'); background-position: 81.8182% 0;" id = "type-ring"></div>
|
||||||
|
<div class = "item-display-new-toggleable" style = "background-image: url('../media/items/new.png'); background-position: 90.9091% 0;" id = "type-bracelet"></div>
|
||||||
|
<div class = "item-display-new-toggleable" style = "background-image: url('../media/items/new.png'); background-position: 100% 0;" id = "type-necklace"></div>
|
||||||
|
</div>
|
||||||
<p class="error col-auto"></p>
|
<p class="error col-auto"></p>
|
||||||
</div>
|
</div>
|
||||||
<div class = "col-lg-3 col-sm-12">
|
|
||||||
<div class = "col fw-bold">Filter 2:</div>
|
|
||||||
<input class = "border-dark text-light dark-5 rounded scaled-font form-control form-control-sm" id="filter2-choice" name="filter2-choice" placeholder="ANY"/>
|
|
||||||
<p class="error col-auto"></p>
|
|
||||||
</div>
|
|
||||||
<div class = "col-lg-3 col-sm-12">
|
|
||||||
<div class = "col fw-bold">Filter 3:</div>
|
|
||||||
<input class = "border-dark text-light dark-5 rounded scaled-font form-control form-control-sm" id="filter3-choice" name="filter3-choice" placeholder="ANY"/>
|
|
||||||
<p class="error col-auto"></p>
|
|
||||||
</div>
|
|
||||||
<div class = "col-lg-3 col-sm-12">
|
|
||||||
<div class = "col fw-bold">Filter 4:</div>
|
|
||||||
<input class = "border-dark text-light dark-5 rounded scaled-font form-control form-control-sm" id="filter4-choice" name="filter4-choice" placeholder="ANY"/>
|
|
||||||
<p class="error col-auto"></p>
|
|
||||||
</div>
|
|
||||||
<datalist id = "filter-items"></datalist>
|
|
||||||
</div>
|
</div>
|
||||||
<div class = "row">
|
<div class = "row">
|
||||||
|
<div class = "col-lg col-sm-12">
|
||||||
|
<div class = "col"><span class = "fw-bold">Rarity:</span> <span style = "cursor: pointer; float: right;"><span id = "all-rarities">All</span> <span id = "none-rarities">None</span></span></div>
|
||||||
|
<div id = "rarity-box">
|
||||||
|
<!-- unfortunately they must be stacked up like this because newlines are considered spaces and muck up the organization -->
|
||||||
|
<div id = "rarity-normal" class = "rarity-selected"><b>N</b></div><div id = "rarity-unique" class = "rarity-selected"><b>U</b></div><div id = "rarity-set" class = "rarity-selected"><b>S</b></div><div id = "rarity-rare" class = "rarity-selected"><b>R</b></div><div id = "rarity-legendary" class = "rarity-selected"><b>L</b></div><div id = "rarity-fabled" class = "rarity-selected"><b>F</b></div><div id = "rarity-mythic" class = "rarity-selected"><b>M</b></div>
|
||||||
|
</div>
|
||||||
|
<p class="error col-auto"></p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class = "col-lg-5">
|
||||||
|
<div id = "filter-container" class = "col">
|
||||||
|
<div class = "col fw-bold">Filters:</div>
|
||||||
|
<div class = "row">
|
||||||
|
<div id = "add-filter" class = "col fw-bold" style = "cursor: pointer; padding-top: 5px;">
|
||||||
|
+ Add Filter
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<br/>
|
||||||
|
<div id = "exclude-container" class = "col">
|
||||||
|
<div class = "col fw-bold">Excluded Filters:</div>
|
||||||
|
<div class = "row">
|
||||||
|
<div id = "add-exclude" class = "col fw-bold" style = "cursor: pointer; padding-top: 5px;">
|
||||||
|
+ Add Excluded Filter
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class = "row">
|
||||||
|
<div class = "col-auto" style = "width: 12.5%;"></div>
|
||||||
<div class = "col-auto">
|
<div class = "col-auto">
|
||||||
<button class = "button rounded scaled-font fw-bold text-light dark-5" id = "search-button" onclick = "doItemSearch()">
|
<button class = "button rounded scaled-font fw-bold text-light dark-5" id = "search-button" onclick = "do_item_search()">
|
||||||
Search!
|
Search!
|
||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
<div class = "col-auto">
|
<div class = "col-auto">
|
||||||
<button class = "button rounded scaled-font fw-bold text-light dark-5" id = "reset-button" onclick = "resetItemSearch()">
|
<button class = "button rounded scaled-font fw-bold text-light dark-5" id = "reset-button" onclick = "reset_item_search()">
|
||||||
Reset
|
Reset
|
||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
|
||||||
<div class = "row box-title justify-content-center" id = "summary">
|
<div class = "row box-title justify-content-center" id = "summary">
|
||||||
</div>
|
</div>
|
||||||
<div class = "row" id = "search-results">
|
<div class = "row" id = "search-results">
|
||||||
|
@ -134,6 +162,7 @@
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<script src="https://cdn.jsdelivr.net/npm/@tarekraafat/autocomplete.js@10.2.6/dist/autoComplete.min.js"></script>
|
<script src="https://cdn.jsdelivr.net/npm/@tarekraafat/autocomplete.js@10.2.6/dist/autoComplete.min.js"></script>
|
||||||
|
<script type="text/javascript" src="../js/drag_drop_touch.js"></script>
|
||||||
<script type="text/javascript" src="../js/utils.js"></script>
|
<script type="text/javascript" src="../js/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>
|
||||||
|
@ -141,10 +170,9 @@
|
||||||
<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/query_2.js"></script>
|
|
||||||
<script type="text/javascript" src="../js/expr_parser.js"></script>
|
<script type="text/javascript" src="../js/expr_parser.js"></script>
|
||||||
<script type="text/javascript" src="../js/load.js"></script>
|
<script type="text/javascript" src="../js/load.js"></script>
|
||||||
<script type="text/javascript" src="../js/sq2items.js"></script>
|
<script type="text/javascript" src="../js/items.js"></script>
|
||||||
<script type="text/javascript" src="../js/powders.js"></script>
|
<script type="text/javascript" src="../js/powders.js"></script>
|
||||||
</body>
|
</body>
|
||||||
</html>
|
</html>
|
||||||
|
|
|
@ -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_2.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>
|
||||||
|
|
|
@ -221,6 +221,6 @@
|
||||||
docsFns.append(genDocEntry(entry[0], entry[1], null, entry[2]));
|
docsFns.append(genDocEntry(entry[0], entry[1], null, entry[2]));
|
||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
<script type="text/javascript" src="../js/sq2icons.js"></script>
|
<script type="text/javascript" src="../js/icons.js"></script>
|
||||||
</body>
|
</body>
|
||||||
</html>
|
</html>
|
|
@ -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
|
|
|
@ -1,3 +1,7 @@
|
||||||
|
/**
|
||||||
|
* File containing utility functions that are useful for the builder page.
|
||||||
|
*/
|
||||||
|
|
||||||
/*Turns the input amount of skill points into a float precision percentage.
|
/*Turns the input amount of skill points into a float precision percentage.
|
||||||
* @param skp - the integer skillpoint count to be converted
|
* @param skp - the integer skillpoint count to be converted
|
||||||
*/
|
*/
|
||||||
|
@ -8,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);
|
||||||
|
@ -66,7 +70,7 @@ const tiers = ["Normal", "Unique", "Rare", "Legendary", "Fabled", "Mythic", "Set
|
||||||
const all_types = armorTypes.concat(accessoryTypes).concat(weaponTypes).concat(consumableTypes).concat(tome_types).map(x => x.substring(0,1).toUpperCase() + x.substring(1));
|
const all_types = armorTypes.concat(accessoryTypes).concat(weaponTypes).concat(consumableTypes).concat(tome_types).map(x => x.substring(0,1).toUpperCase() + x.substring(1));
|
||||||
//weaponTypes.push("sword");
|
//weaponTypes.push("sword");
|
||||||
//console.log(types)
|
//console.log(types)
|
||||||
let itemTypes = armorTypes.concat(accessoryTypes).concat(weaponTypes).concat(tome_types);
|
let item_types = armorTypes.concat(accessoryTypes).concat(weaponTypes).concat(tome_types);
|
||||||
|
|
||||||
let elementIcons = ["\u2724","\u2726", "\u2749", "\u2739", "\u274b" ];
|
let elementIcons = ["\u2724","\u2726", "\u2749", "\u2739", "\u274b" ];
|
||||||
let skpReqs = skp_order.map(x => x + "Req");
|
let skpReqs = skp_order.map(x => x + "Req");
|
||||||
|
@ -82,14 +86,16 @@ 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" ]
|
||||||
|
|
||||||
//File reading for ID translations for JSON purposes
|
//File reading for ID translations for JSON purposes
|
||||||
let reversetranslations = new Map();
|
let reversetranslations = new Map();
|
||||||
let translations = new Map([["name", "name"], ["displayName", "displayName"], ["tier", "tier"], ["set", "set"], ["sockets", "slots"], ["type", "type"], ["dropType", "drop"], ["quest", "quest"], ["restrictions", "restrict"], ["damage", "nDam"], ["fireDamage", "fDam"], ["waterDamage", "wDam"], ["airDamage", "aDam"], ["thunderDamage", "tDam"], ["earthDamage", "eDam"], ["attackSpeed", "atkSpd"], ["health", "hp"], ["fireDefense", "fDef"], ["waterDefense", "wDef"], ["airDefense", "aDef"], ["thunderDefense", "tDef"], ["earthDefense", "eDef"], ["level", "lvl"], ["classRequirement", "classReq"], ["strength", "strReq"], ["dexterity", "dexReq"], ["intelligence", "intReq"], ["agility", "agiReq"], ["defense", "defReq"], ["healthRegen", "hprPct"], ["manaRegen", "mr"], ["spellDamage", "sdPct"], ["damageBonus", "mdPct"], ["lifeSteal", "ls"], ["manaSteal", "ms"], ["xpBonus", "xpb"], ["lootBonus", "lb"], ["reflection", "ref"], ["strengthPoints", "str"], ["dexterityPoints", "dex"], ["intelligencePoints", "int"], ["agilityPoints", "agi"], ["defensePoints", "def"], ["thorns", "thorns"], ["exploding", "expd"], ["speed", "spd"], ["attackSpeedBonus", "atkTier"], ["poison", "poison"], ["healthBonus", "hpBonus"], ["soulPoints", "spRegen"], ["emeraldStealing", "eSteal"], ["healthRegenRaw", "hprRaw"], ["spellDamageRaw", "sdRaw"], ["damageBonusRaw", "mdRaw"], ["bonusFireDamage", "fDamPct"], ["bonusWaterDamage", "wDamPct"], ["bonusAirDamage", "aDamPct"], ["bonusThunderDamage", "tDamPct"], ["bonusEarthDamage", "eDamPct"], ["bonusFireDefense", "fDefPct"], ["bonusWaterDefense", "wDefPct"], ["bonusAirDefense", "aDefPct"], ["bonusThunderDefense", "tDefPct"], ["bonusEarthDefense", "eDefPct"], ["type", "type"], ["identified", "fixID"], ["skin", "skin"], ["category", "category"], ["spellCostPct1", "spPct1"], ["spellCostRaw1", "spRaw1"], ["spellCostPct2", "spPct2"], ["spellCostRaw2", "spRaw2"], ["spellCostPct3", "spPct3"], ["spellCostRaw3", "spRaw3"], ["spellCostPct4", "spPct4"], ["spellCostRaw4", "spRaw4"], ["rainbowSpellDamageRaw", "rSdRaw"], ["sprint", "sprint"], ["sprintRegen", "sprintReg"], ["jumpHeight", "jh"], ["lootQuality", "lq"], ["gatherXpBonus", "gXp"], ["gatherSpeed", "gSpd"]]);
|
let translations = new Map([["name", "name"],["displayName", "displayName"],["tier", "tier"],["set", "set"],["sockets", "slots"],["type", "type"],["armorColor", "color"],["addedLore", "lore"],["dropType", "drop"],["quest", "quest"],["restrictions", "restrict"],["damage", "nDam"],["fireDamage", "fDam"],["waterDamage", "wDam"],["airDamage", "aDam"],["thunderDamage", "tDam"],["earthDamage", "eDam"],["attackSpeed", "atkSpd"],["health", "hp"],["fireDefense", "fDef"],["waterDefense", "wDef"],["airDefense", "aDef"],["thunderDefense", "tDef"],["earthDefense", "eDef"],["level", "lvl"],["classRequirement", "classReq"],["strength", "strReq"],["dexterity", "dexReq"],["intelligence", "intReq"],["agility", "agiReq"],["defense", "defReq"],["healthRegen", "hprPct"],["manaRegen", "mr"],["spellDamageBonus", "sdPct"],["spellElementalDamageBonus", "rSdPct"],["spellNeutralDamageBonus", "nSdPct"],["spellFireDamageBonus", "fSdPct"],["spellWaterDamageBonus", "wSdPct"],["spellAirDamageBonus", "aSdPct"],["spellThunderDamageBonus", "tSdPct"],["spellEarthDamageBonus", "eSdPct"],["mainAttackDamageBonus", "mdPct"],["mainAttackElementalDamageBonus", "rMdPct"],["mainAttackNeutralDamageBonus", "nMdPct"],["mainAttackFireDamageBonus", "fMdPct"],["mainAttackWaterDamageBonus", "wMdPct"],["mainAttackAirDamageBonus", "aMdPct"],["mainAttackThunderDamageBonus", "tMdPct"],["mainAttackEarthDamageBonus", "eMdPct"],["lifeSteal", "ls"],["manaSteal", "ms"],["xpBonus", "xpb"],["lootBonus", "lb"],["reflection", "ref"],["strengthPoints", "str"],["dexterityPoints", "dex"],["intelligencePoints", "int"],["agilityPoints", "agi"],["defensePoints", "def"],["thorns", "thorns"],["exploding", "expd"],["speed", "spd"],["attackSpeedBonus", "atkTier"],["poison", "poison"],["healthBonus", "hpBonus"],["soulPoints", "spRegen"],["emeraldStealing", "eSteal"],["healthRegenRaw", "hprRaw"],["spellDamageBonusRaw", "sdRaw"],["spellElementalDamageBonusRaw", "rSdRaw"],["spellNeutralDamageBonusRaw", "nSdRaw"],["spellFireDamageBonusRaw", "fSdRaw"],["spellWaterDamageBonusRaw", "wSdRaw"],["spellAirDamageBonusRaw", "aSdRaw"],["spellThunderDamageBonusRaw", "tSdRaw"],["spellEarthDamageBonusRaw", "eSdRaw"],["mainAttackDamageBonusRaw", "mdRaw"],["mainAttackElementalDamageBonusRaw", "rMdRaw"],["mainAttackNeutralDamageBonusRaw", "nMdRaw"],["mainAttackFireDamageBonusRaw", "fMdRaw"],["mainAttackWaterDamageBonusRaw", "wMdRaw"],["mainAttackAirDamageBonusRaw", "aMdRaw"],["mainAttackThunderDamageBonusRaw", "tMdRaw"],["mainAttackEarthDamageBonusRaw", "eMdRaw"],["fireDamageBonus", "fDamPct"],["waterDamageBonus", "wDamPct"],["airDamageBonus", "aDamPct"],["thunderDamageBonus", "tDamPct"],["earthDamageBonus", "eDamPct"],["bonusFireDefense", "fDefPct"],["bonusWaterDefense", "wDefPct"],["bonusAirDefense", "aDefPct"],["bonusThunderDefense", "tDefPct"],["bonusEarthDefense", "eDefPct"],["accessoryType", "type"],["identified", "fixID"],["skin", "skin"],["category", "category"],["spellCostPct1", "spPct1"],["spellCostRaw1", "spRaw1"],["spellCostPct2", "spPct2"],["spellCostRaw2", "spRaw2"],["spellCostPct3", "spPct3"],["spellCostRaw3", "spRaw3"],["spellCostPct4", "spPct4"],["spellCostRaw4", "spRaw4"],["sprint", "sprint"],["sprintRegen", "sprintReg"],["jumpHeight", "jh"],["lootQuality", "lq"],["gatherXpBonus", "gXp"],["gatherSpeed", "gSpd"]]);
|
||||||
|
|
||||||
//does not include damMobs (wep tomes) and defMobs (armor tomes)
|
//does not include damMobs (wep tomes) and defMobs (armor tomes)
|
||||||
for (const [k, v] of translations) {
|
for (const [k, v] of translations) {
|
||||||
reversetranslations.set(v, k);
|
reversetranslations.set(v, k);
|
||||||
|
@ -123,16 +129,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",
|
||||||
|
@ -161,7 +158,7 @@ let rolledIDs = [
|
||||||
"spPct2", "spRaw2",
|
"spPct2", "spRaw2",
|
||||||
"spPct3", "spRaw3",
|
"spPct3", "spRaw3",
|
||||||
"spPct4", "spRaw4",
|
"spPct4", "spRaw4",
|
||||||
"pDamRaw",
|
"rSdRaw",
|
||||||
"sprint",
|
"sprint",
|
||||||
"sprintReg",
|
"sprintReg",
|
||||||
"jh",
|
"jh",
|
||||||
|
@ -176,7 +173,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" ];
|
||||||
|
|
||||||
|
@ -199,7 +197,7 @@ function expandItem(item) {
|
||||||
let val = (item[id] || 0);
|
let val = (item[id] || 0);
|
||||||
if (val > 0) { // positive rolled IDs
|
if (val > 0) { // positive rolled IDs
|
||||||
if (reversedIDs.includes(id)) {
|
if (reversedIDs.includes(id)) {
|
||||||
maxRolls.set(id,idRound(val*0.3));
|
maxRolls.set(id,idRound(val*0.7));
|
||||||
minRolls.set(id,idRound(val*1.3));
|
minRolls.set(id,idRound(val*1.3));
|
||||||
} else {
|
} else {
|
||||||
maxRolls.set(id,idRound(val*1.3));
|
maxRolls.set(id,idRound(val*1.3));
|
||||||
|
@ -208,7 +206,7 @@ function expandItem(item) {
|
||||||
} else if (val < 0) { //negative rolled IDs
|
} else if (val < 0) { //negative rolled IDs
|
||||||
if (reversedIDs.includes(id)) {
|
if (reversedIDs.includes(id)) {
|
||||||
maxRolls.set(id,idRound(val*1.3));
|
maxRolls.set(id,idRound(val*1.3));
|
||||||
minRolls.set(id,idRound(val*0.7));
|
minRolls.set(id,idRound(val*0.3));
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
maxRolls.set(id,idRound(val*0.7));
|
maxRolls.set(id,idRound(val*0.7));
|
||||||
|
@ -231,8 +229,15 @@ function expandItem(item) {
|
||||||
}
|
}
|
||||||
|
|
||||||
class Item {
|
class Item {
|
||||||
constructor(item_obj) {
|
constructor(item_obj = null) {
|
||||||
this.statMap = expandItem(item_obj);
|
if (item_obj) { this.statMap = expandItem(item_obj); }
|
||||||
|
else { this.statMap = new Map(); }
|
||||||
|
}
|
||||||
|
|
||||||
|
copy() {
|
||||||
|
const ret = new Item();
|
||||||
|
ret.statMap = new Map(this.statMap);
|
||||||
|
return ret;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
6
js/builder/README_atree_constants.md
Normal 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
|
1
js/builder/atree_constants_min.js
Normal file
|
@ -1,6 +1,11 @@
|
||||||
|
/**
|
||||||
|
* This file defines a class representing the player Build.
|
||||||
|
*
|
||||||
|
* Keeps track of equipment list, equip order, skillpoint assignment (initial),
|
||||||
|
* Aggregates item stats into a statMap to be used in damage calculation.
|
||||||
|
*/
|
||||||
|
|
||||||
|
const classDefenseMultipliers = new Map([ ["relik",0.60], ["bow",0.70], ["wand", 0.80], ["dagger", 1.0], ["spear", 1.0]]);
|
||||||
const classDefenseMultipliers = new Map([ ["relik",0.50], ["bow",0.60], ["wand", 0.80], ["dagger", 1.0], ["spear",1.0], ["sword", 1.10]]);
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Class that represents a wynn player's build.
|
* Class that represents a wynn player's build.
|
||||||
|
@ -10,16 +15,11 @@ class Build{
|
||||||
/**
|
/**
|
||||||
* @description Construct a build.
|
* @description Construct a build.
|
||||||
* @param {Number} level : Level of the player.
|
* @param {Number} level : Level of the player.
|
||||||
* @param {String[]} equipment : List of equipment names that make up the build.
|
* @param {String[]} items: List of equipment names that make up the build.
|
||||||
* In order: boots, Chestplate, Leggings, Boots, Ring1, Ring2, Brace, Neck
|
* In order: Helmet, Chestplate, Leggings, Boots, Ring1, Ring2, Brace, Neck, Tomes [x7].
|
||||||
*
|
* @param {Item} weapon: Weapon that this build is using.
|
||||||
* @param {Object[]} tomes: List of tomes.
|
|
||||||
* In order: 2x Weapon Mastery Tome, 4x Armor Mastery Tome, 1x Guild Tome.
|
|
||||||
* 2x Slaying Mastery Tome, 2x Dungeoneering Mastery Tome, 2x Gathering Mastery Tome are in game, but do not have "useful" stats (those that affect damage calculations or building)
|
|
||||||
*
|
|
||||||
* @param {Object} weapon: Weapon.
|
|
||||||
*/
|
*/
|
||||||
constructor(level, equipment, tomes, weapon){
|
constructor(level, items, weapon){
|
||||||
if (level < 1) { //Should these be constants?
|
if (level < 1) { //Should these be constants?
|
||||||
this.level = 1;
|
this.level = 1;
|
||||||
} else if (level > 106) {
|
} else if (level > 106) {
|
||||||
|
@ -34,15 +34,18 @@ class Build{
|
||||||
document.getElementById("level-choice").value = this.level;
|
document.getElementById("level-choice").value = this.level;
|
||||||
|
|
||||||
this.availableSkillpoints = levelToSkillPoints(this.level);
|
this.availableSkillpoints = levelToSkillPoints(this.level);
|
||||||
this.equipment = equipment;
|
this.equipment = items;
|
||||||
this.tomes = tomes;
|
|
||||||
this.weapon = weapon;
|
this.weapon = weapon;
|
||||||
this.items = this.equipment.concat(tomes, [this.weapon]);
|
this.items = this.equipment.concat([this.weapon]);
|
||||||
// return [equip_order, best_skillpoints, final_skillpoints, best_total];
|
|
||||||
|
|
||||||
// calc skillpoints requires statmaps only
|
// calc skillpoints requires statmaps only
|
||||||
let result = calculate_skillpoints(this.equipment.map((x) => x.statMap), this.weapon.statMap);
|
let result = calculate_skillpoints(this.equipment.map((x) => x.statMap), this.weapon.statMap);
|
||||||
this.equip_order = result[0];
|
const _equip_order = result[0].slice();
|
||||||
|
this.equip_order = [];
|
||||||
|
for (const item of _equip_order) {
|
||||||
|
if (item.get('category') === 'tome' || item.has('NONE')) { continue; }
|
||||||
|
this.equip_order.push(item);
|
||||||
|
}
|
||||||
// How many skillpoints the player had to assign (5 number)
|
// How many skillpoints the player had to assign (5 number)
|
||||||
this.base_skillpoints = result[1];
|
this.base_skillpoints = result[1];
|
||||||
// How many skillpoints the build ended up with (5 number)
|
// How many skillpoints the build ended up with (5 number)
|
||||||
|
@ -60,7 +63,6 @@ class Build{
|
||||||
return [this.equipment,this.weapon].flat();
|
return [this.equipment,this.weapon].flat();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/* Get all stats for this build. Stores in this.statMap.
|
/* Get all stats for this build. Stores in this.statMap.
|
||||||
@pre The build itself should be valid. No checking of validity of pieces is done here.
|
@pre The build itself should be valid. No checking of validity of pieces is done here.
|
||||||
*/
|
*/
|
||||||
|
@ -126,9 +128,9 @@ class Build{
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
statMap.set("poisonPct", 100);
|
statMap.set("poisonPct", 0);
|
||||||
statMap.set("critDamPct", 100);
|
statMap.set("critDamPct", 0);
|
||||||
statMap.set("healPct", 100);
|
statMap.set("healPct", 0);
|
||||||
|
|
||||||
// The stuff relevant for damage calculation!!! @ferricles
|
// The stuff relevant for damage calculation!!! @ferricles
|
||||||
statMap.set("atkSpd", this.weapon.statMap.get("atkSpd"));
|
statMap.set("atkSpd", this.weapon.statMap.get("atkSpd"));
|
|
@ -1,3 +1,6 @@
|
||||||
|
/**
|
||||||
|
* File containing utility functions relevant to the builder page, as well as the setup code (at the very bottom).
|
||||||
|
*/
|
||||||
|
|
||||||
function populateBuildList() {
|
function populateBuildList() {
|
||||||
const buildList = document.getElementById("build-choice");
|
const buildList = document.getElementById("build-choice");
|
||||||
|
@ -44,6 +47,8 @@ function loadBuild() {
|
||||||
let saveName = document.getElementById("build-name").value;
|
let saveName = document.getElementById("build-name").value;
|
||||||
|
|
||||||
if (Object.keys(savedBuilds).includes(saveName)) {
|
if (Object.keys(savedBuilds).includes(saveName)) {
|
||||||
|
// NOTE: this is broken since decodeBuild is async func.
|
||||||
|
// Doubly broken because of versioning... lets just kill this for now
|
||||||
decodeBuild(savedBuilds[saveName])
|
decodeBuild(savedBuilds[saveName])
|
||||||
document.getElementById("loaded-error").textContent = "";
|
document.getElementById("loaded-error").textContent = "";
|
||||||
document.getElementById("loaded-build").textContent = "Build loaded";
|
document.getElementById("loaded-build").textContent = "Build loaded";
|
||||||
|
@ -60,6 +65,9 @@ function resetFields(){
|
||||||
for (const i of equipment_inputs) {
|
for (const i of equipment_inputs) {
|
||||||
setValue(i, "");
|
setValue(i, "");
|
||||||
}
|
}
|
||||||
|
for (const i of tomeInputs) {
|
||||||
|
setValue(i, "");
|
||||||
|
}
|
||||||
setValue("str-skp", "0");
|
setValue("str-skp", "0");
|
||||||
setValue("dex-skp", "0");
|
setValue("dex-skp", "0");
|
||||||
setValue("int-skp", "0");
|
setValue("int-skp", "0");
|
||||||
|
@ -124,34 +132,6 @@ function toggleButton(button_id) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// toggle tab
|
|
||||||
function toggle_tab(tab) {
|
|
||||||
if (document.querySelector("#"+tab).style.display == "none") {
|
|
||||||
document.querySelector("#"+tab).style.display = "";
|
|
||||||
} else {
|
|
||||||
document.querySelector("#"+tab).style.display = "none";
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
function toggle_boost_tab(tab) {
|
|
||||||
for (const i of skp_order) {
|
|
||||||
document.querySelector("#"+i+"-boost").style.display = "none";
|
|
||||||
document.getElementById(i + "-boost-tab").classList.remove("selected-btn");
|
|
||||||
}
|
|
||||||
document.querySelector("#"+tab+"-boost").style.display = "";
|
|
||||||
document.getElementById(tab + "-boost-tab").classList.add("selected-btn");
|
|
||||||
}
|
|
||||||
|
|
||||||
let tabs = ['overall-stats', 'offensive-stats', 'defensive-stats'];
|
|
||||||
function show_tab(tab) {
|
|
||||||
//hide all tabs, then show the tab of the div clicked and highlight the correct button
|
|
||||||
for (const i in tabs) {
|
|
||||||
document.querySelector("#" + tabs[i]).style.display = "none";
|
|
||||||
document.getElementById("tab-" + tabs[i].split("-")[0] + "-btn").classList.remove("selected-btn");
|
|
||||||
}
|
|
||||||
document.querySelector("#" + tab).style.display = "";
|
|
||||||
document.getElementById("tab-" + tab.split("-")[0] + "-btn").classList.add("selected-btn");
|
|
||||||
}
|
|
||||||
|
|
||||||
// autocomplete initialize
|
// autocomplete initialize
|
||||||
function init_autocomplete() {
|
function init_autocomplete() {
|
||||||
|
@ -239,8 +219,9 @@ function init_autocomplete() {
|
||||||
for (const eq of tome_keys) {
|
for (const eq of tome_keys) {
|
||||||
// build dropdown
|
// build dropdown
|
||||||
let tome_arr = [];
|
let tome_arr = [];
|
||||||
for (const tome of tomeLists.get(eq.replace(/[0-9]/g, ''))) {
|
let tome_aliases = new Map();
|
||||||
let tome_obj = tomeMap.get(tome);
|
for (const tome_name of tomeLists.get(eq.replace(/[0-9]/g, ''))) {
|
||||||
|
let tome_obj = tomeMap.get(tome_name);
|
||||||
if (tome_obj["restrict"] && tome_obj["restrict"] === "DEPRECATED") {
|
if (tome_obj["restrict"] && tome_obj["restrict"] === "DEPRECATED") {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
@ -248,8 +229,10 @@ function init_autocomplete() {
|
||||||
if (tome_obj["name"].includes('No ' + eq.charAt(0).toUpperCase())) {
|
if (tome_obj["name"].includes('No ' + eq.charAt(0).toUpperCase())) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
let tome_name = tome;
|
let tome_alias = tome_obj['alias'];
|
||||||
tome_arr.push(tome_name);
|
tome_arr.push(tome_name);
|
||||||
|
tome_arr.push(tome_alias);
|
||||||
|
tome_aliases.set(tome_alias, tome_name);
|
||||||
}
|
}
|
||||||
|
|
||||||
// create dropdown
|
// create dropdown
|
||||||
|
@ -284,14 +267,18 @@ function init_autocomplete() {
|
||||||
class: "scaled-font search-item",
|
class: "scaled-font search-item",
|
||||||
selected: "dark-5",
|
selected: "dark-5",
|
||||||
element: (tome, data) => {
|
element: (tome, data) => {
|
||||||
tome.classList.add(tomeMap.get(data.value).tier);
|
let val = data.value;
|
||||||
|
if (tome_aliases.has(val)) { val = tome_aliases.get(val); }
|
||||||
|
tome.classList.add(tomeMap.get(val).tier);
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
events: {
|
events: {
|
||||||
input: {
|
input: {
|
||||||
selection: (event) => {
|
selection: (event) => {
|
||||||
if (event.detail.selection.value) {
|
if (event.detail.selection.value) {
|
||||||
event.target.value = event.detail.selection.value;
|
let val = event.detail.selection.value;
|
||||||
|
if (tome_aliases.has(val)) { val = tome_aliases.get(val); }
|
||||||
|
event.target.value = val;
|
||||||
}
|
}
|
||||||
event.target.dispatchEvent(new Event('change'));
|
event.target.dispatchEvent(new Event('change'));
|
||||||
},
|
},
|
||||||
|
@ -320,9 +307,8 @@ function collapse_element(elmnt) {
|
||||||
document.querySelector(elmnt).style.removeProperty('display');
|
document.querySelector(elmnt).style.removeProperty('display');
|
||||||
}
|
}
|
||||||
|
|
||||||
function init() {
|
async function init() {
|
||||||
console.log("builder.js init");
|
console.log("builder.js init");
|
||||||
init_autocomplete();
|
|
||||||
|
|
||||||
// Other "main" stuff
|
// Other "main" stuff
|
||||||
// Spell dropdowns
|
// Spell dropdowns
|
||||||
|
@ -344,6 +330,7 @@ function init() {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Masonry setup
|
// Masonry setup
|
||||||
|
try {
|
||||||
let masonry = Macy({
|
let masonry = Macy({
|
||||||
container: "#masonry-container",
|
container: "#masonry-container",
|
||||||
columns: 1,
|
columns: 1,
|
||||||
|
@ -355,7 +342,6 @@ function init() {
|
||||||
x: 20,
|
x: 20,
|
||||||
y: 20,
|
y: 20,
|
||||||
}
|
}
|
||||||
|
|
||||||
});
|
});
|
||||||
|
|
||||||
let search_masonry = Macy({
|
let search_masonry = Macy({
|
||||||
|
@ -369,9 +355,16 @@ function init() {
|
||||||
x: 20,
|
x: 20,
|
||||||
y: 20,
|
y: 20,
|
||||||
}
|
}
|
||||||
|
|
||||||
});
|
});
|
||||||
decodeBuild(url_tag);
|
} catch (e) {
|
||||||
|
console.log("Could not initialize macy components. Maybe you're offline?");
|
||||||
|
}
|
||||||
|
await parse_hash(url_tag);
|
||||||
|
try {
|
||||||
|
init_autocomplete();
|
||||||
|
} catch (e) {
|
||||||
|
console.log("Could not initialize autocomplete. Maybe you're offline?");
|
||||||
|
}
|
||||||
builder_graph_init();
|
builder_graph_init();
|
||||||
for (const item_node of item_nodes) {
|
for (const item_node of item_nodes) {
|
||||||
if (item_node.get_value() === null) {
|
if (item_node.get_value() === null) {
|
||||||
|
@ -379,6 +372,7 @@ function init() {
|
||||||
if (confirm('One or more items failed to load correctly. This could be due to a corrupted build link, or (more likely) a database load failure. Would you like to reload?')) {
|
if (confirm('One or more items failed to load correctly. This could be due to a corrupted build link, or (more likely) a database load failure. Would you like to reload?')) {
|
||||||
hardReload();
|
hardReload();
|
||||||
}
|
}
|
||||||
|
console.log(item_node);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -390,7 +384,5 @@ window.onerror = function(message, source, lineno, colno, error) {
|
||||||
};
|
};
|
||||||
|
|
||||||
(async function() {
|
(async function() {
|
||||||
let load_promises = [ load_init(), load_ing_init(), load_tome_init() ];
|
await init();
|
||||||
await Promise.all(load_promises);
|
|
||||||
init();
|
|
||||||
})();
|
})();
|
|
@ -1,3 +1,7 @@
|
||||||
|
/**
|
||||||
|
* File containing compute graph structure of the builder page.
|
||||||
|
*/
|
||||||
|
|
||||||
let armor_powder_node = new (class extends ComputeNode {
|
let armor_powder_node = new (class extends ComputeNode {
|
||||||
constructor() { super('builder-armor-powder-input'); }
|
constructor() { super('builder-armor-powder-input'); }
|
||||||
|
|
||||||
|
@ -13,6 +17,8 @@ let armor_powder_node = new (class extends ComputeNode {
|
||||||
}
|
}
|
||||||
})();
|
})();
|
||||||
|
|
||||||
|
const damageMultipliers = new Map([ ["totem", 0.2], ["warscream", 0.0], ["ragnarokkr", 0.30], ["fortitude", 0.60], ["radiance", 0.0] ]);
|
||||||
|
|
||||||
let boosts_node = new (class extends ComputeNode {
|
let boosts_node = new (class extends ComputeNode {
|
||||||
constructor() { super('builder-boost-input'); }
|
constructor() { super('builder-boost-input'); }
|
||||||
|
|
||||||
|
@ -23,8 +29,7 @@ let boosts_node = new (class extends ComputeNode {
|
||||||
let elem = document.getElementById(key + "-boost")
|
let elem = document.getElementById(key + "-boost")
|
||||||
if (elem.classList.contains("toggleOn")) {
|
if (elem.classList.contains("toggleOn")) {
|
||||||
damage_boost += value;
|
damage_boost += value;
|
||||||
if (key === "warscream") { def_boost += .10 }
|
if (key === "warscream") { def_boost += .20 }
|
||||||
if (key === "vanish") { def_boost += .15 }
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
let res = new Map();
|
let res = new Map();
|
||||||
|
@ -90,12 +95,10 @@ class PowderSpecialCalcNode extends ComputeNode {
|
||||||
for (const [special, power] of powder_specials) {
|
for (const [special, power] of powder_specials) {
|
||||||
if (special["weaponSpecialEffects"].has("Damage Boost")) {
|
if (special["weaponSpecialEffects"].has("Damage Boost")) {
|
||||||
let name = special["weaponSpecialName"];
|
let name = special["weaponSpecialName"];
|
||||||
if (name === "Courage" || name === "Curse") { //courage and curse are is universal damage boost
|
if (name === "Courage" || name === "Curse" || name == "Wind Prison") { // Master mod all the way
|
||||||
stats.set("sdPct", special.weaponSpecialEffects.get("Damage Boost")[power-1]);
|
stats.set("damMult."+name, special.weaponSpecialEffects.get("Damage Boost")[power-1]);
|
||||||
stats.set("mdPct", special.weaponSpecialEffects.get("Damage Boost")[power-1]);
|
// legacy
|
||||||
stats.set("poisonPct", special.weaponSpecialEffects.get("Damage Boost")[power-1]);
|
stats.set("poisonPct", special.weaponSpecialEffects.get("Damage Boost")[power-1]);
|
||||||
} else if (name === "Wind Prison") {
|
|
||||||
stats.set("aDamPct", special.weaponSpecialEffects.get("Damage Boost")[power-1]);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -121,7 +124,7 @@ class PowderSpecialDisplayNode extends ComputeNode {
|
||||||
/**
|
/**
|
||||||
* Node for getting an item's stats from an item input field.
|
* Node for getting an item's stats from an item input field.
|
||||||
*
|
*
|
||||||
* Signature: ItemInputNode(powdering: Optional[list[powder]]) => Item | null
|
* Signature: ItemInputNode() => Item | null
|
||||||
*/
|
*/
|
||||||
class ItemInputNode extends InputNode {
|
class ItemInputNode extends InputNode {
|
||||||
/**
|
/**
|
||||||
|
@ -143,8 +146,6 @@ class ItemInputNode extends InputNode {
|
||||||
}
|
}
|
||||||
|
|
||||||
compute_func(input_map) {
|
compute_func(input_map) {
|
||||||
const powdering = input_map.get('powdering');
|
|
||||||
|
|
||||||
// built on the assumption of no one will type in CI/CR letter by letter
|
// built on the assumption of no one will type in CI/CR letter by letter
|
||||||
let item_text = this.input_field.value;
|
let item_text = this.input_field.value;
|
||||||
if (!item_text) {
|
if (!item_text) {
|
||||||
|
@ -158,10 +159,6 @@ class ItemInputNode extends InputNode {
|
||||||
else if (tomeMap.has(item_text)) { item = new Item(tomeMap.get(item_text)); }
|
else if (tomeMap.has(item_text)) { item = new Item(tomeMap.get(item_text)); }
|
||||||
|
|
||||||
if (item) {
|
if (item) {
|
||||||
if (powdering !== undefined) {
|
|
||||||
const max_slots = item.statMap.get('slots');
|
|
||||||
item.statMap.set('powders', powdering.slice(0, max_slots));
|
|
||||||
}
|
|
||||||
let type_match;
|
let type_match;
|
||||||
if (this.category == 'weapon') {
|
if (this.category == 'weapon') {
|
||||||
type_match = item.statMap.get('category') == 'weapon';
|
type_match = item.statMap.get('category') == 'weapon';
|
||||||
|
@ -169,12 +166,6 @@ class ItemInputNode extends InputNode {
|
||||||
type_match = item.statMap.get('type') == this.none_item.statMap.get('type');
|
type_match = item.statMap.get('type') == this.none_item.statMap.get('type');
|
||||||
}
|
}
|
||||||
if (type_match) {
|
if (type_match) {
|
||||||
if (item.statMap.get('category') == 'armor') {
|
|
||||||
applyArmorPowders(item.statMap);
|
|
||||||
}
|
|
||||||
else if (item.statMap.get('category') == 'weapon') {
|
|
||||||
apply_weapon_powders(item.statMap);
|
|
||||||
}
|
|
||||||
return item;
|
return item;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -205,6 +196,31 @@ class ItemInputNode extends InputNode {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Node for updating item input fields from parsed items.
|
||||||
|
*
|
||||||
|
* Signature: ItemInputDisplayNode(item: Item, powdering: List[powder]) => Item
|
||||||
|
*/
|
||||||
|
class ItemPowderingNode extends ComputeNode {
|
||||||
|
constructor(name) { super(name); }
|
||||||
|
|
||||||
|
compute_func(input_map) {
|
||||||
|
const powdering = input_map.get('powdering');
|
||||||
|
const input_item = input_map.get('item');
|
||||||
|
const item = input_item.copy(); // TODO: performance
|
||||||
|
|
||||||
|
const max_slots = item.statMap.get('slots');
|
||||||
|
item.statMap.set('powders', powdering.slice(0, max_slots));
|
||||||
|
if (item.statMap.get('category') == 'armor') {
|
||||||
|
applyArmorPowders(item.statMap);
|
||||||
|
}
|
||||||
|
else if (item.statMap.get('category') == 'weapon') {
|
||||||
|
apply_weapon_powders(item.statMap);
|
||||||
|
}
|
||||||
|
return item;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Node for updating item input fields from parsed items.
|
* Node for updating item input fields from parsed items.
|
||||||
*
|
*
|
||||||
|
@ -217,7 +233,6 @@ class ItemInputDisplayNode extends ComputeNode {
|
||||||
this.input_field = document.getElementById(eq+"-choice");
|
this.input_field = document.getElementById(eq+"-choice");
|
||||||
this.health_field = document.getElementById(eq+"-health");
|
this.health_field = document.getElementById(eq+"-health");
|
||||||
this.level_field = document.getElementById(eq+"-lv");
|
this.level_field = document.getElementById(eq+"-lv");
|
||||||
this.powder_field = document.getElementById(eq+"-powder"); // possibly None
|
|
||||||
this.image = item_image;
|
this.image = item_image;
|
||||||
this.fail_cb = true;
|
this.fail_cb = true;
|
||||||
}
|
}
|
||||||
|
@ -242,18 +257,11 @@ class ItemInputDisplayNode extends ComputeNode {
|
||||||
this.input_field.classList.add("is-invalid");
|
this.input_field.classList.add("is-invalid");
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
if (this.powder_field && item.statMap.has('powders')) {
|
|
||||||
this.powder_field.placeholder = "powders";
|
|
||||||
}
|
|
||||||
|
|
||||||
if (item.statMap.has('NONE')) {
|
if (item.statMap.has('NONE')) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (this.powder_field && item.statMap.has('powders')) {
|
|
||||||
this.powder_field.placeholder = item.statMap.get('slots') + ' slots';
|
|
||||||
}
|
|
||||||
|
|
||||||
const tier = item.statMap.get('tier');
|
const tier = item.statMap.get('tier');
|
||||||
this.input_field.classList.add(tier);
|
this.input_field.classList.add(tier);
|
||||||
if (this.health_field) {
|
if (this.health_field) {
|
||||||
|
@ -307,7 +315,8 @@ class WeaponInputDisplayNode extends ComputeNode {
|
||||||
const [item] = input_map.values(); // Extract values, pattern match it into size one list and bind to first element
|
const [item] = input_map.values(); // Extract values, pattern match it into size one list and bind to first element
|
||||||
|
|
||||||
const type = item.statMap.get('type');
|
const type = item.statMap.get('type');
|
||||||
this.image.setAttribute('src', '../media/items/new/generic-'+type+'.png');
|
this.image.style.backgroundPosition = itemBGPositions[type];
|
||||||
|
|
||||||
let dps = get_base_dps(item.statMap);
|
let dps = get_base_dps(item.statMap);
|
||||||
if (isNaN(dps)) {
|
if (isNaN(dps)) {
|
||||||
dps = dps[1];
|
dps = dps[1];
|
||||||
|
@ -374,41 +383,39 @@ class URLUpdateNode extends ComputeNode {
|
||||||
* Create a "build" object from a set of equipments.
|
* Create a "build" object from a set of equipments.
|
||||||
* Returns a new Build object, or null if all items are NONE items.
|
* Returns a new Build object, or null if all items are NONE items.
|
||||||
*
|
*
|
||||||
* Signature: BuildAssembleNode(helmet-input: Item,
|
* Signature: BuildAssembleNode(helmet: Item,
|
||||||
* chestplate-input: Item,
|
* chestplate: Item,
|
||||||
* leggings-input: Item,
|
* leggings: Item,
|
||||||
* boots-input: Item,
|
* boots: Item,
|
||||||
* ring1-input: Item,
|
* ring1: Item,
|
||||||
* ring2-input: Item,
|
* ring2: Item,
|
||||||
* bracelet-input: Item,
|
* bracelet: Item,
|
||||||
* necklace-input: Item,
|
* necklace: Item,
|
||||||
* weapon-input: Item,
|
* weapon: Item,
|
||||||
* level-input: int) => Build | null
|
* level: int) => Build | null
|
||||||
*/
|
*/
|
||||||
class BuildAssembleNode extends ComputeNode {
|
class BuildAssembleNode extends ComputeNode {
|
||||||
constructor() { super("builder-make-build"); }
|
constructor() { super("builder-make-build"); }
|
||||||
|
|
||||||
compute_func(input_map) {
|
compute_func(input_map) {
|
||||||
let equipments = [
|
let equipments = [
|
||||||
input_map.get('helmet-input'),
|
input_map.get('helmet'),
|
||||||
input_map.get('chestplate-input'),
|
input_map.get('chestplate'),
|
||||||
input_map.get('leggings-input'),
|
input_map.get('leggings'),
|
||||||
input_map.get('boots-input'),
|
input_map.get('boots'),
|
||||||
input_map.get('ring1-input'),
|
input_map.get('ring1'),
|
||||||
input_map.get('ring2-input'),
|
input_map.get('ring2'),
|
||||||
input_map.get('bracelet-input'),
|
input_map.get('bracelet'),
|
||||||
input_map.get('necklace-input')
|
input_map.get('necklace'),
|
||||||
|
input_map.get('weaponTome1'),
|
||||||
|
input_map.get('weaponTome2'),
|
||||||
|
input_map.get('armorTome1'),
|
||||||
|
input_map.get('armorTome2'),
|
||||||
|
input_map.get('armorTome3'),
|
||||||
|
input_map.get('armorTome4'),
|
||||||
|
input_map.get('guildTome1')
|
||||||
];
|
];
|
||||||
let tomes = [
|
let weapon = input_map.get('weapon');
|
||||||
input_map.get('weaponTome1-input'),
|
|
||||||
input_map.get('weaponTome2-input'),
|
|
||||||
input_map.get('armorTome1-input'),
|
|
||||||
input_map.get('armorTome2-input'),
|
|
||||||
input_map.get('armorTome3-input'),
|
|
||||||
input_map.get('armorTome4-input'),
|
|
||||||
input_map.get('guildTome1-input')
|
|
||||||
];
|
|
||||||
let weapon = input_map.get('weapon-input');
|
|
||||||
let level = parseInt(input_map.get('level-input'));
|
let level = parseInt(input_map.get('level-input'));
|
||||||
if (isNaN(level)) {
|
if (isNaN(level)) {
|
||||||
level = 106;
|
level = 106;
|
||||||
|
@ -440,15 +447,25 @@ class PlayerClassNode extends ValueCheckComputeNode {
|
||||||
* Read an input field and parse into a list of powderings.
|
* Read an input field and parse into a list of powderings.
|
||||||
* Every two characters makes one powder. If parsing fails, NULL is returned.
|
* Every two characters makes one powder. If parsing fails, NULL is returned.
|
||||||
*
|
*
|
||||||
* Signature: PowderInputNode() => List[powder] | null
|
* Signature: PowderInputNode(item: Item) => List[powder] | null
|
||||||
*/
|
*/
|
||||||
class PowderInputNode extends InputNode {
|
class PowderInputNode extends InputNode {
|
||||||
|
|
||||||
constructor(name, input_field) { super(name, input_field); }
|
constructor(name, input_field) { super(name, input_field); this.fail_cb = true; }
|
||||||
|
|
||||||
compute_func(input_map) {
|
compute_func(input_map) {
|
||||||
|
if (input_map.size !== 1) { throw "PowderInputNode accepts exactly one input (item)"; }
|
||||||
|
const [item] = input_map.values(); // Extract values, pattern match it into size one list and bind to first element
|
||||||
|
if (item === null) {
|
||||||
|
this.input_field.placeholder = 'powders';
|
||||||
|
return [];
|
||||||
|
}
|
||||||
|
|
||||||
|
if (item.statMap.has('slots')) {
|
||||||
|
this.input_field.placeholder = item.statMap.get('slots') + ' slots';
|
||||||
|
}
|
||||||
|
|
||||||
// TODO: haha improve efficiency to O(n) dumb
|
// TODO: haha improve efficiency to O(n) dumb
|
||||||
// also, error handling is missing
|
|
||||||
let input = this.input_field.value.trim();
|
let input = this.input_field.value.trim();
|
||||||
let powdering = [];
|
let powdering = [];
|
||||||
let errorederrors = [];
|
let errorederrors = [];
|
||||||
|
@ -456,12 +473,29 @@ class PowderInputNode extends InputNode {
|
||||||
let first = input.slice(0, 2);
|
let first = input.slice(0, 2);
|
||||||
let powder = powderIDs.get(first);
|
let powder = powderIDs.get(first);
|
||||||
if (powder === undefined) {
|
if (powder === undefined) {
|
||||||
return null;
|
if (first.length > 0) {
|
||||||
|
errorederrors.push(first);
|
||||||
|
} else {
|
||||||
|
break;
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
powdering.push(powder);
|
powdering.push(powder);
|
||||||
}
|
}
|
||||||
input = input.slice(2);
|
input = input.slice(2);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (this.input_field.getAttribute("placeholder") != null) {
|
||||||
|
if (item.statMap.get('slots') < powdering.length) {
|
||||||
|
errorederrors.push("Too many powders: " + powdering.length);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (errorederrors.length) {
|
||||||
|
this.input_field.classList.add("is-invalid");
|
||||||
|
} else {
|
||||||
|
this.input_field.classList.remove("is-invalid");
|
||||||
|
}
|
||||||
|
|
||||||
return powdering;
|
return powdering;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -566,8 +600,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]),
|
||||||
|
@ -579,7 +614,10 @@ 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] * (1+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
|
||||||
|
@ -588,12 +626,14 @@ class SpellDamageCalcNode extends ComputeNode {
|
||||||
else {
|
else {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
spell_result.name = part.name;
|
const {name, display = true} = part;
|
||||||
|
spell_result.name = name;
|
||||||
|
spell_result.display = display;
|
||||||
spell_results.push(spell_result);
|
spell_results.push(spell_result);
|
||||||
spell_result_map.set(part.name, spell_result);
|
spell_result_map.set(name, spell_result);
|
||||||
}
|
}
|
||||||
for (const part of spell_parts) {
|
for (const part of spell_parts) {
|
||||||
if ('hits' in part) {
|
if (!('hits' in part)) { continue; }
|
||||||
let spell_result = {
|
let spell_result = {
|
||||||
normal_min: [0, 0, 0, 0, 0, 0],
|
normal_min: [0, 0, 0, 0, 0, 0],
|
||||||
normal_max: [0, 0, 0, 0, 0, 0],
|
normal_max: [0, 0, 0, 0, 0, 0],
|
||||||
|
@ -626,10 +666,11 @@ class SpellDamageCalcNode extends ComputeNode {
|
||||||
spell_result.heal_amount += subpart.heal_amount * hits;
|
spell_result.heal_amount += subpart.heal_amount * hits;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
spell_result.name = part.name;
|
const {name, display = true} = part;
|
||||||
|
spell_result.name = name;
|
||||||
|
spell_result.display = display;
|
||||||
spell_results.push(spell_result);
|
spell_results.push(spell_result);
|
||||||
spell_result_map.set(part.name, spell_result);
|
spell_result_map.set(name, spell_result);
|
||||||
}
|
|
||||||
}
|
}
|
||||||
return spell_results;
|
return spell_results;
|
||||||
}
|
}
|
||||||
|
@ -674,13 +715,13 @@ class BuildDisplayNode extends ComputeNode {
|
||||||
compute_func(input_map) {
|
compute_func(input_map) {
|
||||||
const build = input_map.get('build');
|
const build = input_map.get('build');
|
||||||
const stats = input_map.get('stats');
|
const stats = input_map.get('stats');
|
||||||
displayBuildStats('overall-stats', build, build_all_display_commands, stats);
|
displayBuildStats('summary-stats', build, build_overall_display_commands, stats);
|
||||||
displayBuildStats("offensive-stats", build, build_offensive_display_commands, stats);
|
displayBuildStats("detailed-stats", build, build_detailed_display_commands, stats);
|
||||||
displaySetBonuses("set-info", build);
|
displaySetBonuses("set-info", build);
|
||||||
// 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);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -705,7 +746,7 @@ class DisplayBuildWarningsNode extends ComputeNode {
|
||||||
input_map.get('def'),
|
input_map.get('def'),
|
||||||
input_map.get('agi')
|
input_map.get('agi')
|
||||||
];
|
];
|
||||||
let skp_effects = ["% more damage dealt.","% chance to crit.","% spell cost reduction.","% less damage taken.","% chance to dodge."];
|
let skp_effects = ["% damage","% crit","% cost red.","% resist","% dodge"];
|
||||||
let total_assigned = 0;
|
let total_assigned = 0;
|
||||||
for (let i in skp_order){ //big bren
|
for (let i in skp_order){ //big bren
|
||||||
const assigned = skillpoints[i] - base_totals[i] + min_assigned[i]
|
const assigned = skillpoints[i] - base_totals[i] + min_assigned[i]
|
||||||
|
@ -727,20 +768,16 @@ class DisplayBuildWarningsNode extends ComputeNode {
|
||||||
|
|
||||||
let summarybox = document.getElementById("summary-box");
|
let summarybox = document.getElementById("summary-box");
|
||||||
summarybox.textContent = "";
|
summarybox.textContent = "";
|
||||||
let skpRow = document.createElement("p");
|
|
||||||
|
|
||||||
let remainingSkp = document.createElement("p");
|
let remainingSkp = make_elem("p", ['scaled-font', 'my-0']);
|
||||||
remainingSkp.classList.add("scaled-font");
|
let remainingSkpTitle = make_elem("b", [], { textContent: "Assigned " + total_assigned + " skillpoints. Remaining skillpoints: " });
|
||||||
let remainingSkpTitle = document.createElement("b");
|
|
||||||
remainingSkpTitle.textContent = "Assigned " + total_assigned + " skillpoints. Remaining skillpoints: ";
|
|
||||||
let remainingSkpContent = document.createElement("b");
|
let remainingSkpContent = document.createElement("b");
|
||||||
remainingSkpContent.textContent = "" + (levelToSkillPoints(build.level) - total_assigned);
|
remainingSkpContent.textContent = "" + (levelToSkillPoints(build.level) - total_assigned);
|
||||||
remainingSkpContent.classList.add(levelToSkillPoints(build.level) - total_assigned < 0 ? "negative" : "positive");
|
remainingSkpContent.classList.add(levelToSkillPoints(build.level) - total_assigned < 0 ? "negative" : "positive");
|
||||||
|
|
||||||
remainingSkp.appendChild(remainingSkpTitle);
|
remainingSkp.append(remainingSkpTitle);
|
||||||
remainingSkp.appendChild(remainingSkpContent);
|
remainingSkp.append(remainingSkpContent);
|
||||||
|
|
||||||
summarybox.append(skpRow);
|
|
||||||
summarybox.append(remainingSkp);
|
summarybox.append(remainingSkp);
|
||||||
if(total_assigned > levelToSkillPoints(build.level)){
|
if(total_assigned > levelToSkillPoints(build.level)){
|
||||||
let skpWarning = document.createElement("span");
|
let skpWarning = document.createElement("span");
|
||||||
|
@ -810,6 +847,72 @@ class AggregateStatsNode extends ComputeNode {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
let radiance_affected = [ /*"hp"*/, "fDef", "wDef", "aDef", "tDef", "eDef", "hprPct", "mr", "sdPct", "mdPct", "ls", "ms", "xpb", "lb", "ref",
|
||||||
|
/*"str", "dex", "int", "agi", "def",*/
|
||||||
|
"thorns", "expd", "spd", "atkTier", "poison", "hpBonus", "spRegen", "eSteal", "hprRaw", "sdRaw", "mdRaw", "fDamPct", "wDamPct", "aDamPct", "tDamPct", "eDamPct", "fDefPct", "wDefPct", "aDefPct", "tDefPct", "eDefPct", "fixID", "category", "spPct1", "spRaw1", "spPct2", "spRaw2", "spPct3", "spRaw3", "spPct4", "spRaw4", "rSdRaw", "sprint", "sprintReg", "jh", "lq", "gXp", "gSpd",
|
||||||
|
|
||||||
|
// wynn2 damages.
|
||||||
|
"eMdPct","eMdRaw","eSdPct","eSdRaw",/*"eDamPct,"*/"eDamRaw",//"eDamAddMin","eDamAddMax",
|
||||||
|
"tMdPct","tMdRaw","tSdPct","tSdRaw",/*"tDamPct,"*/"tDamRaw",//"tDamAddMin","tDamAddMax",
|
||||||
|
"wMdPct","wMdRaw","wSdPct","wSdRaw",/*"wDamPct,"*/"wDamRaw",//"wDamAddMin","wDamAddMax",
|
||||||
|
"fMdPct","fMdRaw","fSdPct","fSdRaw",/*"fDamPct,"*/"fDamRaw",//"fDamAddMin","fDamAddMax",
|
||||||
|
"aMdPct","aMdRaw","aSdPct","aSdRaw",/*"aDamPct,"*/"aDamRaw",//"aDamAddMin","aDamAddMax",
|
||||||
|
"nMdPct","nMdRaw","nSdPct","nSdRaw","nDamPct","nDamRaw",//"nDamAddMin","nDamAddMax", // neutral which is now an element
|
||||||
|
/*"mdPct","mdRaw","sdPct","sdRaw",*/"damPct","damRaw",//"damAddMin","damAddMax", // These are the old ids. Become proportional.
|
||||||
|
"rMdPct","rMdRaw","rSdPct",/*"rSdRaw",*/"rDamPct","rDamRaw",//"rDamAddMin","rDamAddMax", // rainbow (the "element" of all minus neutral). rSdRaw is rainraw
|
||||||
|
"critDamPct",
|
||||||
|
//"spPct1Final", "spPct2Final", "spPct3Final", "spPct4Final"
|
||||||
|
];
|
||||||
|
/**
|
||||||
|
* Scale stats if radiance is enabled.
|
||||||
|
*/
|
||||||
|
const radiance_node = new (class extends ComputeNode {
|
||||||
|
constructor() { super('radiance-node->:('); }
|
||||||
|
|
||||||
|
compute_func(input_map) {
|
||||||
|
const [statmap] = input_map.values(); // Extract values, pattern match it into size one list and bind to first element
|
||||||
|
let elem = document.getElementById('radiance-boost');
|
||||||
|
if (elem.classList.contains("toggleOn")) {
|
||||||
|
const ret = new Map(statmap);
|
||||||
|
for (const val of radiance_affected) {
|
||||||
|
if (reversedIDs.includes(val)) {
|
||||||
|
if ((ret.get(val) || 0) < 0) {
|
||||||
|
ret.set(val, Math.floor((ret.get(val) || 0) * 1.2));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
if ((ret.get(val) || 0) > 0) {
|
||||||
|
ret.set(val, Math.floor((ret.get(val) || 0) * 1.2));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
const dam_mults = new Map(ret.get('damMult'));
|
||||||
|
dam_mults.set('tome', dam_mults.get('tome') * 1.2)
|
||||||
|
ret.set('damMult', dam_mults)
|
||||||
|
const def_mults = new Map(ret.get('defMult'));
|
||||||
|
def_mults.set('tome', def_mults.get('tome') * 1.2)
|
||||||
|
ret.set('defMult', def_mults)
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
return statmap;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})();
|
||||||
|
|
||||||
|
/* Updates all spell boosts
|
||||||
|
*/
|
||||||
|
function update_radiance() {
|
||||||
|
let elem = document.getElementById('radiance-boost');
|
||||||
|
if (elem.classList.contains("toggleOn")) {
|
||||||
|
elem.classList.remove("toggleOn");
|
||||||
|
} else {
|
||||||
|
elem.classList.add("toggleOn");
|
||||||
|
}
|
||||||
|
radiance_node.mark_dirty().update();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Aggregate editable ID stats with build and weapon type.
|
* Aggregate editable ID stats with build and weapon type.
|
||||||
*
|
*
|
||||||
|
@ -856,6 +959,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();
|
||||||
|
@ -928,9 +1042,11 @@ class SumNumberInputNode extends InputNode {
|
||||||
}
|
}
|
||||||
|
|
||||||
let item_nodes = [];
|
let item_nodes = [];
|
||||||
|
let item_nodes_map = new Map();
|
||||||
let powder_nodes = [];
|
let powder_nodes = [];
|
||||||
let edit_input_nodes = [];
|
let edit_input_nodes = [];
|
||||||
let skp_inputs = [];
|
let skp_inputs = [];
|
||||||
|
let equip_inputs = [];
|
||||||
let build_node;
|
let build_node;
|
||||||
let stat_agg_node;
|
let stat_agg_node;
|
||||||
let edit_agg_node;
|
let edit_agg_node;
|
||||||
|
@ -939,25 +1055,53 @@ let atree_graph_creator;
|
||||||
function builder_graph_init() {
|
function builder_graph_init() {
|
||||||
// Phase 1/3: Set up item input, propagate updates, etc.
|
// Phase 1/3: Set up item input, propagate updates, etc.
|
||||||
|
|
||||||
|
// Level input node.
|
||||||
|
let level_input = new InputNode('level-input', document.getElementById('level-choice'));
|
||||||
|
|
||||||
|
// "Build" now only refers to equipment and level (no powders). Powders are injected before damage calculation / stat display.
|
||||||
|
build_node = new BuildAssembleNode();
|
||||||
|
for (const input of item_nodes) {
|
||||||
|
}
|
||||||
|
build_node.link_to(level_input);
|
||||||
|
|
||||||
|
let build_encode_node = new BuildEncodeNode();
|
||||||
|
build_encode_node.link_to(build_node, 'build');
|
||||||
|
|
||||||
// Bind item input fields to input nodes, and some display stuff (for auto colorizing stuff).
|
// Bind item input fields to input nodes, and some display stuff (for auto colorizing stuff).
|
||||||
for (const [eq, display_elem, none_item] of zip3(equipment_fields, build_fields, none_items)) {
|
for (const [eq, display_elem, none_item] of zip3(equipment_fields, build_fields, none_items)) {
|
||||||
let input_field = document.getElementById(eq+"-choice");
|
let input_field = document.getElementById(eq+"-choice");
|
||||||
let item_image = document.getElementById(eq+"-img");
|
let item_image = document.getElementById(eq+"-img");
|
||||||
|
|
||||||
let item_input = new ItemInputNode(eq+'-input', input_field, none_item);
|
let item_input = new ItemInputNode(eq+'-input', input_field, none_item);
|
||||||
|
equip_inputs.push(item_input);
|
||||||
|
if (powder_inputs.includes(eq+'-powder')) { // TODO: fragile
|
||||||
|
const powder_name = eq+'-powder';
|
||||||
|
let powder_node = new PowderInputNode(powder_name, document.getElementById(powder_name))
|
||||||
|
.link_to(item_input, 'item');
|
||||||
|
powder_nodes.push(powder_node);
|
||||||
|
build_encode_node.link_to(powder_node, powder_name);
|
||||||
|
let item_powdering = new ItemPowderingNode(eq+'-powder-apply')
|
||||||
|
.link_to(powder_node, 'powdering').link_to(item_input, 'item');
|
||||||
|
item_input = item_powdering;
|
||||||
|
}
|
||||||
item_nodes.push(item_input);
|
item_nodes.push(item_input);
|
||||||
|
item_nodes_map.set(eq, item_input);
|
||||||
new ItemInputDisplayNode(eq+'-input-display', eq, item_image).link_to(item_input);
|
new ItemInputDisplayNode(eq+'-input-display', eq, item_image).link_to(item_input);
|
||||||
new ItemDisplayNode(eq+'-item-display', display_elem).link_to(item_input);
|
new ItemDisplayNode(eq+'-item-display', display_elem).link_to(item_input);
|
||||||
//new PrintNode(eq+'-debug').link_to(item_input);
|
//new PrintNode(eq+'-debug').link_to(item_input);
|
||||||
//document.querySelector("#"+eq+"-tooltip").setAttribute("onclick", "collapse_element('#"+ eq +"-tooltip');"); //toggle_plus_minus('" + eq + "-pm');
|
//document.querySelector("#"+eq+"-tooltip").setAttribute("onclick", "collapse_element('#"+ eq +"-tooltip');"); //toggle_plus_minus('" + eq + "-pm');
|
||||||
|
build_node.link_to(item_input, eq);
|
||||||
}
|
}
|
||||||
|
|
||||||
for (const [eq, none_item] of zip2(tome_fields, [none_tomes[0], none_tomes[0], none_tomes[1], none_tomes[1], none_tomes[1], none_tomes[1], none_tomes[2]])) {
|
for (const [eq, none_item] of zip2(tome_fields, [none_tomes[0], none_tomes[0], none_tomes[1], none_tomes[1], none_tomes[1], none_tomes[1], none_tomes[2]])) {
|
||||||
let input_field = document.getElementById(eq+"-choice");
|
let input_field = document.getElementById(eq+"-choice");
|
||||||
let item_image = document.getElementById(eq+"-img");
|
let item_image = document.getElementById(eq+"-img");
|
||||||
|
|
||||||
let item_input = new ItemInputNode(eq+'-input', input_field, none_item);
|
let item_input = new ItemInputNode(eq+'-input', input_field, none_item);
|
||||||
|
equip_inputs.push(item_input);
|
||||||
item_nodes.push(item_input);
|
item_nodes.push(item_input);
|
||||||
new ItemInputDisplayNode(eq+'-input-display', eq, item_image).link_to(item_input);
|
new ItemInputDisplayNode(eq+'-input-display', eq, item_image).link_to(item_input);
|
||||||
|
build_node.link_to(item_input, eq);
|
||||||
}
|
}
|
||||||
|
|
||||||
// weapon image changer node.
|
// weapon image changer node.
|
||||||
|
@ -965,38 +1109,12 @@ function builder_graph_init() {
|
||||||
let weapon_dps = document.getElementById("weapon-dps");
|
let weapon_dps = document.getElementById("weapon-dps");
|
||||||
new WeaponInputDisplayNode('weapon-type', weapon_image, weapon_dps).link_to(item_nodes[8]);
|
new WeaponInputDisplayNode('weapon-type', weapon_image, weapon_dps).link_to(item_nodes[8]);
|
||||||
|
|
||||||
// Level input node.
|
|
||||||
let level_input = new InputNode('level-input', document.getElementById('level-choice'));
|
|
||||||
|
|
||||||
// linking to atree verification
|
// linking to atree verification
|
||||||
atree_validate.link_to(level_input, 'level');
|
atree_validate.link_to(level_input, 'level');
|
||||||
|
|
||||||
// "Build" now only refers to equipment and level (no powders). Powders are injected before damage calculation / stat display.
|
|
||||||
build_node = new BuildAssembleNode();
|
|
||||||
for (const input of item_nodes) {
|
|
||||||
build_node.link_to(input);
|
|
||||||
}
|
|
||||||
build_node.link_to(level_input);
|
|
||||||
|
|
||||||
let build_encode_node = new BuildEncodeNode();
|
|
||||||
build_encode_node.link_to(build_node, 'build');
|
|
||||||
|
|
||||||
let url_update_node = new URLUpdateNode();
|
let url_update_node = new URLUpdateNode();
|
||||||
url_update_node.link_to(build_encode_node, 'build-str');
|
url_update_node.link_to(build_encode_node, 'build-str');
|
||||||
|
|
||||||
|
|
||||||
for (const input of powder_inputs) {
|
|
||||||
let powder_node = new PowderInputNode(input, document.getElementById(input));
|
|
||||||
powder_nodes.push(powder_node);
|
|
||||||
build_encode_node.link_to(powder_node, input);
|
|
||||||
}
|
|
||||||
|
|
||||||
item_nodes[0].link_to(powder_nodes[0], 'powdering');
|
|
||||||
item_nodes[1].link_to(powder_nodes[1], 'powdering');
|
|
||||||
item_nodes[2].link_to(powder_nodes[2], 'powdering');
|
|
||||||
item_nodes[3].link_to(powder_nodes[3], 'powdering');
|
|
||||||
item_nodes[8].link_to(powder_nodes[4], 'powdering');
|
|
||||||
|
|
||||||
// Phase 2/3: Set up editable IDs, skill points; use decodeBuild() skill points, calculate damage
|
// Phase 2/3: Set up editable IDs, skill points; use decodeBuild() skill points, calculate damage
|
||||||
|
|
||||||
// Create one node that will be the "aggregator node" (listen to all the editable id nodes, as well as the build_node (for non editable stats) and collect them into one statmap)
|
// Create one node that will be the "aggregator node" (listen to all the editable id nodes, as well as the build_node (for non editable stats) and collect them into one statmap)
|
||||||
|
@ -1030,20 +1148,21 @@ 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');
|
radiance_node.link_to(pre_scale_agg_node, 'stats');
|
||||||
stat_agg_node.link_to(pre_scale_agg_node, 'pre-scaling');
|
atree_scaling.link_to(radiance_node, 'scale-stats');
|
||||||
stat_agg_node.link_to(atree_scaling, 'atree-scaling');
|
stat_agg_node.link_to(radiance_node, 'pre-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');
|
||||||
|
|
||||||
// ---------------------------------------------------------------
|
// ---------------------------------------------------------------
|
||||||
// Trigger the update cascade for build!
|
// Trigger the update cascade for build!
|
||||||
// ---------------------------------------------------------------
|
// ---------------------------------------------------------------
|
||||||
for (const input_node of item_nodes.concat(powder_nodes)) {
|
for (const input_node of equip_inputs) {
|
||||||
input_node.update();
|
input_node.update();
|
||||||
}
|
}
|
||||||
armor_powder_node.update();
|
armor_powder_node.update();
|
||||||
|
@ -1056,11 +1175,15 @@ function builder_graph_init() {
|
||||||
if (atree_data !== null && atree_node.value !== null) { // janky check if atree is valid
|
if (atree_data !== null && atree_node.value !== null) { // janky check if atree is valid
|
||||||
const atree_state = atree_state_node.value;
|
const atree_state = atree_state_node.value;
|
||||||
if (atree_data.length > 0) {
|
if (atree_data.length > 0) {
|
||||||
|
try {
|
||||||
const active_nodes = decode_atree(atree_node.value, atree_data);
|
const active_nodes = decode_atree(atree_node.value, atree_data);
|
||||||
for (const node of active_nodes) {
|
for (const node of active_nodes) {
|
||||||
atree_set_state(atree_state.get(node.ability.id), true);
|
atree_set_state(atree_state.get(node.ability.id), true);
|
||||||
}
|
}
|
||||||
atree_state_node.mark_dirty().update();
|
atree_state_node.mark_dirty().update();
|
||||||
|
} catch (e) {
|
||||||
|
console.log("Failed to decode atree. This can happen when updating versions. Give up!")
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -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;
|
||||||
|
|
|
@ -397,4 +397,8 @@ class Craft{
|
||||||
statMap.set("crafted", true);
|
statMap.set("crafted", true);
|
||||||
this.statMap = statMap;
|
this.statMap = statMap;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
copy() {
|
||||||
|
return new Craft(this.recipe, this.mat_tiers, this.ingreds, this.atkSpd, this.hash.slice(3));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -31,42 +31,31 @@ let player_craft;
|
||||||
|
|
||||||
|
|
||||||
function init_crafter() {
|
function init_crafter() {
|
||||||
//no ing
|
|
||||||
|
|
||||||
console.log("all ingredients");
|
|
||||||
console.log(ingMap);
|
|
||||||
console.log("all recipes");
|
|
||||||
console.log(recipeMap);
|
|
||||||
/*console.log(ingList);
|
|
||||||
console.log(recipeList);
|
|
||||||
console.log(ingIDMap);
|
|
||||||
console.log(recipeIDMap);*/
|
|
||||||
try {
|
try {
|
||||||
document.getElementById("recipe-choice").addEventListener("change", (event) => {
|
document.getElementById("recipe-choice").addEventListener("input", (event) => {
|
||||||
updateMaterials();
|
updateMaterials();
|
||||||
updateCraftedImage();
|
updateCraftedImage();
|
||||||
calculateCraftSchedule();
|
calculateCraftSchedule();
|
||||||
});
|
});
|
||||||
document.getElementById("recipe-choice").addEventListener("oninput", (event) => {
|
document.getElementById("recipe-choice").addEventListener("input", (event) => {
|
||||||
updateCraftedImage();
|
updateCraftedImage();
|
||||||
});
|
});
|
||||||
document.getElementById("level-choice").addEventListener("change", (event) => {
|
document.getElementById("level-choice").addEventListener("input", (event) => {
|
||||||
updateMaterials();
|
updateMaterials();
|
||||||
calculateCraftSchedule();
|
calculateCraftSchedule();
|
||||||
});
|
});
|
||||||
|
|
||||||
for (let i = 1; i < 4; ++i) {
|
for (let i = 1; i < 4; ++i) {
|
||||||
document.getElementById("mat-1-"+i).setAttribute("onclick", document.getElementById("mat-1-"+i).getAttribute("onclick") + "; calculateCraftSchedule();");
|
document.getElementById("mat-1-"+i).addEventListener("click", (e) => calculateCraftSchedule());
|
||||||
document.getElementById("mat-2-"+i).setAttribute("onclick", document.getElementById("mat-2-"+i).getAttribute("onclick") + "; calculateCraftSchedule();");
|
document.getElementById("mat-2-"+i).addEventListener("click", (e) => calculateCraftSchedule());
|
||||||
}
|
}
|
||||||
for (let i = 1; i < 7; ++i) {
|
for (let i = 1; i < 7; ++i) {
|
||||||
document.getElementById("ing-choice-" + i ).setAttribute("oninput", "calculateCraftSchedule();");
|
document.getElementById("ing-choice-" + i ).addEventListener("input", (e) => calculateCraftSchedule());
|
||||||
}
|
}
|
||||||
for (const str of ["slow", "normal", "fast"]) {
|
for (const str of ["slow", "normal", "fast"]) {
|
||||||
document.getElementById(str + "-atk-button").setAttribute("onclick", document.getElementById(str + "-atk-button").getAttribute("onclick") + "; calculateCraftSchedule();");
|
document.getElementById(str + "-atk-button").addEventListener("click", (e) => calculateCraftSchedule());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
populateFields();
|
populateFields();
|
||||||
decodeCraft(ing_url_tag);
|
decodeCraft(ing_url_tag);
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
|
@ -259,12 +248,10 @@ function populateFields() {
|
||||||
ing_list.appendChild(el);
|
ing_list.appendChild(el);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
/*
|
/*
|
||||||
Copies the CR Hash (CR-blahblahblah)
|
* Copies the CR Hash (CR-blahblahblah)
|
||||||
*/
|
*/
|
||||||
function copyRecipeHash() {
|
function copyRecipeHash() {
|
||||||
if (player_craft) {
|
if (player_craft) {
|
||||||
copyTextToClipboard("CR-"+location.hash.slice(1));
|
copyTextToClipboard("CR-"+location.hash.slice(1));
|
||||||
|
@ -345,9 +332,16 @@ function toggleMaterial(buttonId) {
|
||||||
function updateCraftedImage() {
|
function updateCraftedImage() {
|
||||||
let input = document.getElementById("recipe-choice");
|
let input = document.getElementById("recipe-choice");
|
||||||
if (all_types.includes(input.value)) {
|
if (all_types.includes(input.value)) {
|
||||||
document.getElementById("recipe-img").src = "../media/items/" + (newIcons ? "new/":"old/") + "generic-" + input.value.toLowerCase() + ".png";
|
let img = document.getElementById("recipe-img");
|
||||||
|
if (["potion", "scroll", "food"].includes(input.value.toLowerCase())) {
|
||||||
|
img.style.backgroundImage = "url('../media/items/common.png')";
|
||||||
|
img.style.backgroundSize = "500% 100%";
|
||||||
|
} else {
|
||||||
|
img.style.backgroundImage = "url('../media/items/" + (newIcons ? "new.png')" : "old.png')");
|
||||||
|
img.style.backgroundSize = "1200% 100%";
|
||||||
|
}
|
||||||
|
img.style.backgroundPosition = itemBGPositions[input.value.toLowerCase()]
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Reset all fields
|
/* Reset all fields
|
||||||
|
|
|
@ -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 {
|
||||||
/**
|
/**
|
||||||
|
@ -336,4 +336,7 @@ class Custom {
|
||||||
this.statMap.set("restrict", "Custom Item")
|
this.statMap.set("restrict", "Custom Item")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
copy() {
|
||||||
|
return new Custom(new Map(this.statMap));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -12,7 +12,6 @@ let roll_range_ids = ["neg_roll_range-choice-min","neg_roll_range-choice-max","p
|
||||||
|
|
||||||
|
|
||||||
function init_customizer() {
|
function init_customizer() {
|
||||||
|
|
||||||
try {
|
try {
|
||||||
populateFields();
|
populateFields();
|
||||||
decodeCustom(custom_url_tag);
|
decodeCustom(custom_url_tag);
|
||||||
|
@ -181,7 +180,11 @@ function calculateCustom() {
|
||||||
player_custom_item.setHash(custom_str);
|
player_custom_item.setHash(custom_str);
|
||||||
|
|
||||||
|
|
||||||
displaysq2ExpandedItem(player_custom_item.statMap, "custom-stats");
|
if (player_custom_item.statMap.get('category') == 'weapon') {
|
||||||
|
// wonkiness needed to set the right fields... this is jank
|
||||||
|
apply_weapon_powders(player_custom_item.statMap);
|
||||||
|
}
|
||||||
|
displayExpandedItem(player_custom_item.statMap, "custom-stats");
|
||||||
|
|
||||||
}catch (error) {
|
}catch (error) {
|
||||||
//The error elements no longer exist in the page. Add them back if needed.
|
//The error elements no longer exist in the page. Add them back if needed.
|
||||||
|
@ -266,7 +269,7 @@ function decodeCustom(custom_url_tag) {
|
||||||
val = tiers[Base64.toInt(tag.charAt(2))];
|
val = tiers[Base64.toInt(tag.charAt(2))];
|
||||||
len = -1;
|
len = -1;
|
||||||
} else if (id === "type") {
|
} else if (id === "type") {
|
||||||
val = types[Base64.toInt(tag.charAt(2))];
|
val = item_types[Base64.toInt(tag.charAt(2))];
|
||||||
len = -1;
|
len = -1;
|
||||||
} else if (id === "atkSpd") {
|
} else if (id === "atkSpd") {
|
||||||
val = attackSpeeds[Base64.toInt(tag.charAt(2))];
|
val = attackSpeeds[Base64.toInt(tag.charAt(2))];
|
||||||
|
@ -313,7 +316,7 @@ function populateFields() {
|
||||||
tier_list.appendChild(el);
|
tier_list.appendChild(el);
|
||||||
}
|
}
|
||||||
let type_list = document.getElementById("type-list");
|
let type_list = document.getElementById("type-list");
|
||||||
for (const type of types) {
|
for (const type of item_types) {
|
||||||
let el = document.createElement("option");
|
let el = document.createElement("option");
|
||||||
el.value = type;
|
el.value = type;
|
||||||
type_list.appendChild(el);
|
type_list.appendChild(el);
|
||||||
|
@ -602,10 +605,6 @@ function resetBaseValues() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function _init_customizer() {
|
|
||||||
load_ing_init(init_customizer);
|
|
||||||
}
|
|
||||||
|
|
||||||
/** Saves the current user's item as a JSON file.
|
/** Saves the current user's item as a JSON file.
|
||||||
* Starts a JSON download.
|
* Starts a JSON download.
|
||||||
*/
|
*/
|
||||||
|
@ -715,4 +714,8 @@ function full_range_to_base(min, max) {
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
load_init(_init_customizer);
|
(async function() {
|
||||||
|
let load_promises = [ load_init() ];
|
||||||
|
await Promise.all(load_promises);
|
||||||
|
init_customizer();
|
||||||
|
})();
|
||||||
|
|
|
@ -1,4 +1,6 @@
|
||||||
const damageMultipliers = new Map([ ["allytotem", .15], ["yourtotem", .35], ["vanish", 0.80], ["warscream", 0.00], ["ragnarokkr", 0.30], ["fortitude", 0.60] ]);
|
/**
|
||||||
|
* File implementing core damage calculation logic.
|
||||||
|
*/
|
||||||
|
|
||||||
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"))];
|
||||||
|
@ -122,15 +124,21 @@ 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);
|
||||||
|
if (i > 0) {
|
||||||
|
damageBoost += stats.get('r'+specific_boost_str+'Pct') / 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];
|
||||||
|
@ -140,6 +148,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
|
||||||
|
@ -153,22 +162,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;
|
||||||
|
@ -193,7 +202,7 @@ function calculateSpellDamage(stats, weapon, _conversions, use_spell_damage, ign
|
||||||
damage_mult *= (1 + v/100);
|
damage_mult *= (1 + v/100);
|
||||||
}
|
}
|
||||||
|
|
||||||
const crit_mult = stats.get("critDamPct")/100;
|
const crit_mult = 1+(stats.get("critDamPct")/100);
|
||||||
|
|
||||||
for (const damage of damages) {
|
for (const damage of damages) {
|
||||||
const res = [
|
const res = [
|
||||||
|
@ -243,17 +252,21 @@ spell_damage: {
|
||||||
name: str != "total" Name of the part.
|
name: str != "total" Name of the part.
|
||||||
type: "damage" [TODO: DEPRECATED/REMOVE] flag signaling what type of part it is. Can infer from fields
|
type: "damage" [TODO: DEPRECATED/REMOVE] flag signaling what type of part it is. Can infer from fields
|
||||||
multipliers: array[num, 6] floating point spellmults (though supposedly wynn only supports integer mults)
|
multipliers: array[num, 6] floating point spellmults (though supposedly wynn only supports integer mults)
|
||||||
|
display: bool To show part or not (for some spells there are too many intermediate calc parts). Default: True
|
||||||
}
|
}
|
||||||
spell_heal: {
|
spell_heal: {
|
||||||
name: str != "total" Name of the part.
|
name: str != "total" Name of the part.
|
||||||
type: "heal" [TODO: DEPRECATED/REMOVE] flag signaling what type of part it is. Can infer from fields
|
type: "heal" [TODO: DEPRECATED/REMOVE] flag signaling what type of part it is. Can infer from fields
|
||||||
power: num floating point healing power (1 is 100% of max hp).
|
power: num floating point healing power (1 is 100% of max hp).
|
||||||
|
display: bool To show part or not (for some spells there are too many intermediate calc parts). Default: True
|
||||||
}
|
}
|
||||||
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
|
||||||
|
display: bool To show part or not (for some spells there are too many intermediate calc parts). Default: True
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
561
js/display.js
|
@ -1,3 +1,12 @@
|
||||||
|
/**
|
||||||
|
* File containing generic display code, ex. for displaying items and spell damage.
|
||||||
|
* TODO: split this file into separate parts for each "component".
|
||||||
|
*/
|
||||||
|
|
||||||
|
const itemBGPositions = {"bow": "0 0", "spear": "9.090909090909088% 0", "wand": "18.181818181818183% 0", "dagger": "27.27272727272727% 0", "relik": "36.36363636363637% 0",
|
||||||
|
"helmet": "45.45454545454546% 0", "chestplate": "54.54545454545454% 0", "leggings": "63.63636363636363% 0", "boots": "72.72727272727272% 0",
|
||||||
|
"ring": "81.81818181818181% 0", "bracelet": "90.90909090909092% 0", "necklace": "100% 0",
|
||||||
|
"potion": "25% 0", "scroll": "50% 0", "food": "75% 0"};
|
||||||
|
|
||||||
function apply_elemental_format(p_elem, id, suffix) {
|
function apply_elemental_format(p_elem, id, suffix) {
|
||||||
suffix = (typeof suffix !== 'undefined') ? suffix : "";
|
suffix = (typeof suffix !== 'undefined') ? suffix : "";
|
||||||
|
@ -63,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) {
|
||||||
|
@ -100,24 +110,8 @@ function displayBuildStats(parent_id,build,command_group,stats){
|
||||||
if (reversedIDs.includes(id)) {
|
if (reversedIDs.includes(id)) {
|
||||||
style === "positive" ? style = "negative" : style = "positive";
|
style === "positive" ? style = "negative" : style = "positive";
|
||||||
}
|
}
|
||||||
if (id === "poison" && id_val > 0) {
|
|
||||||
id_val = Math.ceil(id_val*stats.get("poisonPct")/100);
|
|
||||||
}
|
|
||||||
displayFixedID(parent_div, id, id_val, elemental_format, style);
|
displayFixedID(parent_div, id, id_val, elemental_format, style);
|
||||||
if (id === "poison" && id_val > 0) {
|
if (id === "ls" && id_val != 0) {
|
||||||
let row = make_elem('div', ['row']);
|
|
||||||
let value_elem = make_elem('div', ['col', 'text-end']);
|
|
||||||
|
|
||||||
let prefix_elem = make_elem('b', [], {textContent: "\u279C With Strength: "});
|
|
||||||
let number_elem = make_elem('b', [style], {
|
|
||||||
textContent: (id_val * (1+skillPointsToPercentage(stats.get('str'))) ).toFixed(0) + idSuffixes[id]
|
|
||||||
});
|
|
||||||
value_elem.append(prefix_elem);
|
|
||||||
value_elem.append(number_elem);
|
|
||||||
row.appendChild(value_elem);
|
|
||||||
parent_div.appendChild(row);
|
|
||||||
}
|
|
||||||
else if (id === "ls" && id_val != 0) {
|
|
||||||
let row = make_elem('div', ['row']);
|
let row = make_elem('div', ['row']);
|
||||||
let value_elem = make_elem('div', ['col', 'text-end']);
|
let value_elem = make_elem('div', ['col', 'text-end']);
|
||||||
|
|
||||||
|
@ -259,7 +253,7 @@ function displayExpandedItem(item, parent_id){
|
||||||
if (item.get("custom")) {
|
if (item.get("custom")) {
|
||||||
item_link = "../custom/#" + item.get("hash");
|
item_link = "../custom/#" + item.get("hash");
|
||||||
} else if (item.get("crafted")) {
|
} else if (item.get("crafted")) {
|
||||||
a_item_link = "../crafter/#" + item.get("hash");
|
item_link = "../crafter/#" + item.get("hash");
|
||||||
} else {
|
} else {
|
||||||
item_link = "../item/#" + item.get("displayName");
|
item_link = "../item/#" + item.get("displayName");
|
||||||
}
|
}
|
||||||
|
@ -286,11 +280,18 @@ function displayExpandedItem(item, parent_id){
|
||||||
parent_div.appendChild(nolink_row);
|
parent_div.appendChild(nolink_row);
|
||||||
|
|
||||||
if (item.has("type")) {
|
if (item.has("type")) {
|
||||||
let img = make_elem("img", [], {
|
let img = make_elem("div", [], {
|
||||||
src: "../media/items/" + (newIcons ? "new/":"old/") + "generic-" + item.get("type") + ".png",
|
|
||||||
alt: item.get("type"),
|
alt: item.get("type"),
|
||||||
style: " z=index: 1; position: relative;"
|
style: "z-index: 1; position: relative; image-rendering: pixelated; width: 50%; height: 50%; background-position: " + itemBGPositions[item.get("type")] + ";"
|
||||||
});
|
});
|
||||||
|
if (["potion", "scroll", "food"].includes(item.get("type"))) {
|
||||||
|
img.style.backgroundImage = "url('../media/items/common.png')";
|
||||||
|
img.style.backgroundSize = "500% 100%";
|
||||||
|
} else {
|
||||||
|
img.style.backgroundImage = "url('../media/items/" + (newIcons ? "new.png')" : "old.png')");
|
||||||
|
img.style.backgroundSize = "1200% 100%";
|
||||||
|
}
|
||||||
|
|
||||||
let container = make_elem("div");
|
let container = make_elem("div");
|
||||||
|
|
||||||
let bckgrd = make_elem("div", ["col", "px-0", "d-flex", "align-items-center", "justify-content-center", 'scaled-bckgrd'], { // , "no-collapse"
|
let bckgrd = make_elem("div", ["col", "px-0", "d-flex", "align-items-center", "justify-content-center", 'scaled-bckgrd'], { // , "no-collapse"
|
||||||
|
@ -377,46 +378,46 @@ function displayExpandedItem(item, parent_id){
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
//Show powder specials ;-;
|
//Show powder specials ;-;
|
||||||
let nonConsumables = ["relik", "wand", "bow", "spear", "dagger", "chestplate", "helmet", "leggings", "boots"];//, "ring", "bracelet", "necklace"];
|
let powder_specials_check = ["relik", "wand", "bow", "spear", "dagger", "chestplate", "helmet", "leggings", "boots"];
|
||||||
if(nonConsumables.includes(item.get("type"))) {
|
if(powder_specials_check.includes(item.get("type"))) {
|
||||||
let powder_special = document.createElement("div");
|
let powder_special = make_elem("div", ['col']);
|
||||||
powder_special.classList.add("col");
|
|
||||||
let powders = item.get("powders");
|
let powders = item.get("powders");
|
||||||
let element = "";
|
let element;
|
||||||
let power = 0;
|
let power_index;
|
||||||
for (let i = 0; i < powders.length; i++) {
|
for (let i = 0; i < powders.length; i++) {
|
||||||
let firstPowderType = skp_elements[Math.floor(powders[i]/6)];
|
const firstPowderType = skp_elements[Math.floor(powders[i]/6)];
|
||||||
if (element !== "") break;
|
const powder1_power = powders[i] % 6;
|
||||||
else if (powders[i]%6 > 2) { //t4+
|
if (powder1_power > 2) { //t4+
|
||||||
for (let j = i+1; j < powders.length; j++) {
|
for (let j = i+1; j < powders.length; j++) {
|
||||||
let currentPowderType = skp_elements[Math.floor(powders[j]/6)]
|
const currentPowderType = skp_elements[Math.floor(powders[j]/6)]
|
||||||
if (powders[j] % 6 > 2 && firstPowderType === currentPowderType) {
|
const powder2_power = powders[j] % 6;
|
||||||
|
if (powder2_power > 2 && firstPowderType === currentPowderType) {
|
||||||
element = currentPowderType;
|
element = currentPowderType;
|
||||||
power = Math.round(((powders[i] % 6 + powders[j] % 6 + 2) / 2 - 4) * 2);
|
power_index = powder1_power + powder2_power - 6;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
if (element) { break; } // terminate early if already found.
|
||||||
}
|
}
|
||||||
if (element !== "") {//powder special is "[e,t,w,f,a]+[0,1,2,3,4]"
|
if (element) {//powder special is "[e,t,w,f,a]+[0,1,2,3,4]"
|
||||||
let powderSpecial = powderSpecialStats[ skp_elements.indexOf(element)];
|
const powderSpecial = powderSpecialStats[skp_elements.indexOf(element)];
|
||||||
let specialSuffixes = new Map([ ["Duration", " sec"], ["Radius", " blocks"], ["Chains", ""], ["Damage", "%"], ["Damage Boost", "%"], ["Knockback", " blocks"] ]);
|
const specialSuffixes = new Map([ ["Duration", " sec"], ["Radius", " blocks"], ["Chains", ""], ["Damage", "%"], ["Damage Boost", "%"], ["Knockback", " blocks"] ]);
|
||||||
let specialTitle = document.createElement("span");
|
const specialTitle = make_elem("span", [damageClasses[skp_elements.indexOf(element) + 1]]);
|
||||||
let specialEffects = document.createElement("span");
|
const specialEffects = document.createElement("span");
|
||||||
addClasses(specialTitle, [damageClasses[skp_elements.indexOf(element) + 1]]);
|
|
||||||
let effects;
|
let effects;
|
||||||
if (item.get("category") === "weapon") {//weapon
|
if (item.get("category") === "weapon") {//weapon
|
||||||
effects = powderSpecial["weaponSpecialEffects"];
|
effects = powderSpecial["weaponSpecialEffects"];
|
||||||
specialTitle.textContent = powderSpecial["weaponSpecialName"];
|
specialTitle.textContent = powderSpecial["weaponSpecialName"];
|
||||||
}else if (item.get("category") === "armor") {//armor
|
} else if (item.get("category") === "armor") {//armor
|
||||||
effects = powderSpecial["armorSpecialEffects"];
|
effects = powderSpecial["armorSpecialEffects"];
|
||||||
specialTitle.textContent += powderSpecial["armorSpecialName"] + ": ";
|
specialTitle.textContent += powderSpecial["armorSpecialName"] + ": ";
|
||||||
}
|
}
|
||||||
for (const [key,value] of effects.entries()) {
|
for (const [key,value] of effects.entries()) {
|
||||||
if (key !== "Description") {
|
if (key !== "Description") {
|
||||||
let effect = document.createElement("p");
|
let effect = make_elem("p", ["m-0"], {
|
||||||
effect.classList.add("m-0");
|
textContent: key + ": " + value[power_index] + specialSuffixes.get(key)
|
||||||
effect.textContent = key + ": " + value[power] + specialSuffixes.get(key);
|
});
|
||||||
if(key === "Damage"){
|
if(key === "Damage"){
|
||||||
effect.textContent += elementIcons[skp_elements.indexOf(element)];
|
effect.textContent += elementIcons[skp_elements.indexOf(element)];
|
||||||
}
|
}
|
||||||
|
@ -424,20 +425,19 @@ function displayExpandedItem(item, parent_id){
|
||||||
effect.textContent += " / Mana Used";
|
effect.textContent += " / Mana Used";
|
||||||
}
|
}
|
||||||
specialEffects.appendChild(effect);
|
specialEffects.appendChild(effect);
|
||||||
}else{
|
} else {
|
||||||
specialTitle.textContent += "[ " + effects.get("Description") + " ]";
|
specialTitle.textContent += "[ " + effects.get("Description") + " ]";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
powder_special.appendChild(specialTitle);
|
powder_special.append(specialTitle, specialEffects);
|
||||||
powder_special.appendChild(specialEffects);
|
|
||||||
parent_div.appendChild(powder_special);
|
parent_div.appendChild(powder_special);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
let nonConsumables = ["relik", "wand", "bow", "spear", "dagger", "chestplate", "helmet", "leggings", "boots", "ring", "bracelet", "necklace"];
|
||||||
if(item.get("tier") && item.get("tier") === "Crafted") {
|
if(item.get("tier") && item.get("tier") === "Crafted") {
|
||||||
let dura_elem = document.createElement("div");
|
let dura_elem = make_elem("div", ["col"]);
|
||||||
dura_elem.classList.add("col");
|
let dura;
|
||||||
let dura = [];
|
|
||||||
let suffix = "";
|
let suffix = "";
|
||||||
if(nonConsumables.includes(item.get("type"))) {
|
if(nonConsumables.includes(item.get("type"))) {
|
||||||
dura = item.get("durability");
|
dura = item.get("durability");
|
||||||
|
@ -446,9 +446,9 @@ function displayExpandedItem(item, parent_id){
|
||||||
dura = item.get("duration");
|
dura = item.get("duration");
|
||||||
dura_elem.textContent = "Duration: "
|
dura_elem.textContent = "Duration: "
|
||||||
suffix = " sec."
|
suffix = " sec."
|
||||||
let charges = document.createElement("b");
|
parent_div.appendChild(make_elem('b', [], {
|
||||||
charges.textContent = "Charges: " + item.get("charges");
|
textContent: "Charges: " + item.get("charges")
|
||||||
parent_div.appendChild(charges);
|
}));
|
||||||
}
|
}
|
||||||
|
|
||||||
if (typeof(dura) === "string") {
|
if (typeof(dura) === "string") {
|
||||||
|
@ -461,9 +461,7 @@ function displayExpandedItem(item, parent_id){
|
||||||
}
|
}
|
||||||
//Show item tier
|
//Show item tier
|
||||||
if (item.get("tier") && item.get("tier") !== " ") {
|
if (item.get("tier") && item.get("tier") !== " ") {
|
||||||
let item_desc_elem = document.createElement("div");
|
let item_desc_elem = make_elem("div", ["col", item.get("tier")]);
|
||||||
item_desc_elem.classList.add("col");
|
|
||||||
item_desc_elem.classList.add(item.get("tier"));
|
|
||||||
if (tome_types.includes(item.get("type"))) {
|
if (tome_types.includes(item.get("type"))) {
|
||||||
tome_type_map = new Map([["weaponTome", "Weapon Tome"],["armorTome", "Armor Tome"],["guildTome", "Guild Tome"]]);
|
tome_type_map = new Map([["weaponTome", "Weapon Tome"],["armorTome", "Armor Tome"],["guildTome", "Guild Tome"]]);
|
||||||
item_desc_elem.textContent = item.get("tier")+" "+tome_type_map.get(item.get("type"));
|
item_desc_elem.textContent = item.get("tier")+" "+tome_type_map.get(item.get("type"));
|
||||||
|
@ -475,20 +473,19 @@ function displayExpandedItem(item, parent_id){
|
||||||
|
|
||||||
//Show item hash if applicable
|
//Show item hash if applicable
|
||||||
if (item.get("crafted") || item.get("custom")) {
|
if (item.get("crafted") || item.get("custom")) {
|
||||||
let item_desc_elem = document.createElement("p");
|
parent_div.append(make_elem('p', ['itemp'], {
|
||||||
item_desc_elem.classList.add('itemp');
|
style: {
|
||||||
item_desc_elem.style.maxWidth = "100%";
|
maxWidth: '100%',
|
||||||
item_desc_elem.style.wordWrap = "break-word";
|
wordWrap: 'break-word',
|
||||||
item_desc_elem.style.wordBreak = "break-word";
|
wordBreak: 'break-word'
|
||||||
item_desc_elem.textContent = item.get("hash");
|
},
|
||||||
parent_div.append(item_desc_elem);
|
textContent: item.get('hash')
|
||||||
|
}));
|
||||||
}
|
}
|
||||||
|
|
||||||
if (item.get("category") === "weapon") {
|
if (item.get("category") === "weapon") {
|
||||||
let total_damages = item.get("basedps");
|
let total_damages = item.get("basedps");
|
||||||
let base_dps_elem = document.createElement("p");
|
let base_dps_elem = make_elem("p", ["left", "itemp"]);
|
||||||
base_dps_elem.classList.add("left");
|
|
||||||
base_dps_elem.classList.add("itemp");
|
|
||||||
if (item.get("tier") === "Crafted") {
|
if (item.get("tier") === "Crafted") {
|
||||||
let base_dps_min = total_damages[0];
|
let base_dps_min = total_damages[0];
|
||||||
let base_dps_max = total_damages[1];
|
let base_dps_max = total_damages[1];
|
||||||
|
@ -498,8 +495,7 @@ function displayExpandedItem(item, parent_id){
|
||||||
else {
|
else {
|
||||||
base_dps_elem.textContent = "Base DPS: "+(total_damages);
|
base_dps_elem.textContent = "Base DPS: "+(total_damages);
|
||||||
}
|
}
|
||||||
parent_div.appendChild(document.createElement("p"));
|
parent_div.append(make_elem("p"), base_dps_elem);
|
||||||
parent_div.appendChild(base_dps_elem);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -987,9 +983,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;
|
||||||
}
|
}
|
||||||
|
@ -1003,7 +999,8 @@ 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.floor(statMap.get("poison")/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(
|
||||||
|
@ -1257,8 +1254,8 @@ function displayPowderSpecials(parent_elem, powderSpecials, stats, weapon, overa
|
||||||
//iterate through the special and display its effects.
|
//iterate through the special and display its effects.
|
||||||
let powder_special = make_elem("p", ["pt-3"]);
|
let powder_special = make_elem("p", ["pt-3"]);
|
||||||
let specialSuffixes = new Map([ ["Duration", " sec"], ["Radius", " blocks"], ["Chains", ""], ["Damage", "%"], ["Damage Boost", "%"], ["Knockback", " blocks"] ]);
|
let specialSuffixes = new Map([ ["Duration", " sec"], ["Radius", " blocks"], ["Chains", ""], ["Damage", "%"], ["Damage Boost", "%"], ["Knockback", " blocks"] ]);
|
||||||
let specialTitle = document.createElement("p");
|
let specialTitle = make_elem("p");
|
||||||
let specialEffects = document.createElement("p");
|
let specialEffects = make_elem("p");
|
||||||
specialTitle.classList.add(damageClasses[powderSpecialStats.indexOf(special[0]) + 1]);
|
specialTitle.classList.add(damageClasses[powderSpecialStats.indexOf(special[0]) + 1]);
|
||||||
let effects = special[0]["weaponSpecialEffects"];
|
let effects = special[0]["weaponSpecialEffects"];
|
||||||
let power = special[1];
|
let power = special[1];
|
||||||
|
@ -1382,7 +1379,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) {
|
||||||
|
@ -1445,6 +1442,7 @@ function displaySpellDamage(parent_elem, _overallparent_elem, stats, spell, spel
|
||||||
|
|
||||||
for (let i = 0; i < spell_results.length; ++i) {
|
for (let i = 0; i < spell_results.length; ++i) {
|
||||||
const spell_info = spell_results[i];
|
const spell_info = spell_results[i];
|
||||||
|
if (!spell_info.display) { continue; }
|
||||||
|
|
||||||
let part_div = make_elem("p", ["pt-3"]);
|
let part_div = make_elem("p", ["pt-3"]);
|
||||||
parent_elem.append(part_div);
|
parent_elem.append(part_div);
|
||||||
|
@ -1499,9 +1497,7 @@ function displaySpellDamage(parent_elem, _overallparent_elem, stats, spell, spel
|
||||||
_damage_display("Crit Average: ", critAverage, spell_info.crit_min, spell_info.crit_max);
|
_damage_display("Crit Average: ", critAverage, spell_info.crit_min, spell_info.crit_max);
|
||||||
} else if (spell_info.type === "heal") {
|
} else if (spell_info.type === "heal") {
|
||||||
let heal_amount = spell_info.heal_amount;
|
let heal_amount = spell_info.heal_amount;
|
||||||
let healLabel = document.createElement("p");
|
let healLabel = make_elem("p", ["Set"], {textContent: heal_amount.toFixed(2)});
|
||||||
healLabel.textContent = heal_amount;
|
|
||||||
// healLabel.classList.add("damagep");
|
|
||||||
part_div.append(healLabel);
|
part_div.append(healLabel);
|
||||||
if (spell_info.name === spell.display) {
|
if (spell_info.name === spell.display) {
|
||||||
add_summary(spell_info.name+ ": ", heal_amount, "Set");
|
add_summary(spell_info.name+ ": ", heal_amount, "Set");
|
||||||
|
@ -1513,417 +1509,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" });
|
||||||
|
|
|
@ -40,9 +40,37 @@ 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: ",
|
||||||
|
"rSdRaw":"Elem. Spell Damage Raw: ",
|
||||||
|
"nSdRaw":"Neut. Spell Damage Raw: ",
|
||||||
|
"eSdRaw":"Raw Earth Spell Damage: ",
|
||||||
|
"tSdRaw":"Raw Thunder Spell Damage: ",
|
||||||
|
"wSdRaw":"Raw Water Spell Damage: ",
|
||||||
|
"fSdRaw":"Raw Fire Spell Damage: ",
|
||||||
|
"aSdRaw":"Raw Air Spell Damage: ",
|
||||||
"sdPct":"Spell Damage %: ",
|
"sdPct":"Spell Damage %: ",
|
||||||
|
"rSdPct":"Elem. Spell Damage %: ",
|
||||||
|
"nSdPct":"Neut. Spell Damage %: ",
|
||||||
|
"eSdPct":"% Earth Spell Damage: ",
|
||||||
|
"tSdPct":"% Thunder Spell Damage: ",
|
||||||
|
"wSdPct":"% Water Spell Damage: ",
|
||||||
|
"fSdPct":"% Fire Spell Damage: ",
|
||||||
|
"aSdPct":"% Air Spell Damage: ",
|
||||||
"mdRaw":"Raw Melee Damage: ",
|
"mdRaw":"Raw Melee Damage: ",
|
||||||
|
"rMdRaw":"Elem. Melee Damage Raw: ",
|
||||||
|
"nMdRaw":"Neut. Melee Damage Raw: ",
|
||||||
|
"eMdRaw":"Raw Earth Melee Damage: ",
|
||||||
|
"tMdRaw":"Raw Thunder Melee Damage: ",
|
||||||
|
"wMdRaw":"Raw Water Melee Damage: ",
|
||||||
|
"fMdRaw":"Raw Fire Melee Damage: ",
|
||||||
|
"aMdRaw":"Raw Air Melee Damage: ",
|
||||||
"mdPct":"Melee Damage %: ",
|
"mdPct":"Melee Damage %: ",
|
||||||
|
"rMdPct":"Elem. Melee Damage %: ",
|
||||||
|
"nMdPct":"Neut. Melee Damage %: ",
|
||||||
|
"eMdPct":"% Earth Melee Damage: ",
|
||||||
|
"tMdPct":"% Thunder Melee Damage: ",
|
||||||
|
"wMdPct":"% Water Melee Damage: ",
|
||||||
|
"fMdPct":"% Fire Melee Damage: ",
|
||||||
|
"aMdPct":"% Air Melee Damage: ",
|
||||||
"mr":"Mana Regen: ",
|
"mr":"Mana Regen: ",
|
||||||
"ms":"Mana Steal: ",
|
"ms":"Mana Steal: ",
|
||||||
"ref":"Reflection: ",
|
"ref":"Reflection: ",
|
||||||
|
@ -70,7 +98,6 @@ 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: ",
|
|
||||||
"sprint":"Sprint Bonus: ",
|
"sprint":"Sprint Bonus: ",
|
||||||
"sprintReg":"Sprint Regen Bonus: ",
|
"sprintReg":"Sprint Regen Bonus: ",
|
||||||
"jh":"Jump Height: ",
|
"jh":"Jump Height: ",
|
||||||
|
@ -117,9 +144,37 @@ let idSuffixes = {"displayName": "",
|
||||||
"hprRaw":"",
|
"hprRaw":"",
|
||||||
"hprPct":"%",
|
"hprPct":"%",
|
||||||
"sdRaw":"",
|
"sdRaw":"",
|
||||||
|
"rSdRaw":"",
|
||||||
|
"nSdRaw":"",
|
||||||
|
"eSdRaw":"",
|
||||||
|
"tSdRaw":"",
|
||||||
|
"wSdRaw":"",
|
||||||
|
"fSdRaw":"",
|
||||||
|
"aSdRaw":"",
|
||||||
"sdPct":"%",
|
"sdPct":"%",
|
||||||
|
"rSdPct":"%",
|
||||||
|
"nSdPct":"%",
|
||||||
|
"eSdPct":"%",
|
||||||
|
"tSdPct":"%",
|
||||||
|
"wSdPct":"%",
|
||||||
|
"fSdPct":"%",
|
||||||
|
"aSdPct":"%",
|
||||||
"mdRaw":"",
|
"mdRaw":"",
|
||||||
|
"rMdRaw":"",
|
||||||
|
"nMdRaw":"",
|
||||||
|
"eMdRaw":"",
|
||||||
|
"tMdRaw":"",
|
||||||
|
"wMdRaw":"",
|
||||||
|
"fMdRaw":"",
|
||||||
|
"aMdRaw":"",
|
||||||
"mdPct":"%",
|
"mdPct":"%",
|
||||||
|
"rMdPct":"%",
|
||||||
|
"nMdPct":"%",
|
||||||
|
"eMdPct":"%",
|
||||||
|
"tMdPct":"%",
|
||||||
|
"wMdPct":"%",
|
||||||
|
"fMdPct":"%",
|
||||||
|
"aMdPct":"%",
|
||||||
"mr":"/5s",
|
"mr":"/5s",
|
||||||
"ms":"/3s",
|
"ms":"/3s",
|
||||||
"ref":"%",
|
"ref":"%",
|
||||||
|
@ -147,7 +202,6 @@ let idSuffixes = {"displayName": "",
|
||||||
"spRaw3":"",
|
"spRaw3":"",
|
||||||
"spPct4":"%",
|
"spPct4":"%",
|
||||||
"spRaw4":"",
|
"spRaw4":"",
|
||||||
"rainbowRaw":"",
|
|
||||||
"sprint":"%",
|
"sprint":"%",
|
||||||
"sprintReg":"%",
|
"sprintReg":"%",
|
||||||
"jh":"",
|
"jh":"",
|
||||||
|
@ -209,25 +263,16 @@ let posModSuffixes = {
|
||||||
/*
|
/*
|
||||||
* Display commands
|
* Display commands
|
||||||
*/
|
*/
|
||||||
let build_all_display_commands = [
|
let build_overall_display_commands = [
|
||||||
"#defense-stats",
|
"#defense-stats",
|
||||||
"str", "dex", "int", "def", "agi",
|
"str", "dex", "int", "def", "agi",
|
||||||
"!spacer",
|
"!spacer",
|
||||||
"mr", "ms",
|
"mr", "ms",
|
||||||
"hprRaw", "hprPct",
|
|
||||||
"ls",
|
"ls",
|
||||||
"sdRaw", "sdPct",
|
|
||||||
"mdRaw", "mdPct",
|
|
||||||
"!elemental",
|
|
||||||
"fDamPct", "wDamPct", "aDamPct", "tDamPct", "eDamPct",
|
|
||||||
"!elemental",
|
|
||||||
"spPct1", "spRaw1", "spPct2", "spRaw2", "spPct3", "spRaw3", "spPct4", "spRaw4",
|
|
||||||
"atkTier",
|
|
||||||
"poison",
|
"poison",
|
||||||
"ref", "thorns",
|
"ref", "thorns",
|
||||||
"expd",
|
"expd",
|
||||||
"spd",
|
"spd",
|
||||||
"rainbowRaw",
|
|
||||||
"sprint", "sprintReg",
|
"sprint", "sprintReg",
|
||||||
"jh",
|
"jh",
|
||||||
"xpb", "lb", "lq",
|
"xpb", "lb", "lq",
|
||||||
|
@ -236,24 +281,65 @@ let build_all_display_commands = [
|
||||||
"gXp", "gSpd",
|
"gXp", "gSpd",
|
||||||
];
|
];
|
||||||
|
|
||||||
let build_offensive_display_commands = [
|
let build_detailed_display_commands = [
|
||||||
|
"#defense-stats",
|
||||||
"str", "dex", "int", "def", "agi",
|
"str", "dex", "int", "def", "agi",
|
||||||
|
"!spacer",
|
||||||
"mr", "ms",
|
"mr", "ms",
|
||||||
"sdRaw", "sdPct",
|
"hprRaw", "hprPct",
|
||||||
"mdRaw", "mdPct",
|
|
||||||
"ref", "thorns",
|
|
||||||
"ls",
|
"ls",
|
||||||
"poison",
|
"sdRaw", "nSdRaw", "rSdRaw",
|
||||||
"expd",
|
"sdPct", "nSdPct", "rSdPct",
|
||||||
"spd",
|
"mdRaw", "nMdRaw", "rMdRaw",
|
||||||
"atkTier",
|
"mdPct", "nMdPct", "rMdPct",
|
||||||
"rainbowRaw",
|
|
||||||
"!elemental",
|
"!elemental",
|
||||||
|
"fSdRaw", "wSdRaw", "aSdRaw", "tSdRaw", "eSdRaw",
|
||||||
|
"fSdPct", "wSdPct", "aSdPct", "tSdPct", "eSdPct",
|
||||||
|
"fMdRaw", "wMdRaw", "aMdRaw", "tMdRaw", "eMdRaw",
|
||||||
|
"fMdPct", "wMdPct", "aMdPct", "tMdPct", "eMdPct",
|
||||||
"fDamPct", "wDamPct", "aDamPct", "tDamPct", "eDamPct",
|
"fDamPct", "wDamPct", "aDamPct", "tDamPct", "eDamPct",
|
||||||
"!elemental",
|
"!elemental",
|
||||||
"spPct1", "spRaw1", "spPct2", "spRaw2", "spPct3", "spRaw3", "spPct4", "spRaw4",
|
"spPct1", "spRaw1", "spPct2", "spRaw2", "spPct3", "spRaw3", "spPct4", "spRaw4",
|
||||||
|
"atkTier",
|
||||||
|
"poison",
|
||||||
|
"ref", "thorns",
|
||||||
|
"expd",
|
||||||
|
"spd",
|
||||||
|
"rSdRaw",
|
||||||
|
"sprint", "sprintReg",
|
||||||
|
"jh",
|
||||||
|
"xpb", "lb", "lq",
|
||||||
|
"spRegen",
|
||||||
|
"eSteal",
|
||||||
|
"gXp", "gSpd",
|
||||||
];
|
];
|
||||||
|
|
||||||
|
// full
|
||||||
|
//"#defense-stats",
|
||||||
|
//"str", "dex", "int", "def", "agi",
|
||||||
|
//"!spacer",
|
||||||
|
//"mr", "ms",
|
||||||
|
//"hprRaw", "hprPct",
|
||||||
|
//"ls",
|
||||||
|
//"sdRaw", "sdPct",
|
||||||
|
//"mdRaw", "mdPct",
|
||||||
|
//"!elemental",
|
||||||
|
//"fDamPct", "wDamPct", "aDamPct", "tDamPct", "eDamPct",
|
||||||
|
//"!elemental",
|
||||||
|
//"spPct1", "spRaw1", "spPct2", "spRaw2", "spPct3", "spRaw3", "spPct4", "spRaw4",
|
||||||
|
//"atkTier",
|
||||||
|
//"poison",
|
||||||
|
//"ref", "thorns",
|
||||||
|
//"expd",
|
||||||
|
//"spd",
|
||||||
|
//"rainbowRaw",
|
||||||
|
//"sprint", "sprintReg",
|
||||||
|
//"jh",
|
||||||
|
//"xpb", "lb", "lq",
|
||||||
|
//"spRegen",
|
||||||
|
//"eSteal",
|
||||||
|
//"gXp", "gSpd",
|
||||||
|
|
||||||
let build_basic_display_commands = [
|
let build_basic_display_commands = [
|
||||||
'#defense-stats',
|
'#defense-stats',
|
||||||
// defense stats [hp, ehp, hpr, ]
|
// defense stats [hp, ehp, hpr, ]
|
||||||
|
@ -283,8 +369,10 @@ let sq2_item_display_commands = [
|
||||||
"str", "dex", "int", "def", "agi",
|
"str", "dex", "int", "def", "agi",
|
||||||
"hpBonus",
|
"hpBonus",
|
||||||
"hprRaw", "hprPct",
|
"hprRaw", "hprPct",
|
||||||
"sdRaw", "sdPct",
|
"sdRaw", "nSdRaw", "eSdRaw", "tSdRaw", "wSdRaw", "fSdRaw", "aSdRaw", "rSdRaw",
|
||||||
"mdRaw", "mdPct",
|
"sdPct", "nSdPct", "eSdPct", "tSdPct", "wSdPct", "fSdPct", "aSdPct", "rSdPct",
|
||||||
|
"mdRaw", "nMdRaw", "eMdRaw", "tMdRaw", "wMdRaw", "fMdRaw", "aMdRaw", "rMdRaw",
|
||||||
|
"mdPct", "nMdPct", "eMdPct", "tMdPct", "wMdPct", "fMdPct", "aMdPct", "rMdPct",
|
||||||
"mr", "ms",
|
"mr", "ms",
|
||||||
"ref", "thorns",
|
"ref", "thorns",
|
||||||
"ls",
|
"ls",
|
||||||
|
@ -297,7 +385,6 @@ 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",
|
|
||||||
"sprint", "sprintReg",
|
"sprint", "sprintReg",
|
||||||
"jh",
|
"jh",
|
||||||
"xpb", "lb", "lq",
|
"xpb", "lb", "lq",
|
||||||
|
|
8
js/drag_drop_touch.js
Normal file
33
js/icons.js
|
@ -1,33 +1,26 @@
|
||||||
//which icons to use
|
|
||||||
let window_storage = window.localStorage;
|
let window_storage = window.localStorage;
|
||||||
icon_state_stored = window_storage.getItem("newicons");
|
|
||||||
newIcons = true;
|
newIcons = true;
|
||||||
if (icon_state_stored === "false") {toggleIcons()}
|
if (window_storage.getItem("newicons") === "false") {
|
||||||
|
toggleIcons();
|
||||||
|
}
|
||||||
|
|
||||||
/** Toggle icons on the ENTIRE page.
|
/** Toggle icons on the ENTIRE page.
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
function toggleIcons() {
|
function toggleIcons() {
|
||||||
newIcons = !newIcons;
|
newIcons = !newIcons;
|
||||||
let imgs = document.getElementsByTagName("IMG");
|
window_storage.setItem("newicons", newIcons.toString());
|
||||||
let favicon = document.querySelector("link[rel~='icon']");
|
let newOrOld = (newIcons ? "new" : "old");
|
||||||
let toggleiconbutton = document.getElementById("toggle-icon-button");
|
|
||||||
|
|
||||||
if (newIcons) { //switch to new
|
let imgs = document.getElementsByTagName("img");
|
||||||
favicon.href = favicon.href.replace("media/icons/old","media/icons/new");
|
let divs = document.getElementsByClassName("item-display-new-toggleable");
|
||||||
|
let favicon = document.querySelector("link[rel~='icon']");
|
||||||
|
favicon.href = favicon.href.replace("media/icons/" + (newIcons ? "old" : "new"), "media/icons/" + newOrOld);
|
||||||
for (const img of imgs) {
|
for (const img of imgs) {
|
||||||
if (img.src.includes("media/icons/old")) {img.src = img.src.replace("media/icons/old","media/icons/new");}
|
// if doesn't contain, replace() does nothing
|
||||||
if (img.src.includes("media/items/old")) {img.src = img.src.replace("media/items/old","media/items/new");}
|
img.src = img.src.replace("media/icons/" + (newIcons ? "old" : "new"), "media/icons/" + newOrOld);
|
||||||
}
|
}
|
||||||
toggleiconbutton.textContent = "Use Old Icons";
|
for (let i = 0; i < divs.length; i++) {
|
||||||
window_storage.setItem("newicons","true");
|
divs.item(i).style.backgroundImage = "url('../media/items/" + (newIcons ? "new" : "old") + ".png')";
|
||||||
} else { //switch to old
|
|
||||||
favicon.href = favicon.href.replace("media/icons/new","media/icons/old");
|
|
||||||
for (const img of imgs) {
|
|
||||||
if (img.src.includes("media/icons/new")) {img.src = img.src.replace("media/icons/new","media/icons/old");}
|
|
||||||
if (img.src.includes("media/items/new")) {img.src = img.src.replace("media/items/new","media/items/old");}
|
|
||||||
}
|
|
||||||
toggleiconbutton.textContent = "Use New Icons";
|
|
||||||
window_storage.setItem("newicons","false");
|
|
||||||
}
|
}
|
||||||
}
|
}
|
501
js/items.js
|
@ -1,17 +1,12 @@
|
||||||
const translate_mappings = {
|
// commented out filters
|
||||||
//"Name": "name",
|
//"Name": "name",
|
||||||
//"Display Name": "displayName",
|
//"Display Name": "displayName",
|
||||||
//"tier"Tier": ",
|
//"Tier": "tier",
|
||||||
//"Set": "set",
|
//"Set": "set",
|
||||||
"Powder Slots": "slots",
|
|
||||||
//"Type": "type",
|
//"Type": "type",
|
||||||
//"armorType", (deleted)
|
//"Drop type": "drop", BROKEN
|
||||||
//"color", (deleted)
|
//"Quest requirement": "quest", BROKEN
|
||||||
//"lore", (deleted)
|
//"Restriction": "restrict", BROKEN
|
||||||
//"material", (deleted)
|
|
||||||
"Drop type": "drop",
|
|
||||||
"Quest requirement": "quest",
|
|
||||||
"Restriction": "restrict",
|
|
||||||
//"Base Neutral Damage": "nDam",
|
//"Base Neutral Damage": "nDam",
|
||||||
//"Base Fire Damage": "fDam",
|
//"Base Fire Damage": "fDam",
|
||||||
//"Base Water Damage": "wDam",
|
//"Base Water Damage": "wDam",
|
||||||
|
@ -19,6 +14,13 @@ const translate_mappings = {
|
||||||
//"Base Thunder Damage": "tDam",
|
//"Base Thunder Damage": "tDam",
|
||||||
//"Base Earth Damage": "eDam",
|
//"Base Earth Damage": "eDam",
|
||||||
//"Base Attack Speed": "atkSpd",
|
//"Base Attack Speed": "atkSpd",
|
||||||
|
//"Class Requirement": "classReq",
|
||||||
|
// "Fixed IDs": "fixID", BROKEN
|
||||||
|
// "Custom Skin": "skin", BROKEN
|
||||||
|
//"Item Category": "category",
|
||||||
|
|
||||||
|
const translate_mappings = {
|
||||||
|
"Powder Slots": "slots",
|
||||||
"Health": "hp",
|
"Health": "hp",
|
||||||
"Raw Fire Defense": "fDef",
|
"Raw Fire Defense": "fDef",
|
||||||
"Raw Water Defense": "wDef",
|
"Raw Water Defense": "wDef",
|
||||||
|
@ -26,7 +28,6 @@ const translate_mappings = {
|
||||||
"Raw Thunder Defense": "tDef",
|
"Raw Thunder Defense": "tDef",
|
||||||
"Raw Earth Defense": "eDef",
|
"Raw Earth Defense": "eDef",
|
||||||
"Combat Level": "lvl",
|
"Combat Level": "lvl",
|
||||||
//"Class Requirement": "classReq",
|
|
||||||
"Req Strength": "strReq",
|
"Req Strength": "strReq",
|
||||||
"Req Dexterity": "dexReq",
|
"Req Dexterity": "dexReq",
|
||||||
"Req Intelligence": "intReq",
|
"Req Intelligence": "intReq",
|
||||||
|
@ -67,10 +68,6 @@ const translate_mappings = {
|
||||||
"% Air Defense": "aDefPct",
|
"% Air Defense": "aDefPct",
|
||||||
"% Thunder Defense": "tDefPct",
|
"% Thunder Defense": "tDefPct",
|
||||||
"% Earth Defense": "eDefPct",
|
"% Earth Defense": "eDefPct",
|
||||||
"Fixed IDs": "fixID",
|
|
||||||
"Custom Skin": "skin",
|
|
||||||
//"Item Category": "category",
|
|
||||||
|
|
||||||
"1st Spell Cost %": "-spPct1",
|
"1st Spell Cost %": "-spPct1",
|
||||||
"1st Spell Cost Raw": "-spRaw1",
|
"1st Spell Cost Raw": "-spRaw1",
|
||||||
"2nd Spell Cost %": "-spPct2",
|
"2nd Spell Cost %": "-spPct2",
|
||||||
|
@ -79,129 +76,180 @@ const translate_mappings = {
|
||||||
"3rd Spell Cost Raw": "-spRaw3",
|
"3rd Spell Cost Raw": "-spRaw3",
|
||||||
"4th Spell Cost %": "-spPct4",
|
"4th Spell Cost %": "-spPct4",
|
||||||
"4th Spell Cost Raw": "-spRaw4",
|
"4th Spell Cost Raw": "-spRaw4",
|
||||||
|
"Rainbow Spell Damage Raw": "rainbowRaw",
|
||||||
"Rainbow Spell Damage": "rainbowRaw",
|
|
||||||
"Sprint": "sprint",
|
"Sprint": "sprint",
|
||||||
"Sprint Regen": "sprintReg",
|
"Sprint Regen": "sprintReg",
|
||||||
"Jump Height": "jh",
|
"Jump Height": "jh",
|
||||||
"Loot Quality": "lq",
|
"Loot Quality": "lq",
|
||||||
|
|
||||||
"Gather XP Bonus": "gXp",
|
"Gather XP Bonus": "gXp",
|
||||||
"Gather Speed Bonus": "gSpd",
|
"Gather Speed Bonus": "gSpd"
|
||||||
};
|
};
|
||||||
|
|
||||||
const special_mappings = {
|
const special_mappings = {
|
||||||
"Sum (skill points)": "s:str+dex+int+def+agi",
|
"Sum (skill points)": "str+dex+int+def+agi",
|
||||||
"Sum (Mana Sustain)": "s:mr+ms",
|
"Sum (Mana Sustain)": "mr+ms",
|
||||||
"Sum (Life Sustain)": "s:hpr+ls",
|
"Sum (Life Sustain)": "hpr+ls",
|
||||||
"Sum (Health + Health Bonus)": "s:hp+hpBonus",
|
"Sum (Health + Health Bonus)": "hp+hpBonus",
|
||||||
"No Strength Req": "f:strReq=0",
|
"Base DPS": "(nDam+fDam+wDam+aDam+tDam+eDam) * atkspdmod(atkspd)"
|
||||||
"No Dexterity Req": "f:dexReq=0",
|
|
||||||
"No Intelligence Req": "f:intReq=0",
|
|
||||||
"No Agility Req": "f:agiReq=0",
|
|
||||||
"No Defense Req": "f:defReq=0",
|
|
||||||
};
|
};
|
||||||
|
|
||||||
let itemFilters = document.getElementById("filter-items");
|
let item_filters = [];
|
||||||
if (itemFilters) {
|
for (let x in translate_mappings) {
|
||||||
for (let x in translate_mappings) {
|
item_filters.push(x);
|
||||||
let el = document.createElement("option");
|
}
|
||||||
el.value = x;
|
for (let x in special_mappings) {
|
||||||
itemFilters.appendChild(el);
|
item_filters.push(x);
|
||||||
}
|
|
||||||
for (let x in special_mappings) {
|
|
||||||
let el = document.createElement("option");
|
|
||||||
el.value = x;
|
|
||||||
itemFilters.appendChild(el);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
let itemCategories = [ "armor", "accessory", "weapon" ];
|
let item_categories = ["armor", "accessory", "weapon"];
|
||||||
|
|
||||||
function applyQuery(items, query) {
|
const types = {bow: false, spear: false, wand: false, dagger: false, relik: false, helmet: false, chestplate: false, leggings: false, boots: false, ring: false, bracelet: false, necklace: false};
|
||||||
return items.filter(query.filter, query).sort(query.compare);
|
const rarities = {normal: true, unique: true, set: true, rare: true, legendary: true, fabled: true, mythic: true};
|
||||||
}
|
const filters = [], excludes = [];
|
||||||
|
let filter_id_counter = 0;
|
||||||
|
|
||||||
function displayItems(results) {
|
function displayItems(items_copy) {
|
||||||
let items_parent = document.getElementById("main");
|
let items_parent = document.getElementById("search-results");
|
||||||
for (let i in results) {
|
for (let i in items_copy) {
|
||||||
let item = results[i].itemExp;
|
if (i > 200) {break;}
|
||||||
let box = document.createElement("div");
|
let item = items_copy[i].itemExp;
|
||||||
box.classList.add("box");
|
let box = make_elem('div', ['col-lg-3', 'col-sm-6', 'p-2'], {id: 'item'+i});
|
||||||
box.id = "item"+i;
|
|
||||||
|
let bckgrdbox = make_elem("div", ["dark-7", "rounded", "px-2", "col-auto"], {id: 'item'+i+'b'});
|
||||||
|
box.append(bckgrdbox);
|
||||||
items_parent.appendChild(box);
|
items_parent.appendChild(box);
|
||||||
displayExpandedItem(item, box.id);
|
item.set("powders", []);
|
||||||
|
if (item.get("category") == "weapon") {
|
||||||
|
apply_weapon_powders(item);
|
||||||
|
}
|
||||||
|
displayExpandedItem(item, bckgrdbox.id, true);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
let searchDb;
|
let search_db;
|
||||||
|
let expr_parser;
|
||||||
|
|
||||||
function doItemSearch() {
|
function do_item_search() {
|
||||||
|
document.getElementById("summary").style.color = "red"; // to display errors, changed to white if search successful
|
||||||
window.scrollTo(0, 0);
|
window.scrollTo(0, 0);
|
||||||
let queries = [];
|
let queries = [];
|
||||||
queries.push('f:name?="'+document.getElementById("item-name-choice").value.trim()+'"');
|
|
||||||
|
|
||||||
let categoryOrType = document.getElementById("item-category-choice").value;
|
// name
|
||||||
if (itemTypes.includes(categoryOrType)) {
|
if (document.getElementById("item-name-choice").value != "") {
|
||||||
queries.push('f:type="'+categoryOrType+'"');
|
queries.push("f:name?=\"" + document.getElementById("item-name-choice").value.trim() + "\"");
|
||||||
}
|
|
||||||
else if (itemCategories.includes(categoryOrType)) {
|
|
||||||
queries.push('f:cat="'+categoryOrType+'"');
|
|
||||||
}
|
}
|
||||||
|
|
||||||
let rarity = document.getElementById("item-rarity-choice").value;
|
// types
|
||||||
if (rarity) {
|
let allTypes = true, noTypes = true;
|
||||||
if (rarity === "ANY") {
|
let typeQuery = "f:("
|
||||||
|
for (const type of Object.keys(types)) {
|
||||||
|
if (types[type]) {
|
||||||
|
typeQuery += "type=\"" + type + "\"|";
|
||||||
|
noTypes = false;
|
||||||
|
} else {
|
||||||
|
allTypes = false;
|
||||||
}
|
}
|
||||||
else if (rarity === "Sane") {
|
|
||||||
queries.push('f:tiername!="mythic"');
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
queries.push('f:tiername="'+rarity+'"');
|
|
||||||
}
|
}
|
||||||
|
if (noTypes) {
|
||||||
|
document.getElementById("summary").innerHTML = "Error: Cannot search without at least 1 type selected";
|
||||||
|
return;
|
||||||
|
} else if (!allTypes) {
|
||||||
|
queries.push(typeQuery.substring(0, typeQuery.length - 1) + ")");
|
||||||
}
|
}
|
||||||
|
|
||||||
let level_dat = document.getElementById("item-level-choice").value.split("-");
|
// rarities
|
||||||
queries.push('f:(lvl>='+parseInt(level_dat[0])+'&lvl<='+parseInt(level_dat[1])+')');
|
let allRarities = true, noRarities = true;
|
||||||
|
let rarityQuery = "f:("
|
||||||
for (let i = 1; i <= 4; ++i) {
|
for (const rarity of Object.keys(rarities)) {
|
||||||
let raw_dat = document.getElementById("filter"+i+"-choice").value;
|
if (rarities[rarity]) {
|
||||||
let filter_dat = translate_mappings[raw_dat];
|
rarityQuery += "tiername=\"" + rarity + "\"|";
|
||||||
if (filter_dat !== undefined) {
|
noRarities = false;
|
||||||
queries.push("s:"+filter_dat);
|
} else {
|
||||||
queries.push("f:"+filter_dat+"!=0");
|
allRarities = false;
|
||||||
continue;
|
|
||||||
}
|
}
|
||||||
filter_dat = special_mappings[raw_dat];
|
|
||||||
if (filter_dat !== undefined) {
|
|
||||||
queries.push(filter_dat);
|
|
||||||
continue;
|
|
||||||
}
|
}
|
||||||
|
if (noRarities) {
|
||||||
|
document.getElementById("summary").innerHTML = "Error: Cannot search without at least 1 rarity selected";
|
||||||
|
return;
|
||||||
|
} else if (!allRarities) {
|
||||||
|
queries.push(rarityQuery.substring(0, rarityQuery.length - 1) + ")");
|
||||||
}
|
}
|
||||||
|
|
||||||
let filterQuery = "true";
|
// filters
|
||||||
let sortQueries = [];
|
for (const filter of filters) {
|
||||||
|
let min = parseInt(filter.min_elem.value);
|
||||||
|
let max = parseInt(filter.max_elem.value);
|
||||||
|
if (min > max) {
|
||||||
|
document.getElementById("summary").innerHTML = "Error: The minimum of filter " + filter.input_elem.value + " (" + min + ") is greater than its maximum (" + max + ")";
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
let zero_in_min_max = (isNaN(min) || min < 0) && (isNaN(max) || max > 0);
|
||||||
|
|
||||||
|
let raw_name = filter.input_elem.value;
|
||||||
|
if (raw_name == "") {
|
||||||
|
continue; // empty
|
||||||
|
}
|
||||||
|
let filter_name = translate_mappings[raw_name];
|
||||||
|
if (filter_name === undefined) {
|
||||||
|
filter_name = special_mappings[raw_name];
|
||||||
|
if (filter_name === undefined) {
|
||||||
|
document.getElementById("summary").innerHTML = "Error: The filter \"" + filter.input_elem.value + "\" is not recognized";
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
filter_name = "(" + filter_name + ")";
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!isNaN(min)) {
|
||||||
|
queries.push("f:" + filter_name + ">=" + min);
|
||||||
|
}
|
||||||
|
if (!isNaN(max)) {
|
||||||
|
queries.push("f:" + filter_name + "<=" + max);
|
||||||
|
}
|
||||||
|
if (zero_in_min_max) {
|
||||||
|
queries.push("f:" + filter_name + "!=0");
|
||||||
|
}
|
||||||
|
queries.push("s:" + (filter.ascending ? "0-" : "") + filter_name);
|
||||||
|
}
|
||||||
|
|
||||||
|
// excludes
|
||||||
|
for (const exclude of excludes) {
|
||||||
|
let raw_name = exclude.input_elem.value;
|
||||||
|
if (raw_name == "") {
|
||||||
|
continue; // empty
|
||||||
|
}
|
||||||
|
let filter_name = translate_mappings[raw_name];
|
||||||
|
if (filter_name === undefined) {
|
||||||
|
filter_name = special_mappings[raw_name];
|
||||||
|
if (filter_name === undefined) {
|
||||||
|
document.getElementById("summary").innerHTML = "Error: The excluded filter \"" + exclude.input_elem.value + "\" is not recognized";
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
filter_name = "(" + filter_name + ")";
|
||||||
|
}
|
||||||
|
queries.push("f:" + filter_name + "=0");
|
||||||
|
}
|
||||||
|
|
||||||
|
let filter_query = "true";
|
||||||
|
let sort_queries = [];
|
||||||
console.log(queries);
|
console.log(queries);
|
||||||
for (const query of queries) {
|
for (const query of queries) {
|
||||||
if (query.startsWith("s:")) {
|
if (query.startsWith("s:")) {
|
||||||
sortQueries.push(query.slice(2));
|
sort_queries.push(query.slice(2));
|
||||||
}
|
}
|
||||||
else if (query.startsWith("f:")) {
|
else if (query.startsWith("f:")) {
|
||||||
filterQuery = filterQuery + "&" + query.slice(2);
|
filter_query = filter_query + "&" + query.slice(2);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
console.log(filterQuery);
|
document.getElementById("search-results").textContent = "";
|
||||||
console.log(sortQueries);
|
|
||||||
let results = [];
|
let results = [];
|
||||||
try {
|
try {
|
||||||
const filterExpr = exprParser.parse(filterQuery);
|
const filter_expr = expr_parser.parse(filter_query);
|
||||||
const sortExprs = sortQueries.map(q => exprParser.parse(q));
|
const sort_exprs = sort_queries.map(q => expr_parser.parse(q));
|
||||||
for (let i = 0; i < searchDb.length; ++i) {
|
for (let i = 0; i < search_db.length; ++i) {
|
||||||
const item = searchDb[i][0];
|
const item = search_db[i][0];
|
||||||
const itemExp = searchDb[i][1];
|
const itemExp = search_db[i][1];
|
||||||
if (checkBool(filterExpr.resolve(item, itemExp))) {
|
if (checkBool(filter_expr.resolve(item, itemExp))) {
|
||||||
results.push({ item, itemExp, sortKeys: sortExprs.map(e => e.resolve(item, itemExp)) });
|
results.push({ item, itemExp, sortKeys: sort_exprs.map(e => e.resolve(item, itemExp)) });
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
results.sort((a, b) => {
|
results.sort((a, b) => {
|
||||||
|
@ -211,13 +259,264 @@ function doItemSearch() {
|
||||||
document.getElementById("summary").textContent = e.message;
|
document.getElementById("summary").textContent = e.message;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
document.getElementById("summary").textContent = results.length + " results."
|
document.getElementById("summary").textContent = results.length + " results:";
|
||||||
|
document.getElementById("summary").style.color = "white";
|
||||||
displayItems(results);
|
displayItems(results);
|
||||||
}
|
}
|
||||||
|
|
||||||
function init_items() {
|
function init_items() {
|
||||||
searchDb = items.filter( i => ! i.remapID ).map( i => [i, expandItem(i, [])] );
|
search_db = items.filter( i => ! i.remapID ).map( i => [i, expandItem(i, [])] );
|
||||||
exprParser = new ExprParser(itemQueryProps, itemQueryFuncs);
|
expr_parser = new ExprParser(itemQueryProps, itemQueryFuncs);
|
||||||
|
|
||||||
|
// init type buttons
|
||||||
|
for (const type of Object.keys(types)) {
|
||||||
|
document.getElementById("type-" + type).addEventListener("click", function() {
|
||||||
|
types[type] = !types[type];
|
||||||
|
this.classList.toggle("type-selected");
|
||||||
|
});
|
||||||
|
}
|
||||||
|
document.getElementById("all-types").addEventListener("click", function() {
|
||||||
|
for (const type of Object.keys(types)) {
|
||||||
|
types[type] = true;
|
||||||
|
document.getElementById("type-" + type).classList.add("type-selected");
|
||||||
|
}
|
||||||
|
});
|
||||||
|
document.getElementById("none-types").addEventListener("click", function() {
|
||||||
|
for (const type of Object.keys(types)) {
|
||||||
|
types[type] = false;
|
||||||
|
document.getElementById("type-" + type).classList.remove("type-selected");
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
// init rarity buttons
|
||||||
|
for (const rarity of Object.keys(rarities)) {
|
||||||
|
document.getElementById("rarity-" + rarity).addEventListener("click", function() {
|
||||||
|
rarities[rarity] = !rarities[rarity];
|
||||||
|
this.classList.toggle("rarity-selected");
|
||||||
|
});
|
||||||
|
}
|
||||||
|
document.getElementById("all-rarities").addEventListener("click", function() {
|
||||||
|
for (const rarity of Object.keys(rarities)) {
|
||||||
|
rarities[rarity] = true;
|
||||||
|
document.getElementById("rarity-" + rarity).classList.add("rarity-selected");
|
||||||
|
}
|
||||||
|
});
|
||||||
|
document.getElementById("none-rarities").addEventListener("click", function() {
|
||||||
|
for (const rarity of Object.keys(rarities)) {
|
||||||
|
rarities[rarity] = false;
|
||||||
|
document.getElementById("rarity-" + rarity).classList.remove("rarity-selected");
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
// filters
|
||||||
|
document.getElementById("add-filter").addEventListener("click", create_filter);
|
||||||
|
document.getElementById("add-exclude").addEventListener("click", create_exclude);
|
||||||
|
create_filter();
|
||||||
|
filters[0].input_elem.value = "Combat Level";
|
||||||
|
init_filter_drag();
|
||||||
}
|
}
|
||||||
|
|
||||||
load_init(init_items);
|
function reset_item_search() {
|
||||||
|
document.getElementById("item-name-choice").value = "";
|
||||||
|
document.getElementById("all-types").click();
|
||||||
|
document.getElementById("all-rarities").click();
|
||||||
|
}
|
||||||
|
|
||||||
|
function create_filter() {
|
||||||
|
let data = {ascending: false};
|
||||||
|
|
||||||
|
let row = make_elem("div", ["row", "filter-row"], {});
|
||||||
|
let col = make_elem("div", ["col"], {});
|
||||||
|
row.appendChild(col);
|
||||||
|
data.div = row;
|
||||||
|
|
||||||
|
let reorder_img = make_elem("img", ["reorder-filter"], {src: "../media/icons/3-lines.svg", draggable: "true"});
|
||||||
|
col.appendChild(reorder_img);
|
||||||
|
|
||||||
|
let filter_input = make_elem("input",
|
||||||
|
["col", "border-dark", "text-light", "dark-5", "rounded", "scaled-font", "form-control", "form-control-sm", "filter-input"],
|
||||||
|
{id: "filter-input-" + filter_id_counter, type: "text", placeholder: "Filter"}
|
||||||
|
);
|
||||||
|
filter_id_counter++;
|
||||||
|
col.appendChild(filter_input);
|
||||||
|
data.input_elem = filter_input;
|
||||||
|
|
||||||
|
let asc_desc = make_elem("div", [], {style: "cursor: pointer; display: inline-block;"});
|
||||||
|
asc_desc.appendChild(make_elem("img", ["desc-icon", "asc-sel"], {src: "../media/icons/triangle.svg"}));
|
||||||
|
asc_desc.appendChild(make_elem("img", ["asc-icon"], {src: "../media/icons/triangle.svg"}));
|
||||||
|
asc_desc.addEventListener("click", function() {
|
||||||
|
data.ascending = !data.ascending;
|
||||||
|
asc_desc.children[0].classList.toggle("asc-sel");
|
||||||
|
asc_desc.children[1].classList.toggle("asc-sel");
|
||||||
|
});
|
||||||
|
col.appendChild(asc_desc);
|
||||||
|
|
||||||
|
let min = make_elem("input",
|
||||||
|
["col", "border-dark", "text-light", "dark-5", "rounded", "scaled-font", "form-control", "form-control-sm", "min-max-input"],
|
||||||
|
{type: "number", placeholder: "-\u221E"}
|
||||||
|
);
|
||||||
|
col.appendChild(min);
|
||||||
|
data.min_elem = min;
|
||||||
|
|
||||||
|
let to = make_elem("span", [], {innerHTML: " to "});
|
||||||
|
col.appendChild(to);
|
||||||
|
|
||||||
|
let max = make_elem("input",
|
||||||
|
["col", "border-dark", "text-light", "dark-5", "rounded", "scaled-font", "form-control", "form-control-sm", "min-max-input"],
|
||||||
|
{type: "number", placeholder: "\u221E"}
|
||||||
|
);
|
||||||
|
col.appendChild(max);
|
||||||
|
data.max_elem = max;
|
||||||
|
|
||||||
|
let trash = make_elem("img", ["delete-filter"], {src: "../media/icons/trash.svg"});
|
||||||
|
trash.addEventListener("click", function() {
|
||||||
|
filters.splice(Array.from(row.parentElement.children).indexOf(row) - 1, 1);
|
||||||
|
row.remove();
|
||||||
|
});
|
||||||
|
col.appendChild(trash);
|
||||||
|
|
||||||
|
document.getElementById("filter-container").insertBefore(row, document.getElementById("add-filter").parentElement);
|
||||||
|
filters.push(data);
|
||||||
|
init_filter_dropdown(data);
|
||||||
|
}
|
||||||
|
|
||||||
|
let currently_dragging = null;
|
||||||
|
function init_filter_drag() {
|
||||||
|
let container = document.getElementById("filter-container");
|
||||||
|
|
||||||
|
container.addEventListener("dragstart", function(e) {
|
||||||
|
if (e.path[0].classList.contains("reorder-filter")) {
|
||||||
|
currently_dragging = filters[Array.from(e.path[3].children).indexOf(e.path[2]) - 1];
|
||||||
|
} else {
|
||||||
|
e.preventDefault();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
container.addEventListener("dragenter", function(e) {
|
||||||
|
e.preventDefault();
|
||||||
|
});
|
||||||
|
|
||||||
|
container.addEventListener("dragleave", function(e) {
|
||||||
|
e.preventDefault();
|
||||||
|
});
|
||||||
|
|
||||||
|
container.addEventListener("dragend", function(e) {
|
||||||
|
e.preventDefault();
|
||||||
|
for (const el of document.getElementsByClassName("filter-dragged-over")) {
|
||||||
|
el.classList.remove("filter-dragged-over");
|
||||||
|
}
|
||||||
|
currently_dragging = null;
|
||||||
|
});
|
||||||
|
|
||||||
|
container.addEventListener("dragover", function(e) {
|
||||||
|
e.preventDefault();
|
||||||
|
for (const el of document.getElementsByClassName("filter-dragged-over")) {
|
||||||
|
el.classList.remove("filter-dragged-over");
|
||||||
|
}
|
||||||
|
if (!e.path.includes(currently_dragging.div)) {
|
||||||
|
for (let i = 0; i < e.path.length; i++) {
|
||||||
|
if (e.path[i].classList.contains("filter-row")) {
|
||||||
|
e.path[i].classList.add("filter-dragged-over");
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
container.addEventListener("drop", function(e) {
|
||||||
|
e.preventDefault();
|
||||||
|
for (const el of document.getElementsByClassName("filter-dragged-over")) {
|
||||||
|
el.classList.remove("filter-dragged-over");
|
||||||
|
}
|
||||||
|
if (!e.path.includes(currently_dragging.div)) {
|
||||||
|
for (let i = 0; i < e.path.length; i++) {
|
||||||
|
if (e.path[i].classList.contains("filter-row")) {
|
||||||
|
let old_index = filters.indexOf(currently_dragging);
|
||||||
|
let new_index = Array.from(e.path[i + 1].children).indexOf(e.path[i]) - 1;
|
||||||
|
filters.splice(old_index, 1);
|
||||||
|
filters.splice(new_index, 0, currently_dragging);
|
||||||
|
currently_dragging.div.remove();
|
||||||
|
container.insertBefore(currently_dragging.div, container.children[new_index + 1]);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
currently_dragging = null;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
function create_exclude() {
|
||||||
|
let data = {};
|
||||||
|
|
||||||
|
let row = make_elem("div", ["row", "filter-row"], {});
|
||||||
|
let col = make_elem("div", ["col"], {});
|
||||||
|
row.appendChild(col);
|
||||||
|
data.div = row;
|
||||||
|
|
||||||
|
let filter_input = make_elem("input",
|
||||||
|
["col", "border-dark", "text-light", "dark-5", "rounded", "scaled-font", "form-control", "form-control-sm", "filter-input"],
|
||||||
|
{id: "filter-input-" + filter_id_counter, type: "text", placeholder: "Excluded Filter"}
|
||||||
|
);
|
||||||
|
filter_id_counter++;
|
||||||
|
col.appendChild(filter_input);
|
||||||
|
data.input_elem = filter_input;
|
||||||
|
|
||||||
|
let trash = make_elem("img", ["delete-filter"], {src: "../media/icons/trash.svg"});
|
||||||
|
trash.addEventListener("click", function() {
|
||||||
|
excludes.splice(Array.from(row.parentElement.children).indexOf(row) - 1, 1);
|
||||||
|
row.remove();
|
||||||
|
});
|
||||||
|
col.appendChild(trash);
|
||||||
|
|
||||||
|
document.getElementById("exclude-container").insertBefore(row, document.getElementById("add-exclude").parentElement);
|
||||||
|
excludes.push(data);
|
||||||
|
init_filter_dropdown(data);
|
||||||
|
}
|
||||||
|
|
||||||
|
function init_filter_dropdown(filter) {
|
||||||
|
let field_choice = filter.input_elem;
|
||||||
|
field_choice.onclick = function() {field_choice.dispatchEvent(new Event('input', {bubbles:true}));};
|
||||||
|
filter.autoComplete = new autoComplete({
|
||||||
|
data: {
|
||||||
|
src: item_filters,
|
||||||
|
},
|
||||||
|
threshold: 0,
|
||||||
|
selector: "#" + field_choice.id,
|
||||||
|
wrapper: false,
|
||||||
|
resultsList: {
|
||||||
|
maxResults: 100,
|
||||||
|
tabSelect: true,
|
||||||
|
noResults: true,
|
||||||
|
class: "search-box dark-7 rounded-bottom px-2 fw-bold dark-shadow-sm",
|
||||||
|
element: (list, data) => {
|
||||||
|
let position = field_choice.getBoundingClientRect();
|
||||||
|
list.style.top = position.bottom + window.scrollY +"px";
|
||||||
|
list.style.left = position.x+"px";
|
||||||
|
list.style.width = position.width+"px";
|
||||||
|
list.style.maxHeight = position.height * 4 +"px";
|
||||||
|
if (!data.results.length) {
|
||||||
|
const message = make_elem('li', ['scaled-font'], {textContent: "No results found!"});
|
||||||
|
list.prepend(message);
|
||||||
|
};
|
||||||
|
},
|
||||||
|
},
|
||||||
|
resultItem: {
|
||||||
|
class: "scaled-font search-item",
|
||||||
|
selected: "dark-5",
|
||||||
|
},
|
||||||
|
events: {
|
||||||
|
input: {
|
||||||
|
selection: (event) => {
|
||||||
|
if (event.detail.selection.value) {
|
||||||
|
event.target.value = event.detail.selection.value;
|
||||||
|
};
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
(async function() {
|
||||||
|
await Promise.resolve(load_init());
|
||||||
|
init_items();
|
||||||
|
})();
|
||||||
|
|
|
@ -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();
|
||||||
|
})();
|
35
js/load.js
|
@ -1,4 +1,4 @@
|
||||||
const DB_VERSION = 101;
|
const DB_VERSION = 120;
|
||||||
// @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;
|
||||||
|
@ -92,13 +92,32 @@ function clean_item(item) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
async function load_old_version(version_str) {
|
||||||
|
load_in_progress = true;
|
||||||
|
let getUrl = window.location;
|
||||||
|
let baseUrl = `${getUrl.protocol}//${getUrl.host}/`;
|
||||||
|
// No random string -- we want to use caching
|
||||||
|
let url = `${baseUrl}/data/${version_str}/items.json`;
|
||||||
|
let result = await (await fetch(url)).json();
|
||||||
|
items = result.items;
|
||||||
|
for (const item of items) {
|
||||||
|
clean_item(item);
|
||||||
|
}
|
||||||
|
let sets_ = result.sets;
|
||||||
|
sets = new Map();
|
||||||
|
for (const set in sets_) {
|
||||||
|
sets.set(set, sets_[set]);
|
||||||
|
}
|
||||||
|
init_maps();
|
||||||
|
load_complete = true;
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Load item set from remote DB (aka a big json file). Calls init() on success.
|
* Load item set from remote DB (aka a big json file). Calls init() on success.
|
||||||
*/
|
*/
|
||||||
async function load() {
|
async function load() {
|
||||||
|
|
||||||
let getUrl = window.location;
|
let getUrl = window.location;
|
||||||
let baseUrl = getUrl.protocol + "//" + getUrl.host + "/";// + getUrl.pathname.split('/')[1];
|
let baseUrl = `${getUrl.protocol}//${getUrl.host}/`;
|
||||||
// "Random" string to prevent caching!
|
// "Random" string to prevent caching!
|
||||||
let url = baseUrl + "/compress.json?"+new Date();
|
let url = baseUrl + "/compress.json?"+new Date();
|
||||||
let result = await (await fetch(url)).json();
|
let result = await (await fetch(url)).json();
|
||||||
|
@ -150,7 +169,7 @@ async function load_init() {
|
||||||
console.log("Skipping load...")
|
console.log("Skipping load...")
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
load_in_progress = true
|
load_in_progress = true;
|
||||||
if (reload) {
|
if (reload) {
|
||||||
console.log("Using new data...")
|
console.log("Using new data...")
|
||||||
await load();
|
await load();
|
||||||
|
@ -190,7 +209,7 @@ async function load_init() {
|
||||||
}
|
}
|
||||||
|
|
||||||
// List of 'raw' "none" items (No Helmet, etc), in order helmet, chestplate... ring1, ring2, brace, neck, weapon.
|
// List of 'raw' "none" items (No Helmet, etc), in order helmet, chestplate... ring1, ring2, brace, neck, weapon.
|
||||||
for (const it of itemTypes) {
|
for (const it of item_types) {
|
||||||
itemLists.set(it, []);
|
itemLists.set(it, []);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -254,5 +273,9 @@ function init_maps() {
|
||||||
redirectMap.set(item.id, item.remapID);
|
redirectMap.set(item.id, item.remapID);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
console.log(itemMap);
|
for (const [set_name, set_data] of sets) {
|
||||||
|
for (const item_name of set_data.items) {
|
||||||
|
itemMap.get(item_name).set = set_name;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
const ING_DB_VERSION = 14;
|
const ING_DB_VERSION = 19;
|
||||||
|
|
||||||
// @See https://github.com/mdn/learning-area/blob/master/javascript/apis/client-side-storage/indexeddb/video-store/index.js
|
// @See https://github.com/mdn/learning-area/blob/master/javascript/apis/client-side-storage/indexeddb/video-store/index.js
|
||||||
|
|
||||||
|
@ -59,22 +59,41 @@ function clean_ing(ing) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
async function load_ings_old_version(version_str) {
|
||||||
|
iload_in_progress = true;
|
||||||
|
let getUrl = window.location;
|
||||||
|
let baseUrl = `${getUrl.protocol}//${getUrl.host}/`;
|
||||||
|
// No random string -- we want to use caching
|
||||||
|
let url = `${baseUrl}/data/${version_str}/ingreds.json`;
|
||||||
|
let result = await (await fetch(url)).json();
|
||||||
|
ings = result;
|
||||||
|
for (const id in ings) {
|
||||||
|
clean_ing(ings[id]);
|
||||||
|
}
|
||||||
|
|
||||||
|
url = baseUrl + "/recipes_compress.json";
|
||||||
|
result = await (await fetch(url)).json();
|
||||||
|
recipes = result.recipes;
|
||||||
|
|
||||||
|
init_maps();
|
||||||
|
iload_complete = true;
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Load item set from remote DB (aka a big json file). Calls init() on success.
|
* Load item set from remote DB (aka a big json file). Calls init() on success.
|
||||||
*/
|
*/
|
||||||
async function load_ings() {
|
async function load_ings() {
|
||||||
|
|
||||||
let getUrl = window.location;
|
let getUrl = window.location;
|
||||||
let baseUrl = getUrl.protocol + "//" + getUrl.host + "/";// + getUrl.pathname.split('/')[1];
|
let baseUrl = `${getUrl.protocol}//${getUrl.host}/`;
|
||||||
// "Random" string to prevent caching!
|
// "Random" string to prevent caching!
|
||||||
let url = baseUrl + "/ingreds_compress.json?"+new Date();
|
let url = baseUrl + "/ingreds_compress.json?"+new Date();
|
||||||
url = url.replace(/\w+.html/, "") ;
|
|
||||||
let result = await (await fetch(url)).json();
|
let result = await (await fetch(url)).json();
|
||||||
|
|
||||||
result = await (await fetch(url)).json();
|
result = await (await fetch(url)).json();
|
||||||
ings = result;
|
ings = result;
|
||||||
|
|
||||||
url = url.replace("/ingreds_compress.json", "/recipes_compress.json");
|
url = baseUrl + "/recipes_compress.json?"+new Date();
|
||||||
result = await (await fetch(url)).json();
|
result = await (await fetch(url)).json();
|
||||||
recipes = result.recipes;
|
recipes = result.recipes;
|
||||||
|
|
||||||
|
@ -197,7 +216,7 @@ function init_ing_maps() {
|
||||||
posMods: {"left": 0, "right": 0, "above": 0, "under": 0, "touching": 0, "notTouching": 0}
|
posMods: {"left": 0, "right": 0, "above": 0, "under": 0, "touching": 0, "notTouching": 0}
|
||||||
};
|
};
|
||||||
ing.id = 4001 + ing.pid;
|
ing.id = 4001 + ing.pid;
|
||||||
ing.diplayName = ing.name;
|
ing.displayName = ing.name;
|
||||||
switch(i) {
|
switch(i) {
|
||||||
case 0:
|
case 0:
|
||||||
ing.itemIDs["strReq"] = powderIng["skpReq"];
|
ing.itemIDs["strReq"] = powderIng["skpReq"];
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
const TOME_DB_VERSION = 3;
|
const TOME_DB_VERSION = 6;
|
||||||
// @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 tdb;
|
let tdb;
|
||||||
|
@ -34,13 +34,27 @@ async function load_tome_local() {
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
async function load_tome_old_version(version_str) {
|
||||||
|
tload_in_progress = true;
|
||||||
|
let getUrl = window.location;
|
||||||
|
let baseUrl = `${getUrl.protocol}//${getUrl.host}/`;
|
||||||
|
// No random string -- we want to use caching
|
||||||
|
let url = `${baseUrl}/data/${version_str}/tomes.json`;
|
||||||
|
let result = await (await fetch(url)).json();
|
||||||
|
tomes = result.tomes;
|
||||||
|
for (const tome of tomes) {
|
||||||
|
//dependency on clean_item in load.js
|
||||||
|
clean_item(tome);
|
||||||
|
}
|
||||||
|
init_tome_maps();
|
||||||
|
tload_complete = true;
|
||||||
|
}
|
||||||
/*
|
/*
|
||||||
* Load tome set from remote DB (json). Calls init() on success.
|
* Load tome set from remote DB (json). Calls init() on success.
|
||||||
*/
|
*/
|
||||||
async function load_tome() {
|
async function load_tome() {
|
||||||
|
|
||||||
let getUrl = window.location;
|
let getUrl = window.location;
|
||||||
let baseUrl = getUrl.protocol + "//" + getUrl.host + "/";// + getUrl.pathname.split('/')[1];
|
let baseUrl = `${getUrl.protocol}//${getUrl.host}/`;
|
||||||
// "Random" string to prevent caching!
|
// "Random" string to prevent caching!
|
||||||
let url = baseUrl + "/tomes.json?"+new Date();
|
let url = baseUrl + "/tomes.json?"+new Date();
|
||||||
let result = await (await fetch(url)).json();
|
let result = await (await fetch(url)).json();
|
||||||
|
@ -119,11 +133,13 @@ async function load_tome_init() {
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
let none_tomes = [
|
const none_tomes_info = [
|
||||||
["tome", "weaponTome", "No Weapon Tome"],
|
["tome", "weaponTome", "No Weapon Tome"],
|
||||||
["tome", "armorTome", "No Armor Tome"],
|
["tome", "armorTome", "No Armor Tome"],
|
||||||
["tome", "guildTome", "No Guild Tome"]
|
["tome", "guildTome", "No Guild Tome"]
|
||||||
];
|
];
|
||||||
|
let none_tomes;
|
||||||
|
|
||||||
function init_tome_maps() {
|
function init_tome_maps() {
|
||||||
//warp
|
//warp
|
||||||
tomeMap = new Map();
|
tomeMap = new Map();
|
||||||
|
@ -135,12 +151,13 @@ function init_tome_maps() {
|
||||||
tomeLists.set(it, []);
|
tomeLists.set(it, []);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
none_tomes = [];
|
||||||
for (let i = 0; i < 3; i++) {
|
for (let i = 0; i < 3; i++) {
|
||||||
let tome = Object();
|
let tome = Object();
|
||||||
tome.slots = 0;
|
tome.slots = 0;
|
||||||
tome.category = none_tomes[i][0];
|
tome.category = none_tomes_info[i][0];
|
||||||
tome.type = none_tomes[i][1];
|
tome.type = none_tomes_info[i][1];
|
||||||
tome.name = none_tomes[i][2];
|
tome.name = none_tomes_info[i][2];
|
||||||
tome.displayName = tome.name;
|
tome.displayName = tome.name;
|
||||||
tome.set = null;
|
tome.set = null;
|
||||||
tome.quest = null;
|
tome.quest = null;
|
||||||
|
@ -159,7 +176,7 @@ function init_tome_maps() {
|
||||||
//dependency - load.js
|
//dependency - load.js
|
||||||
clean_item(tome);
|
clean_item(tome);
|
||||||
|
|
||||||
none_tomes[i] = tome;
|
none_tomes.push(tome);
|
||||||
}
|
}
|
||||||
tomes = tomes.concat(none_tomes);
|
tomes = tomes.concat(none_tomes);
|
||||||
for (const tome of tomes) {
|
for (const tome of tomes) {
|
||||||
|
|
|
@ -55,11 +55,11 @@ class PowderSpecial{
|
||||||
function _ps(a,b,c,d,e) { return new PowderSpecial(a,b,c,d,e); } //bruh moment
|
function _ps(a,b,c,d,e) { return new PowderSpecial(a,b,c,d,e); } //bruh moment
|
||||||
|
|
||||||
let powderSpecialStats = [
|
let powderSpecialStats = [
|
||||||
_ps("Quake",new Map([["Radius",[4.4,4.9,5.4,5.9,6.4]], ["Damage",[155,220,285,350,415]] ]),"Rage",new Map([ ["Damage", [0.3,0.4,0.5,0.7,1.0]],["Description", "% " + "\u2764" + " Missing"] ]), 396), //e
|
_ps("Quake",new Map([["Radius",[4.5,5,5.5,6,6.5]], ["Damage",[240,280,320,360,400]] ]),"Rage",new Map([ ["Damage", [0.2,0.4,0.6,0.8,1.0]],["Description", "% " + "\u2764" + " Missing below 75%"] ]),300), //e
|
||||||
_ps("Chain Lightning",new Map([ ["Chains", [5,6,7,8,9]], ["Damage", [200,225,250,275,300]] ]),"Kill Streak",new Map([ ["Damage", [3,4.5,6,7.5,9]],["Duration", [5,5,5,5,5]],["Description", "Mob Killed"] ]),200), //t
|
_ps("Chain Lightning",new Map([ ["Chains", [5,6,7,8,9]], ["Damage", [200,225,250,275,300]] ]),"Kill Streak",new Map([ ["Damage", [3,4.5,6,7.5,9]],["Duration", [5,5,5,5,5]],["Description", "Mob Killed"] ]),150), //t
|
||||||
_ps("Curse",new Map([ ["Duration", [7,7.5,8,8.5,9]],["Damage Boost", [90,120,150,180,210]] ]),"Concentration",new Map([ ["Damage", [1,2,3,4,5]],["Duration",[1,1,1,1,1]],["Description", "Mana Used"] ]),150), //w
|
_ps("Curse",new Map([ ["Duration", [4,4,4,4,4]],["Damage Boost", [10,15,20,25,30]] ]),"Concentration",new Map([ ["Damage", [0.05,0.1,0.15,0.2,0.25]],["Duration",[1,1,1,1,1]],["Description", "Mana Used"] ]),100), //w
|
||||||
_ps("Courage",new Map([ ["Duration", [6,6.5,7,7.5,8]],["Damage", [75,87.5,100,112.5,125]],["Damage Boost", [70,90,110,130,150]] ]),"Endurance",new Map([ ["Damage", [2,3,4,5,6]],["Duration", [8,8,8,8,8]],["Description", "Hit Taken"] ]),200), //f
|
_ps("Courage",new Map([ ["Duration", [4,4,4,4,4]],["Damage", [60, 70, 80, 90, 100]],["Damage Boost", [10,12.5,15,17.5,20]] ]),"Endurance",new Map([ ["Damage", [2,3,4,5,6]],["Duration", [8,8,8,8,8]],["Description", "Hit Taken"] ]),100), //f
|
||||||
_ps("Wind Prison",new Map([ ["Duration", [3,3.5,4,4.5,5]],["Damage Boost", [400,450,500,550,600]],["Knockback", [8,12,16,20,24]] ]),"Dodge",new Map([ ["Damage",[2,3,4,5,6]],["Duration",[2,3,4,5,6]],["Description","Near Mobs"] ]),150) //a
|
_ps("Wind Prison",new Map([ ["Duration", [3,3.5,4,4.5,5]],["Damage Boost", [100,125,150,175,200]],["Knockback", [8,12,16,20,24]] ]),"Dodge",new Map([ ["Damage",[2,3,4,5,6]],["Duration",[2,3,4,5,6]],["Description","Near Mobs"] ]),150) //a
|
||||||
];
|
];
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -159,6 +159,45 @@ function calc_weapon_powder(weapon, damageBases) {
|
||||||
neutralBase = damages[0].slice();
|
neutralBase = damages[0].slice();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//apply powders to weapon (1.21 fked implementation)
|
||||||
|
let powder_apply_order = [];
|
||||||
|
let powder_apply_map = new Map();
|
||||||
|
for (const powderID of powders) {
|
||||||
|
const powder = powderStats[powderID];
|
||||||
|
// Bitwise to force conversion to integer (integer division).
|
||||||
|
const element = (powderID/6) | 0;
|
||||||
|
const conversion_ratio = powder.convert/100;
|
||||||
|
|
||||||
|
if (powder_apply_map.has(element)) {
|
||||||
|
let apply_info = powder_apply_map.get(element);
|
||||||
|
apply_info.conv += conversion_ratio;
|
||||||
|
apply_info.min += powder.min;
|
||||||
|
apply_info.max += powder.max;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
let apply_info = {
|
||||||
|
conv: conversion_ratio,
|
||||||
|
min: powder.min,
|
||||||
|
max: powder.max
|
||||||
|
};
|
||||||
|
powder_apply_order.push(element);
|
||||||
|
powder_apply_map.set(element, apply_info);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
for (const element of powder_apply_order) {
|
||||||
|
const apply_info = powder_apply_map.get(element);
|
||||||
|
const conversion_ratio = apply_info.conv;
|
||||||
|
const min_diff = Math.min(neutralRemainingRaw[0], conversion_ratio * neutralRemainingRaw[0]);
|
||||||
|
const max_diff = Math.min(neutralRemainingRaw[1], conversion_ratio * neutralRemainingRaw[1]);
|
||||||
|
neutralRemainingRaw[0] -= min_diff;
|
||||||
|
neutralRemainingRaw[1] -= max_diff;
|
||||||
|
damages[element+1][0] += min_diff;
|
||||||
|
damages[element+1][1] += max_diff;
|
||||||
|
damages[element+1][0] += apply_info.min;
|
||||||
|
damages[element+1][1] += apply_info.max;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
//apply powders to weapon
|
//apply powders to weapon
|
||||||
for (const powderID of powders) {
|
for (const powderID of powders) {
|
||||||
const powder = powderStats[powderID];
|
const powder = powderStats[powderID];
|
||||||
|
@ -181,14 +220,15 @@ function calc_weapon_powder(weapon, damageBases) {
|
||||||
damages[element+1][0] += powder.min;
|
damages[element+1][0] += powder.min;
|
||||||
damages[element+1][1] += powder.max;
|
damages[element+1][1] += powder.max;
|
||||||
}
|
}
|
||||||
|
*/
|
||||||
|
|
||||||
|
// The ordering of these two blocks decides whether neutral is present when converted away or not.
|
||||||
|
damages[0] = neutralRemainingRaw;
|
||||||
|
|
||||||
// The ordering of these two blocks decides whether neutral is present when converted away or not.
|
// The ordering of these two blocks decides whether neutral is present when converted away or not.
|
||||||
let present_elements = []
|
let present_elements = []
|
||||||
for (const damage of damages) {
|
for (const damage of damages) {
|
||||||
present_elements.push(damage[1] > 0);
|
present_elements.push(damage[1] > 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
// The ordering of these two blocks decides whether neutral is present when converted away or not.
|
|
||||||
damages[0] = neutralRemainingRaw;
|
|
||||||
return [damages, present_elements];
|
return [damages, present_elements];
|
||||||
}
|
}
|
||||||
|
|
637
js/query.js
|
@ -1,115 +1,550 @@
|
||||||
let queryTypeMap = new Map();
|
// dynamic type casts
|
||||||
|
function checkBool(v) {
|
||||||
class NameQuery {
|
if (typeof v !== 'boolean') throw new Error(`Expected boolean, but got ${typeof v}`);
|
||||||
constructor(string) { this.queryString = string.toLowerCase(); }
|
return v;
|
||||||
|
|
||||||
filter(item) {
|
|
||||||
if (item.get("restrict") && item.get("restrict") === "DEPRECATED") {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
return (item.get("displayName").toLowerCase().includes(this.queryString));
|
|
||||||
}
|
|
||||||
|
|
||||||
compare(a, b) { return a < b; }
|
|
||||||
}
|
|
||||||
queryTypeMap.set("name", function(s) { return new NameQuery(s); } );
|
|
||||||
|
|
||||||
class LevelRangeQuery {
|
|
||||||
constructor(min, max) { this.min = min; this.max = max; }
|
|
||||||
|
|
||||||
filter(item) {
|
|
||||||
if (item.get("remapID") === undefined) {
|
|
||||||
return (item.get("lvl") <= this.max && item.get("lvl") >= this.min);
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
compare(a, b) { return a > b; }
|
|
||||||
}
|
}
|
||||||
|
|
||||||
class NegateQuery {
|
function checkNum(v) {
|
||||||
constructor(id) {
|
if (typeof v === 'boolean') {
|
||||||
this.id = id;
|
if (v) return 1;
|
||||||
this.compare = function(a, b) { return 0; };
|
|
||||||
}
|
|
||||||
|
|
||||||
filter(item) {
|
|
||||||
return (!item.get(this.id)) || (item.get(this.id) == 0);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
queryTypeMap.set("null", function(s) { return new IdQuery(s); } );
|
|
||||||
|
|
||||||
class IdQuery {
|
|
||||||
constructor(id) {
|
|
||||||
this.id = id;
|
|
||||||
if (nonRolledIDs.includes(id)) {
|
|
||||||
this.compare = function(a, b) {
|
|
||||||
return b.get(id) - a.get(id);
|
|
||||||
};
|
|
||||||
this.filter = function(a) {
|
|
||||||
return a.get(this.id);
|
|
||||||
}
|
|
||||||
console.log("QUERY: ID, NONROLL");
|
|
||||||
}
|
|
||||||
else if (reversedIDs.includes(id)) {
|
|
||||||
this.compare = function(a, b) {
|
|
||||||
return a.get("maxRolls").get(id) - b.get("maxRolls").get(id);
|
|
||||||
};
|
|
||||||
this.filter = function(a) {
|
|
||||||
return a.get("maxRolls").get(this.id);
|
|
||||||
}
|
|
||||||
console.log("QUERY: ID, REVERSE");
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
this.compare = function(a, b) {
|
|
||||||
return b.get("maxRolls").get(id) - a.get("maxRolls").get(id);
|
|
||||||
};
|
|
||||||
this.filter = function(a) {
|
|
||||||
return a.get("maxRolls").get(this.id);
|
|
||||||
}
|
|
||||||
console.log("QUERY: ID, ,,,");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
queryTypeMap.set("stat", function(s) { return new IdQuery(s); } );
|
|
||||||
|
|
||||||
class IdMatchQuery {
|
|
||||||
constructor(id, value) {
|
|
||||||
this.id = id;
|
|
||||||
this.value = value;
|
|
||||||
this.compare = function(a, b) {
|
|
||||||
return 0;
|
return 0;
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
filter(item) {
|
|
||||||
return item.get(this.id) && (item.get(this.id) == this.value);
|
|
||||||
}
|
}
|
||||||
|
if (typeof v !== 'number') throw new Error(`Expected number, but got ${typeof v}`);
|
||||||
|
return v;
|
||||||
}
|
}
|
||||||
|
|
||||||
class SumQuery {
|
function checkStr(v) {
|
||||||
constructor(ids) {
|
if (typeof v !== 'string') throw new Error(`Expected string, but got ${typeof v}`);
|
||||||
let getters = [];
|
return v;
|
||||||
for (const id of ids) {
|
}
|
||||||
if (nonRolledIDs.includes(id)) {
|
|
||||||
getters.push(a => a.get(id));
|
function checkComparable(v) {
|
||||||
|
if (typeof v === 'boolean') throw new Error('Boolean is not comparable');
|
||||||
|
return v;
|
||||||
|
}
|
||||||
|
|
||||||
|
// properties of items that can be looked up
|
||||||
|
// each entry is a function `(item, extended item) -> value`
|
||||||
|
const itemQueryProps = (function() {
|
||||||
|
const props = {};
|
||||||
|
|
||||||
|
function prop(names, type, resolve) {
|
||||||
|
if (Array.isArray(names)) {
|
||||||
|
for (name of names) {
|
||||||
|
props[name] = { type, resolve };
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
props[names] = { type, resolve };
|
||||||
}
|
}
|
||||||
else {
|
|
||||||
getters.push(a => a.get("maxRolls").get(id));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
function maxId(names, idKey) {
|
||||||
this.compare = function(a, b) {
|
prop(names, 'number', (i, ie) => ie.get('maxRolls').get(idKey) || 0);
|
||||||
let balance = 0;
|
|
||||||
for (const getter of getters) {
|
|
||||||
if (getter(a)) { balance -= getter(a); }
|
|
||||||
if (getter(b)) { balance += getter(b); }
|
|
||||||
}
|
|
||||||
return balance;
|
|
||||||
};
|
|
||||||
}
|
}
|
||||||
|
|
||||||
filter(item) {
|
function minId(names, idKey) {
|
||||||
|
prop(names, 'number', (i, ie) => ie.get('minRolls').get(idKey) || 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
function rangeAvg(names, getProp) {
|
||||||
|
prop(names, 'number', (i, ie) => {
|
||||||
|
const range = getProp(i, ie);
|
||||||
|
if (!range) return 0;
|
||||||
|
const ndx = range.indexOf('-');
|
||||||
|
return (parseInt(range.substring(0, ndx), 10) + parseInt(range.substring(ndx + 1), 10)) / 2;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
function map(names, comps, outType, f) {
|
||||||
|
return prop(names, outType, (i, ie) => {
|
||||||
|
const args = [];
|
||||||
|
for (let k = 0; k < comps.length; k++) args.push(comps[k].resolve(i, ie));
|
||||||
|
return f.apply(null, args);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
function sum(names, ...comps) {
|
||||||
|
return map(names, comps, 'number', (...summands) => {
|
||||||
|
let total = 0;
|
||||||
|
for (let i = 0; i < summands.length; i++) total += summands[i];
|
||||||
|
return total;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
prop('name', 'string', (i, ie) => i.displayName || i.name);
|
||||||
|
prop('type', 'string', (i, ie) => i.type);
|
||||||
|
prop(['cat', 'category'], 'string', (i, ie) => i.category);
|
||||||
|
const tierIndices = { Normal: 0, Unique: 1, Set: 2, Rare: 3, Legendary: 4, Fabled: 5, Mythic: 6 };
|
||||||
|
prop(['rarityname', 'raritystr', 'tiername', 'tierstr'], 'string', (i, ie) => i.tier);
|
||||||
|
prop(['rarity', 'tier'], 'number', (i, ie) => tierIndices[i.tier]);
|
||||||
|
|
||||||
|
prop(['level', 'lvl', 'combatlevel', 'combatlvl'], 'number', (i, ie) => i.lvl);
|
||||||
|
prop(['strmin', 'strreq'], 'number', (i, ie) => i.strReq);
|
||||||
|
prop(['dexmin', 'dexreq'], 'number', (i, ie) => i.dexReq);
|
||||||
|
prop(['intmin', 'intreq'], 'number', (i, ie) => i.intReq);
|
||||||
|
prop(['defmin', 'defreq'], 'number', (i, ie) => i.defReq);
|
||||||
|
prop(['agimin', 'agireq'], 'number', (i, ie) => i.agiReq);
|
||||||
|
sum(['summin', 'sumreq', 'totalmin', 'totalreq'], props.strmin, props.dexmin, props.intmin, props.defmin, props.agimin);
|
||||||
|
|
||||||
|
prop('str', 'number', (i, ie) => i.str);
|
||||||
|
prop('dex', 'number', (i, ie) => i.dex);
|
||||||
|
prop('int', 'number', (i, ie) => i.int);
|
||||||
|
prop('def', 'number', (i, ie) => i.def);
|
||||||
|
prop('agi', 'number', (i, ie) => i.agi);
|
||||||
|
sum(['skillpoints', 'skillpts', 'attributes', 'attrs'], props.str, props.dex, props.int, props.def, props.agi);
|
||||||
|
|
||||||
|
rangeAvg(['neutraldmg', 'neutraldam', 'ndmg', 'ndam'], (i, ie) => i.nDam);
|
||||||
|
rangeAvg(['earthdmg', 'earthdam', 'edmg', 'edam'], (i, ie) => i.eDam);
|
||||||
|
rangeAvg(['thunderdmg', 'thunderdam', 'tdmg', 'tdam'], (i, ie) => i.tDam);
|
||||||
|
rangeAvg(['waterdmg', 'waterdam', 'wdmg', 'wdam'], (i, ie) => i.wDam);
|
||||||
|
rangeAvg(['firedmg', 'firedam', 'fdmg', 'fdam'], (i, ie) => i.fDam);
|
||||||
|
rangeAvg(['airdmg', 'airdam', 'admg', 'adam'], (i, ie) => i.aDam);
|
||||||
|
sum(['sumdmg', 'sumdam', 'totaldmg', 'totaldam'], props.ndam, props.edam, props.tdam, props.wdam, props.fdam, props.adam);
|
||||||
|
|
||||||
|
maxId(['earthdmg%', 'earthdam%', 'edmg%', 'edam%', 'edampct'], 'eDamPct');
|
||||||
|
maxId(['thunderdmg%', 'thunderdam%', 'tdmg%', 'tdam%', 'tdampct'], 'tDamPct');
|
||||||
|
maxId(['waterdmg%', 'waterdam%', 'wdmg%', 'wdam%', 'wdampct'], 'wDamPct');
|
||||||
|
maxId(['firedmg%', 'firedam%', 'fdmg%', 'fdam%', 'fdampct'], 'fDamPct');
|
||||||
|
maxId(['airdmg%', 'airdam%', 'admg%', 'adam%', 'adampct'], 'aDamPct');
|
||||||
|
sum(['sumdmg%', 'sumdam%', 'totaldmg%', 'totaldam%', 'sumdampct', 'totaldampct'], props.edampct, props.tdampct, props.wdampct, props.fdampct, props.adampct);
|
||||||
|
|
||||||
|
maxId(['mainatkdmg', 'mainatkdam', 'mainatkdmg%', 'mainatkdam%', 'meleedmg', 'meleedam', 'meleedmg%', 'meleedam%', 'mdpct'], 'mdPct');
|
||||||
|
maxId(['mainatkrawdmg', 'mainatkrawdam', 'mainatkneutraldmg', 'mainatkneutraldam', 'meleerawdmg', 'meleerawdam', 'meleeneutraldmg', 'meleeneutraldam', 'mdraw'], 'mdRaw');
|
||||||
|
maxId(['spelldmg', 'spelldam', 'spelldmg%', 'spelldam%', 'sdpct'], 'sdPct');
|
||||||
|
maxId(['spellrawdmg', 'spellrawdam', 'spellneutraldmg', 'spellneutraldam', 'sdraw'], 'sdRaw');
|
||||||
|
maxId(['rainbowraw'], 'rSdRaw');
|
||||||
|
|
||||||
|
const atkSpdIndices = { SUPER_SLOW: -3, VERY_SLOW: -2, SLOW: -1, NORMAL: 0, FAST: 1, VERY_FAST: 2, SUPER_FAST: 3 };
|
||||||
|
prop(['attackspeed', 'atkspd'], 'string', (i, ie) => i.atkSpd ? atkSpdIndices[i.atkSpd] : 0);
|
||||||
|
maxId(['bonusattackspeed', 'bonusatkspd', 'attackspeedid', 'atkspdid', 'atktier'], 'atkTier');
|
||||||
|
sum(['sumattackspeed', 'totalattackspeed', 'sumatkspd', 'totalatkspd', 'sumatktier', 'totalatktier'], props.atkspd, props.atktier);
|
||||||
|
|
||||||
|
prop(['earthdef', 'edef'], 'number', (i, ie) => i.eDef || 0);
|
||||||
|
prop(['thunderdef', 'tdef'], 'number', (i, ie) => i.tDef || 0);
|
||||||
|
prop(['waterdef', 'wdef'], 'number', (i, ie) => i.wDef || 0);
|
||||||
|
prop(['firedef', 'fdef'], 'number', (i, ie) => i.fDef || 0);
|
||||||
|
prop(['airdef', 'adef'], 'number', (i, ie) => i.aDef || 0);
|
||||||
|
sum(['sumdef', 'totaldef'], props.edef, props.tdef, props.wdef, props.fdef, props.adef);
|
||||||
|
|
||||||
|
maxId(['earthdef%', 'edef%', 'edefpct'], 'eDefPct');
|
||||||
|
maxId(['thunderdef%', 'tdef%', 'tdefpct'], 'tDefPct');
|
||||||
|
maxId(['waterdef%', 'wdef%', 'wdefpct'], 'wDefPct');
|
||||||
|
maxId(['firedef%', 'fdef%', 'fdefpct'], 'fDefPct');
|
||||||
|
maxId(['airdef%', 'adef%', 'adefpct'], 'aDefPct');
|
||||||
|
sum(['sumdef%', 'totaldef%', 'sumdefpct', 'totaldefpct'], props.edefpct, props.tdefpct, props.wdefpct, props.fdefpct, props.adefpct);
|
||||||
|
|
||||||
|
prop(['health', 'hp'], 'number', (i, ie) => i.hp || 0);
|
||||||
|
maxId(['bonushealth', 'healthid', 'bonushp', 'hpid', 'hpbonus'], 'hpBonus');
|
||||||
|
sum(['sumhealth', 'sumhp', 'totalhealth', 'totalhp'], props.hp, props.hpid);
|
||||||
|
|
||||||
|
maxId(['hpregen', 'hpr', 'hr', 'hprraw'], 'hprRaw');
|
||||||
|
maxId(['hpregen%', 'hpr%', 'hr%', 'hprpct'], 'hprPct');
|
||||||
|
maxId(['lifesteal', 'ls'], 'ls');
|
||||||
|
maxId(['manaregen', 'mr'], 'mr');
|
||||||
|
maxId(['manasteal', 'ms'], 'ms');
|
||||||
|
|
||||||
|
maxId(['walkspeed', 'movespeed', 'ws', 'spd'], 'spd');
|
||||||
|
maxId('sprint', 'sprint');
|
||||||
|
maxId(['sprintregen', 'sprintreg'], 'sprintReg');
|
||||||
|
maxId(['jumpheight', 'jh'], 'jh');
|
||||||
|
|
||||||
|
maxId(['spellcost1', 'rawspellcost1', 'spcost1', 'spraw1'], 'spRaw1');
|
||||||
|
maxId(['spellcost1%', 'spcost1%', 'sppct1'], 'spPct1');
|
||||||
|
maxId(['spellcost2', 'rawspellcost2', 'spcost2', 'spraw2'], 'spRaw2');
|
||||||
|
maxId(['spellcost2%', 'spcost2%', 'sppct2'], 'spPct2');
|
||||||
|
maxId(['spellcost3', 'rawspellcost3', 'spcost3', 'spraw3'], 'spRaw3');
|
||||||
|
maxId(['spellcost3%', 'spcost3%', 'sppct3'], 'spPct3');
|
||||||
|
maxId(['spellcost4', 'rawspellcost4', 'spcost4', 'spraw4'], 'spRaw4');
|
||||||
|
maxId(['spellcost4%', 'spcost4%', 'sppct4'], 'spPct4');
|
||||||
|
sum(['sumspellcost', 'totalspellcost', 'sumrawspellcost', 'totalrawspellcost', 'sumspcost', 'totalspcost', 'sumspraw', 'totalspraw'], props.spraw1, props.spraw2, props.spraw3, props.spraw4);
|
||||||
|
sum(['sumspellcost%', 'totalspellcost%', 'sumspcost%', 'totalspcost%', 'sumsppct', 'totalsppct'], props.sppct1, props.sppct2, props.sppct3, props.sppct4);
|
||||||
|
|
||||||
|
maxId(['exploding', 'expl', 'expd'], 'expd');
|
||||||
|
maxId('poison', 'poison');
|
||||||
|
maxId('thorns', 'thorns');
|
||||||
|
maxId(['reflection', 'refl', 'ref'], 'ref');
|
||||||
|
maxId(['soulpointregen', 'spr', 'spregen'], 'spRegen');
|
||||||
|
maxId(['lootbonus', 'lb'], 'lb');
|
||||||
|
maxId(['xpbonus', 'xpb', 'xb'], 'xpb');
|
||||||
|
maxId(['stealing', 'esteal'], 'eSteal');
|
||||||
|
prop(['powderslots', 'powders', 'slots', 'sockets'], 'number', (i, ie) => i.slots || 0);
|
||||||
|
|
||||||
|
return props;
|
||||||
|
})();
|
||||||
|
|
||||||
|
// functions that can be called in query expressions
|
||||||
|
const itemQueryFuncs = {
|
||||||
|
max: {
|
||||||
|
type: 'number',
|
||||||
|
fn: function(item, itemExp, args) {
|
||||||
|
if (args.length < 1) throw new Error('Not enough args to max()');
|
||||||
|
let runningMax = -Infinity;
|
||||||
|
for (let i = 0; i < args.length; i++) {
|
||||||
|
if (checkNum(args[i]) > runningMax) runningMax = args[i];
|
||||||
|
}
|
||||||
|
return runningMax;
|
||||||
|
}
|
||||||
|
},
|
||||||
|
min: {
|
||||||
|
type: 'number',
|
||||||
|
fn: function(item, itemExp, args) {
|
||||||
|
if (args.length < 1) throw new Error('Not enough args to min()');
|
||||||
|
let runningMin = Infinity;
|
||||||
|
for (let i = 0; i < args.length; i++) {
|
||||||
|
if (checkNum(args[i]) < runningMin) runningMin = args[i];
|
||||||
|
}
|
||||||
|
return runningMin;
|
||||||
|
}
|
||||||
|
},
|
||||||
|
floor: {
|
||||||
|
type: 'number',
|
||||||
|
fn: function(item, itemExp, args) {
|
||||||
|
if (args.length < 1) throw new Error('Not enough args to floor()');
|
||||||
|
return Math.floor(checkNum(args[0]));
|
||||||
|
}
|
||||||
|
},
|
||||||
|
ceil: {
|
||||||
|
type: 'number',
|
||||||
|
fn: function(item, itemExp, args) {
|
||||||
|
if (args.length < 1) throw new Error('Not enough args to ceil()');
|
||||||
|
return Math.ceil(checkNum(args[0]));
|
||||||
|
}
|
||||||
|
},
|
||||||
|
round: {
|
||||||
|
type: 'number',
|
||||||
|
fn: function(item, itemExp, args) {
|
||||||
|
if (args.length < 1) throw new Error('Not enough args to round()');
|
||||||
|
return Math.round(checkNum(args[0]));
|
||||||
|
}
|
||||||
|
},
|
||||||
|
sqrt: {
|
||||||
|
type: 'number',
|
||||||
|
fn: function(item, itemExp, args) {
|
||||||
|
if (args.length < 1) throw new Error('Not enough args to sqrt()');
|
||||||
|
return Math.sqrt(checkNum(args[0]));
|
||||||
|
}
|
||||||
|
},
|
||||||
|
abs: {
|
||||||
|
type: 'number',
|
||||||
|
fn: function(item, itemExp, args) {
|
||||||
|
if (args.length < 1) throw new Error('Not enough args to abs()');
|
||||||
|
return Math.abs(checkNum(args[0]));
|
||||||
|
}
|
||||||
|
},
|
||||||
|
contains: {
|
||||||
|
type: 'boolean',
|
||||||
|
fn: function(item, itemExp, args) {
|
||||||
|
if (args.length < 2) throw new Error('Not enough args to contains()');
|
||||||
|
return checkStr(args[0]).toLowerCase().includes(checkStr(args[1]).toLowerCase());
|
||||||
|
}
|
||||||
|
},
|
||||||
|
atkspdmod: {
|
||||||
|
type: 'number',
|
||||||
|
fn: function(item, itemExp, args) {
|
||||||
|
if (args.length < 1) throw new Error('Not enough args to atkSpdMod()');
|
||||||
|
switch (checkNum(args[0])) {
|
||||||
|
case 2:
|
||||||
|
return 3.1;
|
||||||
|
case 1:
|
||||||
|
return 2.5;
|
||||||
|
case 0:
|
||||||
|
return 2.05;
|
||||||
|
case -1:
|
||||||
|
return 1.5;
|
||||||
|
case -2:
|
||||||
|
return 0.83;
|
||||||
|
}
|
||||||
|
if (args[0] <= -3) return 0.51;
|
||||||
|
if (args[0] >= 3) return 4.3;
|
||||||
|
throw new Error('Invalid argument to atkSpdMod()');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
// static type check
|
||||||
|
function staticCheck(expType, term) {
|
||||||
|
if (expType === 'any' || expType === term.type) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
if (expType === 'number' && term.type === 'boolean') {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
throw new Error(`Expected ${expType}, but got ${term.type}`);
|
||||||
|
}
|
||||||
|
|
||||||
|
// expression terms
|
||||||
|
class Term {
|
||||||
|
constructor(type) {
|
||||||
|
this.type = type;
|
||||||
|
}
|
||||||
|
|
||||||
|
resolve(item, itemExt) {
|
||||||
|
throw new Error('Abstract method!');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class LiteralTerm extends Term {
|
||||||
|
constructor(type, value) {
|
||||||
|
super(type);
|
||||||
|
this.value = value;
|
||||||
|
}
|
||||||
|
|
||||||
|
resolve(item, itemExt) {
|
||||||
|
return this.value;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class BoolLitTerm extends LiteralTerm {
|
||||||
|
constructor(value) {
|
||||||
|
super('boolean', value);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class NumLitTerm extends LiteralTerm {
|
||||||
|
constructor(value) {
|
||||||
|
super('number', value);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class StrLitTerm extends LiteralTerm {
|
||||||
|
constructor(value) {
|
||||||
|
super('string', value);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class BinaryOpTerm extends Term {
|
||||||
|
constructor(type, leftType, left, rightType, right) {
|
||||||
|
super(type);
|
||||||
|
staticCheck(leftType, left);
|
||||||
|
staticCheck(rightType, right);
|
||||||
|
this.left = left;
|
||||||
|
this.right = right;
|
||||||
|
}
|
||||||
|
|
||||||
|
resolve(item, itemExt) {
|
||||||
|
return this.apply(this.left.resolve(item, itemExt), this.right.resolve(item, itemExt));
|
||||||
|
}
|
||||||
|
|
||||||
|
apply(a, b) {
|
||||||
|
throw new Error('Abstract method!');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class LogicalTerm extends BinaryOpTerm {
|
||||||
|
constructor(left, right) {
|
||||||
|
super('boolean', 'boolean', left, 'boolean', right);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class ConjTerm extends LogicalTerm {
|
||||||
|
apply(a, b) {
|
||||||
|
return a && b;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class DisjTerm extends LogicalTerm {
|
||||||
|
apply(a, b) {
|
||||||
|
return a || b;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class EqualityTerm extends BinaryOpTerm {
|
||||||
|
constructor(left, right) {
|
||||||
|
super('boolean', 'any', left, 'any', right);
|
||||||
|
}
|
||||||
|
|
||||||
|
apply(a, b) {
|
||||||
|
return (typeof a === 'string' && typeof b === 'string')
|
||||||
|
? this.compare(a.toLowerCase(), b.toLowerCase()) : this.compare(a, b);
|
||||||
|
}
|
||||||
|
|
||||||
|
compare(a, b) {
|
||||||
|
throw new Error('Abstract method!');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class EqTerm extends EqualityTerm {
|
||||||
|
compare(a, b) {
|
||||||
|
return a === b;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class NeqTerm extends EqualityTerm {
|
||||||
|
compare(a, b) {
|
||||||
|
return a !== b;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class ContainsTerm extends BinaryOpTerm {
|
||||||
|
constructor(left, right) {
|
||||||
|
super('boolean', 'string', left, 'string', right);
|
||||||
|
}
|
||||||
|
|
||||||
|
apply(a, b) {
|
||||||
|
return a.toLowerCase().includes(b.toLowerCase());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class InequalityTerm extends BinaryOpTerm {
|
||||||
|
constructor(left, right) {
|
||||||
|
super('boolean', 'any', left, 'any', right);
|
||||||
|
}
|
||||||
|
|
||||||
|
apply(a, b) {
|
||||||
|
checkComparable(a);
|
||||||
|
checkComparable(b);
|
||||||
|
return (typeof a === 'string' && typeof b === 'string')
|
||||||
|
? this.compare(a.toLowerCase(), b.toLowerCase()) : this.compare(a, b);
|
||||||
|
}
|
||||||
|
|
||||||
|
compare(a, b) {
|
||||||
|
throw new Error('Abstract method!');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class LeqTerm extends InequalityTerm {
|
||||||
|
compare(a, b) {
|
||||||
|
return a <= b;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class LtTerm extends InequalityTerm {
|
||||||
|
compare(a, b) {
|
||||||
|
return a < b;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class GtTerm extends InequalityTerm {
|
||||||
|
compare(a, b) {
|
||||||
|
return a > b;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class GeqTerm extends InequalityTerm {
|
||||||
|
compare(a, b) {
|
||||||
|
return a >= b;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class ArithmeticTerm extends BinaryOpTerm {
|
||||||
|
constructor(left, right) {
|
||||||
|
super('number', 'number', left, 'number', right);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class AddTerm extends ArithmeticTerm {
|
||||||
|
apply(a, b) {
|
||||||
|
return a + b;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class SubTerm extends ArithmeticTerm {
|
||||||
|
apply(a, b) {
|
||||||
|
return a - b;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class MulTerm extends ArithmeticTerm {
|
||||||
|
apply(a, b) {
|
||||||
|
return a * b;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class DivTerm extends ArithmeticTerm {
|
||||||
|
apply(a, b) {
|
||||||
|
return a / b;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class ExpTerm extends ArithmeticTerm {
|
||||||
|
apply(a, b) {
|
||||||
|
return a ** b;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class UnaryOpTerm extends Term {
|
||||||
|
constructor(type, inType, inVal) {
|
||||||
|
super(type);
|
||||||
|
staticCheck(inType, inVal);
|
||||||
|
this.inVal = inVal;
|
||||||
|
}
|
||||||
|
|
||||||
|
resolve(item, itemExt) {
|
||||||
|
return this.apply(this.inVal.resolve(item, itemExt));
|
||||||
|
}
|
||||||
|
|
||||||
|
apply(x) {
|
||||||
|
throw new Error('Abstract method!');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class NegTerm extends UnaryOpTerm {
|
||||||
|
constructor(inVal) {
|
||||||
|
super('number', 'number', inVal);
|
||||||
|
}
|
||||||
|
|
||||||
|
apply(x) {
|
||||||
|
return -x;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class InvTerm extends UnaryOpTerm {
|
||||||
|
constructor(inVal) {
|
||||||
|
super('boolean', 'boolean', inVal);
|
||||||
|
}
|
||||||
|
|
||||||
|
apply(x) {
|
||||||
|
return !x;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class FnCallTerm extends Term {
|
||||||
|
constructor(fn, argExprs) {
|
||||||
|
super(fn.type);
|
||||||
|
this.fn = fn;
|
||||||
|
this.argExprs = argExprs;
|
||||||
|
}
|
||||||
|
|
||||||
|
resolve(item, itemExt) {
|
||||||
|
const argVals = [];
|
||||||
|
for (const argExpr of this.argExprs) {
|
||||||
|
argVals.push(argExpr.resolve(item, itemExt));
|
||||||
|
}
|
||||||
|
return this.fn.fn(item, itemExt, argVals);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class PropTerm extends Term {
|
||||||
|
constructor(prop) {
|
||||||
|
super(prop.type);
|
||||||
|
this.prop = prop;
|
||||||
|
}
|
||||||
|
|
||||||
|
resolve(item, itemExt) {
|
||||||
|
return this.prop.resolve(item, itemExt);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function compareLexico(ia, keysA, ib, keysB) {
|
||||||
|
for (let i = 0; i < keysA.length; i++) { // assuming keysA and keysB are the same length
|
||||||
|
let aKey = keysA[i], bKey = keysB[i];
|
||||||
|
if (typeof aKey !== typeof bKey) throw new Error(`Incomparable types ${typeof aKey} and ${typeof bKey}`); // can this even happen?
|
||||||
|
switch (typeof aKey) {
|
||||||
|
case 'string':
|
||||||
|
aKey = aKey.toLowerCase();
|
||||||
|
bKey = bKey.toLowerCase();
|
||||||
|
if (aKey < bKey) return -1;
|
||||||
|
if (aKey > bKey) return 1;
|
||||||
|
break;
|
||||||
|
case 'number': // sort numeric stuff in reverse order
|
||||||
|
aKey = isNaN(aKey) ? 0 : aKey;
|
||||||
|
bKey = isNaN(bKey) ? 0 : bKey;
|
||||||
|
if (aKey < bKey) return 1;
|
||||||
|
if (aKey > bKey) return -1;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
throw new Error(`Incomparable type ${typeof aKey}`);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return ib.lvl - ia.lvl;
|
||||||
}
|
}
|
||||||
|
|
549
js/query_2.js
|
@ -1,549 +0,0 @@
|
||||||
// dynamic type casts
|
|
||||||
function checkBool(v) {
|
|
||||||
if (typeof v !== 'boolean') throw new Error(`Expected boolean, but got ${typeof v}`);
|
|
||||||
return v;
|
|
||||||
}
|
|
||||||
|
|
||||||
function checkNum(v) {
|
|
||||||
if (typeof v === 'boolean') {
|
|
||||||
if (v) return 1;
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
if (typeof v !== 'number') throw new Error(`Expected number, but got ${typeof v}`);
|
|
||||||
return v;
|
|
||||||
}
|
|
||||||
|
|
||||||
function checkStr(v) {
|
|
||||||
if (typeof v !== 'string') throw new Error(`Expected string, but got ${typeof v}`);
|
|
||||||
return v;
|
|
||||||
}
|
|
||||||
|
|
||||||
function checkComparable(v) {
|
|
||||||
if (typeof v === 'boolean') throw new Error('Boolean is not comparable');
|
|
||||||
return v;
|
|
||||||
}
|
|
||||||
|
|
||||||
// properties of items that can be looked up
|
|
||||||
// each entry is a function `(item, extended item) -> value`
|
|
||||||
const itemQueryProps = (function() {
|
|
||||||
const props = {};
|
|
||||||
|
|
||||||
function prop(names, type, resolve) {
|
|
||||||
if (Array.isArray(names)) {
|
|
||||||
for (name of names) {
|
|
||||||
props[name] = { type, resolve };
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
props[names] = { type, resolve };
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
function maxId(names, idKey) {
|
|
||||||
prop(names, 'number', (i, ie) => ie.get('maxRolls').get(idKey) || 0);
|
|
||||||
}
|
|
||||||
|
|
||||||
function minId(names, idKey) {
|
|
||||||
prop(names, 'number', (i, ie) => ie.get('minRolls').get(idKey) || 0);
|
|
||||||
}
|
|
||||||
|
|
||||||
function rangeAvg(names, getProp) {
|
|
||||||
prop(names, 'number', (i, ie) => {
|
|
||||||
const range = getProp(i, ie);
|
|
||||||
if (!range) return 0;
|
|
||||||
const ndx = range.indexOf('-');
|
|
||||||
return (parseInt(range.substring(0, ndx), 10) + parseInt(range.substring(ndx + 1), 10)) / 2;
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
function map(names, comps, outType, f) {
|
|
||||||
return prop(names, outType, (i, ie) => {
|
|
||||||
const args = [];
|
|
||||||
for (let k = 0; k < comps.length; k++) args.push(comps[k].resolve(i, ie));
|
|
||||||
return f.apply(null, args);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
function sum(names, ...comps) {
|
|
||||||
return map(names, comps, 'number', (...summands) => {
|
|
||||||
let total = 0;
|
|
||||||
for (let i = 0; i < summands.length; i++) total += summands[i];
|
|
||||||
return total;
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
prop('name', 'string', (i, ie) => i.displayName || i.name);
|
|
||||||
prop('type', 'string', (i, ie) => i.type);
|
|
||||||
prop(['cat', 'category'], 'string', (i, ie) => i.category);
|
|
||||||
const tierIndices = { Normal: 0, Unique: 1, Set: 2, Rare: 3, Legendary: 4, Fabled: 5, Mythic: 6 };
|
|
||||||
prop(['rarityname', 'raritystr', 'tiername', 'tierstr'], 'string', (i, ie) => i.tier);
|
|
||||||
prop(['rarity', 'tier'], 'number', (i, ie) => tierIndices[i.tier]);
|
|
||||||
|
|
||||||
prop(['level', 'lvl', 'combatlevel', 'combatlvl'], 'number', (i, ie) => i.lvl);
|
|
||||||
prop(['strmin', 'strreq'], 'number', (i, ie) => i.strReq);
|
|
||||||
prop(['dexmin', 'dexreq'], 'number', (i, ie) => i.dexReq);
|
|
||||||
prop(['intmin', 'intreq'], 'number', (i, ie) => i.intReq);
|
|
||||||
prop(['defmin', 'defreq'], 'number', (i, ie) => i.defReq);
|
|
||||||
prop(['agimin', 'agireq'], 'number', (i, ie) => i.agiReq);
|
|
||||||
sum(['summin', 'sumreq', 'totalmin', 'totalreq'], props.strmin, props.dexmin, props.intmin, props.defmin, props.agimin);
|
|
||||||
|
|
||||||
prop('str', 'number', (i, ie) => i.str);
|
|
||||||
prop('dex', 'number', (i, ie) => i.dex);
|
|
||||||
prop('int', 'number', (i, ie) => i.int);
|
|
||||||
prop('def', 'number', (i, ie) => i.def);
|
|
||||||
prop('agi', 'number', (i, ie) => i.agi);
|
|
||||||
sum(['skillpoints', 'skillpts', 'attributes', 'attrs'], props.str, props.dex, props.int, props.def, props.agi);
|
|
||||||
|
|
||||||
rangeAvg(['neutraldmg', 'neutraldam', 'ndmg', 'ndam'], (i, ie) => i.nDam);
|
|
||||||
rangeAvg(['earthdmg', 'earthdam', 'edmg', 'edam'], (i, ie) => i.eDam);
|
|
||||||
rangeAvg(['thunderdmg', 'thunderdam', 'tdmg', 'tdam'], (i, ie) => i.tDam);
|
|
||||||
rangeAvg(['waterdmg', 'waterdam', 'wdmg', 'wdam'], (i, ie) => i.wDam);
|
|
||||||
rangeAvg(['firedmg', 'firedam', 'fdmg', 'fdam'], (i, ie) => i.fDam);
|
|
||||||
rangeAvg(['airdmg', 'airdam', 'admg', 'adam'], (i, ie) => i.aDam);
|
|
||||||
sum(['sumdmg', 'sumdam', 'totaldmg', 'totaldam'], props.ndam, props.edam, props.tdam, props.wdam, props.fdam, props.adam);
|
|
||||||
|
|
||||||
maxId(['earthdmg%', 'earthdam%', 'edmg%', 'edam%', 'edampct'], 'eDamPct');
|
|
||||||
maxId(['thunderdmg%', 'thunderdam%', 'tdmg%', 'tdam%', 'tdampct'], 'tDamPct');
|
|
||||||
maxId(['waterdmg%', 'waterdam%', 'wdmg%', 'wdam%', 'wdampct'], 'wDamPct');
|
|
||||||
maxId(['firedmg%', 'firedam%', 'fdmg%', 'fdam%', 'fdampct'], 'fDamPct');
|
|
||||||
maxId(['airdmg%', 'airdam%', 'admg%', 'adam%', 'adampct'], 'aDamPct');
|
|
||||||
sum(['sumdmg%', 'sumdam%', 'totaldmg%', 'totaldam%', 'sumdampct', 'totaldampct'], props.edampct, props.tdampct, props.wdampct, props.fdampct, props.adampct);
|
|
||||||
|
|
||||||
maxId(['mainatkdmg', 'mainatkdam', 'mainatkdmg%', 'mainatkdam%', 'meleedmg', 'meleedam', 'meleedmg%', 'meleedam%', 'mdpct'], 'mdPct');
|
|
||||||
maxId(['mainatkrawdmg', 'mainatkrawdam', 'mainatkneutraldmg', 'mainatkneutraldam', 'meleerawdmg', 'meleerawdam', 'meleeneutraldmg', 'meleeneutraldam', 'mdraw'], 'mdRaw');
|
|
||||||
maxId(['spelldmg', 'spelldam', 'spelldmg%', 'spelldam%', 'sdpct'], 'sdPct');
|
|
||||||
maxId(['spellrawdmg', 'spellrawdam', 'spellneutraldmg', 'spellneutraldam', 'sdraw'], 'sdRaw');
|
|
||||||
|
|
||||||
const atkSpdIndices = { SUPER_SLOW: -3, VERY_SLOW: -2, SLOW: -1, NORMAL: 0, FAST: 1, VERY_FAST: 2, SUPER_FAST: 3 };
|
|
||||||
prop(['attackspeed', 'atkspd'], 'string', (i, ie) => i.atkSpd ? atkSpdIndices[i.atkSpd] : 0);
|
|
||||||
maxId(['bonusattackspeed', 'bonusatkspd', 'attackspeedid', 'atkspdid', 'atktier'], 'atkTier');
|
|
||||||
sum(['sumattackspeed', 'totalattackspeed', 'sumatkspd', 'totalatkspd', 'sumatktier', 'totalatktier'], props.atkspd, props.atktier);
|
|
||||||
|
|
||||||
prop(['earthdef', 'edef'], 'number', (i, ie) => i.eDef || 0);
|
|
||||||
prop(['thunderdef', 'tdef'], 'number', (i, ie) => i.tDef || 0);
|
|
||||||
prop(['waterdef', 'wdef'], 'number', (i, ie) => i.wDef || 0);
|
|
||||||
prop(['firedef', 'fdef'], 'number', (i, ie) => i.fDef || 0);
|
|
||||||
prop(['airdef', 'adef'], 'number', (i, ie) => i.aDef || 0);
|
|
||||||
sum(['sumdef', 'totaldef'], props.edef, props.tdef, props.wdef, props.fdef, props.adef);
|
|
||||||
|
|
||||||
maxId(['earthdef%', 'edef%', 'edefpct'], 'eDefPct');
|
|
||||||
maxId(['thunderdef%', 'tdef%', 'tdefpct'], 'tDefPct');
|
|
||||||
maxId(['waterdef%', 'wdef%', 'wdefpct'], 'wDefPct');
|
|
||||||
maxId(['firedef%', 'fdef%', 'fdefpct'], 'fDefPct');
|
|
||||||
maxId(['airdef%', 'adef%', 'adefpct'], 'aDefPct');
|
|
||||||
sum(['sumdef%', 'totaldef%', 'sumdefpct', 'totaldefpct'], props.edefpct, props.tdefpct, props.wdefpct, props.fdefpct, props.adefpct);
|
|
||||||
|
|
||||||
prop(['health', 'hp'], 'number', (i, ie) => i.hp || 0);
|
|
||||||
maxId(['bonushealth', 'healthid', 'bonushp', 'hpid', 'hpbonus'], 'hpBonus');
|
|
||||||
sum(['sumhealth', 'sumhp', 'totalhealth', 'totalhp'], props.hp, props.hpid);
|
|
||||||
|
|
||||||
maxId(['hpregen', 'hpr', 'hr', 'hprraw'], 'hprRaw');
|
|
||||||
maxId(['hpregen%', 'hpr%', 'hr%', 'hprpct'], 'hprPct');
|
|
||||||
maxId(['lifesteal', 'ls'], 'ls');
|
|
||||||
maxId(['manaregen', 'mr'], 'mr');
|
|
||||||
maxId(['manasteal', 'ms'], 'ms');
|
|
||||||
|
|
||||||
maxId(['walkspeed', 'movespeed', 'ws', 'spd'], 'spd');
|
|
||||||
maxId('sprint', 'sprint');
|
|
||||||
maxId(['sprintregen', 'sprintreg'], 'sprintReg');
|
|
||||||
maxId(['jumpheight', 'jh'], 'jh');
|
|
||||||
|
|
||||||
maxId(['spellcost1', 'rawspellcost1', 'spcost1', 'spraw1'], 'spRaw1');
|
|
||||||
maxId(['spellcost1%', 'spcost1%', 'sppct1'], 'spPct1');
|
|
||||||
maxId(['spellcost2', 'rawspellcost2', 'spcost2', 'spraw2'], 'spRaw2');
|
|
||||||
maxId(['spellcost2%', 'spcost2%', 'sppct2'], 'spPct2');
|
|
||||||
maxId(['spellcost3', 'rawspellcost3', 'spcost3', 'spraw3'], 'spRaw3');
|
|
||||||
maxId(['spellcost3%', 'spcost3%', 'sppct3'], 'spPct3');
|
|
||||||
maxId(['spellcost4', 'rawspellcost4', 'spcost4', 'spraw4'], 'spRaw4');
|
|
||||||
maxId(['spellcost4%', 'spcost4%', 'sppct4'], 'spPct4');
|
|
||||||
sum(['sumspellcost', 'totalspellcost', 'sumrawspellcost', 'totalrawspellcost', 'sumspcost', 'totalspcost', 'sumspraw', 'totalspraw'], props.spraw1, props.spraw2, props.spraw3, props.spraw4);
|
|
||||||
sum(['sumspellcost%', 'totalspellcost%', 'sumspcost%', 'totalspcost%', 'sumsppct', 'totalsppct'], props.sppct1, props.sppct2, props.sppct3, props.sppct4);
|
|
||||||
|
|
||||||
maxId(['exploding', 'expl', 'expd'], 'expd');
|
|
||||||
maxId('poison', 'poison');
|
|
||||||
maxId('thorns', 'thorns');
|
|
||||||
maxId(['reflection', 'refl', 'ref'], 'ref');
|
|
||||||
maxId(['soulpointregen', 'spr', 'spregen'], 'spRegen');
|
|
||||||
maxId(['lootbonus', 'lb'], 'lb');
|
|
||||||
maxId(['xpbonus', 'xpb', 'xb'], 'xpb');
|
|
||||||
maxId(['stealing', 'esteal'], 'eSteal');
|
|
||||||
prop(['powderslots', 'powders', 'slots', 'sockets'], 'number', (i, ie) => i.slots || 0);
|
|
||||||
|
|
||||||
return props;
|
|
||||||
})();
|
|
||||||
|
|
||||||
// functions that can be called in query expressions
|
|
||||||
const itemQueryFuncs = {
|
|
||||||
max: {
|
|
||||||
type: 'number',
|
|
||||||
fn: function(item, itemExp, args) {
|
|
||||||
if (args.length < 1) throw new Error('Not enough args to max()');
|
|
||||||
let runningMax = -Infinity;
|
|
||||||
for (let i = 0; i < args.length; i++) {
|
|
||||||
if (checkNum(args[i]) > runningMax) runningMax = args[i];
|
|
||||||
}
|
|
||||||
return runningMax;
|
|
||||||
}
|
|
||||||
},
|
|
||||||
min: {
|
|
||||||
type: 'number',
|
|
||||||
fn: function(item, itemExp, args) {
|
|
||||||
if (args.length < 1) throw new Error('Not enough args to min()');
|
|
||||||
let runningMin = Infinity;
|
|
||||||
for (let i = 0; i < args.length; i++) {
|
|
||||||
if (checkNum(args[i]) < runningMin) runningMin = args[i];
|
|
||||||
}
|
|
||||||
return runningMin;
|
|
||||||
}
|
|
||||||
},
|
|
||||||
floor: {
|
|
||||||
type: 'number',
|
|
||||||
fn: function(item, itemExp, args) {
|
|
||||||
if (args.length < 1) throw new Error('Not enough args to floor()');
|
|
||||||
return Math.floor(checkNum(args[0]));
|
|
||||||
}
|
|
||||||
},
|
|
||||||
ceil: {
|
|
||||||
type: 'number',
|
|
||||||
fn: function(item, itemExp, args) {
|
|
||||||
if (args.length < 1) throw new Error('Not enough args to ceil()');
|
|
||||||
return Math.ceil(checkNum(args[0]));
|
|
||||||
}
|
|
||||||
},
|
|
||||||
round: {
|
|
||||||
type: 'number',
|
|
||||||
fn: function(item, itemExp, args) {
|
|
||||||
if (args.length < 1) throw new Error('Not enough args to round()');
|
|
||||||
return Math.round(checkNum(args[0]));
|
|
||||||
}
|
|
||||||
},
|
|
||||||
sqrt: {
|
|
||||||
type: 'number',
|
|
||||||
fn: function(item, itemExp, args) {
|
|
||||||
if (args.length < 1) throw new Error('Not enough args to sqrt()');
|
|
||||||
return Math.sqrt(checkNum(args[0]));
|
|
||||||
}
|
|
||||||
},
|
|
||||||
abs: {
|
|
||||||
type: 'number',
|
|
||||||
fn: function(item, itemExp, args) {
|
|
||||||
if (args.length < 1) throw new Error('Not enough args to abs()');
|
|
||||||
return Math.abs(checkNum(args[0]));
|
|
||||||
}
|
|
||||||
},
|
|
||||||
contains: {
|
|
||||||
type: 'boolean',
|
|
||||||
fn: function(item, itemExp, args) {
|
|
||||||
if (args.length < 2) throw new Error('Not enough args to contains()');
|
|
||||||
return checkStr(args[0]).toLowerCase().includes(checkStr(args[1]).toLowerCase());
|
|
||||||
}
|
|
||||||
},
|
|
||||||
atkspdmod: {
|
|
||||||
type: 'number',
|
|
||||||
fn: function(item, itemExp, args) {
|
|
||||||
if (args.length < 1) throw new Error('Not enough args to atkSpdMod()');
|
|
||||||
switch (checkNum(args[0])) {
|
|
||||||
case 2:
|
|
||||||
return 3.1;
|
|
||||||
case 1:
|
|
||||||
return 2.5;
|
|
||||||
case 0:
|
|
||||||
return 2.05;
|
|
||||||
case -1:
|
|
||||||
return 1.5;
|
|
||||||
case -2:
|
|
||||||
return 0.83;
|
|
||||||
}
|
|
||||||
if (args[0] <= -3) return 0.51;
|
|
||||||
if (args[0] >= 3) return 4.3;
|
|
||||||
throw new Error('Invalid argument to atkSpdMod()');
|
|
||||||
}
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
// static type check
|
|
||||||
function staticCheck(expType, term) {
|
|
||||||
if (expType === 'any' || expType === term.type) {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
if (expType === 'number' && term.type === 'boolean') {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
throw new Error(`Expected ${expType}, but got ${term.type}`);
|
|
||||||
}
|
|
||||||
|
|
||||||
// expression terms
|
|
||||||
class Term {
|
|
||||||
constructor(type) {
|
|
||||||
this.type = type;
|
|
||||||
}
|
|
||||||
|
|
||||||
resolve(item, itemExt) {
|
|
||||||
throw new Error('Abstract method!');
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
class LiteralTerm extends Term {
|
|
||||||
constructor(type, value) {
|
|
||||||
super(type);
|
|
||||||
this.value = value;
|
|
||||||
}
|
|
||||||
|
|
||||||
resolve(item, itemExt) {
|
|
||||||
return this.value;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
class BoolLitTerm extends LiteralTerm {
|
|
||||||
constructor(value) {
|
|
||||||
super('boolean', value);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
class NumLitTerm extends LiteralTerm {
|
|
||||||
constructor(value) {
|
|
||||||
super('number', value);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
class StrLitTerm extends LiteralTerm {
|
|
||||||
constructor(value) {
|
|
||||||
super('string', value);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
class BinaryOpTerm extends Term {
|
|
||||||
constructor(type, leftType, left, rightType, right) {
|
|
||||||
super(type);
|
|
||||||
staticCheck(leftType, left);
|
|
||||||
staticCheck(rightType, right);
|
|
||||||
this.left = left;
|
|
||||||
this.right = right;
|
|
||||||
}
|
|
||||||
|
|
||||||
resolve(item, itemExt) {
|
|
||||||
return this.apply(this.left.resolve(item, itemExt), this.right.resolve(item, itemExt));
|
|
||||||
}
|
|
||||||
|
|
||||||
apply(a, b) {
|
|
||||||
throw new Error('Abstract method!');
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
class LogicalTerm extends BinaryOpTerm {
|
|
||||||
constructor(left, right) {
|
|
||||||
super('boolean', 'boolean', left, 'boolean', right);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
class ConjTerm extends LogicalTerm {
|
|
||||||
apply(a, b) {
|
|
||||||
return a && b;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
class DisjTerm extends LogicalTerm {
|
|
||||||
apply(a, b) {
|
|
||||||
return a || b;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
class EqualityTerm extends BinaryOpTerm {
|
|
||||||
constructor(left, right) {
|
|
||||||
super('boolean', 'any', left, 'any', right);
|
|
||||||
}
|
|
||||||
|
|
||||||
apply(a, b) {
|
|
||||||
return (typeof a === 'string' && typeof b === 'string')
|
|
||||||
? this.compare(a.toLowerCase(), b.toLowerCase()) : this.compare(a, b);
|
|
||||||
}
|
|
||||||
|
|
||||||
compare(a, b) {
|
|
||||||
throw new Error('Abstract method!');
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
class EqTerm extends EqualityTerm {
|
|
||||||
compare(a, b) {
|
|
||||||
return a === b;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
class NeqTerm extends EqualityTerm {
|
|
||||||
compare(a, b) {
|
|
||||||
return a !== b;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
class ContainsTerm extends BinaryOpTerm {
|
|
||||||
constructor(left, right) {
|
|
||||||
super('boolean', 'string', left, 'string', right);
|
|
||||||
}
|
|
||||||
|
|
||||||
apply(a, b) {
|
|
||||||
return a.toLowerCase().includes(b.toLowerCase());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
class InequalityTerm extends BinaryOpTerm {
|
|
||||||
constructor(left, right) {
|
|
||||||
super('boolean', 'any', left, 'any', right);
|
|
||||||
}
|
|
||||||
|
|
||||||
apply(a, b) {
|
|
||||||
checkComparable(a);
|
|
||||||
checkComparable(b);
|
|
||||||
return (typeof a === 'string' && typeof b === 'string')
|
|
||||||
? this.compare(a.toLowerCase(), b.toLowerCase()) : this.compare(a, b);
|
|
||||||
}
|
|
||||||
|
|
||||||
compare(a, b) {
|
|
||||||
throw new Error('Abstract method!');
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
class LeqTerm extends InequalityTerm {
|
|
||||||
compare(a, b) {
|
|
||||||
return a <= b;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
class LtTerm extends InequalityTerm {
|
|
||||||
compare(a, b) {
|
|
||||||
return a < b;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
class GtTerm extends InequalityTerm {
|
|
||||||
compare(a, b) {
|
|
||||||
return a > b;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
class GeqTerm extends InequalityTerm {
|
|
||||||
compare(a, b) {
|
|
||||||
return a >= b;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
class ArithmeticTerm extends BinaryOpTerm {
|
|
||||||
constructor(left, right) {
|
|
||||||
super('number', 'number', left, 'number', right);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
class AddTerm extends ArithmeticTerm {
|
|
||||||
apply(a, b) {
|
|
||||||
return a + b;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
class SubTerm extends ArithmeticTerm {
|
|
||||||
apply(a, b) {
|
|
||||||
return a - b;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
class MulTerm extends ArithmeticTerm {
|
|
||||||
apply(a, b) {
|
|
||||||
return a * b;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
class DivTerm extends ArithmeticTerm {
|
|
||||||
apply(a, b) {
|
|
||||||
return a / b;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
class ExpTerm extends ArithmeticTerm {
|
|
||||||
apply(a, b) {
|
|
||||||
return a ** b;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
class UnaryOpTerm extends Term {
|
|
||||||
constructor(type, inType, inVal) {
|
|
||||||
super(type);
|
|
||||||
staticCheck(inType, inVal);
|
|
||||||
this.inVal = inVal;
|
|
||||||
}
|
|
||||||
|
|
||||||
resolve(item, itemExt) {
|
|
||||||
return this.apply(this.inVal.resolve(item, itemExt));
|
|
||||||
}
|
|
||||||
|
|
||||||
apply(x) {
|
|
||||||
throw new Error('Abstract method!');
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
class NegTerm extends UnaryOpTerm {
|
|
||||||
constructor(inVal) {
|
|
||||||
super('number', 'number', inVal);
|
|
||||||
}
|
|
||||||
|
|
||||||
apply(x) {
|
|
||||||
return -x;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
class InvTerm extends UnaryOpTerm {
|
|
||||||
constructor(inVal) {
|
|
||||||
super('boolean', 'boolean', inVal);
|
|
||||||
}
|
|
||||||
|
|
||||||
apply(x) {
|
|
||||||
return !x;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
class FnCallTerm extends Term {
|
|
||||||
constructor(fn, argExprs) {
|
|
||||||
super(fn.type);
|
|
||||||
this.fn = fn;
|
|
||||||
this.argExprs = argExprs;
|
|
||||||
}
|
|
||||||
|
|
||||||
resolve(item, itemExt) {
|
|
||||||
const argVals = [];
|
|
||||||
for (const argExpr of this.argExprs) {
|
|
||||||
argVals.push(argExpr.resolve(item, itemExt));
|
|
||||||
}
|
|
||||||
return this.fn.fn(item, itemExt, argVals);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
class PropTerm extends Term {
|
|
||||||
constructor(prop) {
|
|
||||||
super(prop.type);
|
|
||||||
this.prop = prop;
|
|
||||||
}
|
|
||||||
|
|
||||||
resolve(item, itemExt) {
|
|
||||||
return this.prop.resolve(item, itemExt);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
function compareLexico(ia, keysA, ib, keysB) {
|
|
||||||
for (let i = 0; i < keysA.length; i++) { // assuming keysA and keysB are the same length
|
|
||||||
let aKey = keysA[i], bKey = keysB[i];
|
|
||||||
if (typeof aKey !== typeof bKey) throw new Error(`Incomparable types ${typeof aKey} and ${typeof bKey}`); // can this even happen?
|
|
||||||
switch (typeof aKey) {
|
|
||||||
case 'string':
|
|
||||||
aKey = aKey.toLowerCase();
|
|
||||||
bKey = bKey.toLowerCase();
|
|
||||||
if (aKey < bKey) return -1;
|
|
||||||
if (aKey > bKey) return 1;
|
|
||||||
break;
|
|
||||||
case 'number': // sort numeric stuff in reverse order
|
|
||||||
aKey = isNaN(aKey) ? 0 : aKey;
|
|
||||||
bKey = isNaN(bKey) ? 0 : bKey;
|
|
||||||
if (aKey < bKey) return 1;
|
|
||||||
if (aKey > bKey) return -1;
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
throw new Error(`Incomparable type ${typeof aKey}`);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return ib.lvl - ia.lvl;
|
|
||||||
}
|
|
|
@ -187,8 +187,17 @@ function calculate_skillpoints(equipment, weapon) {
|
||||||
permute_check(idx+1, skillpoints_applied, skillpoints, activeSetCounts, has_skillpoint, total_applied, order.concat(permutation.map(x => x.item)));
|
permute_check(idx+1, skillpoints_applied, skillpoints, activeSetCounts, has_skillpoint, total_applied, order.concat(permutation.map(x => x.item)));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
if (sccs.length === 1) {
|
||||||
|
// Only crafteds. Just do end check (check req first, then apply sp after)
|
||||||
|
const total = check_end(best_skillpoints, final_skillpoints, best_activeSetCounts, allFalse.slice());
|
||||||
|
final_skillpoints = best_skillpoints.slice();
|
||||||
|
best_total = total;
|
||||||
|
best_activeSetCounts = best_activeSetCounts;
|
||||||
|
best = [];
|
||||||
|
} else {
|
||||||
// skip root.
|
// skip root.
|
||||||
permute_check(1, best_skillpoints, final_skillpoints, best_activeSetCounts, allFalse.slice(), 0, []);
|
permute_check(1, best_skillpoints, final_skillpoints, best_activeSetCounts, allFalse.slice(), 0, []);
|
||||||
|
}
|
||||||
|
|
||||||
// add extra sp bonus
|
// add extra sp bonus
|
||||||
apply_skillpoints(final_skillpoints, weapon, best_activeSetCounts);
|
apply_skillpoints(final_skillpoints, weapon, best_activeSetCounts);
|
||||||
|
|
|
@ -1,34 +0,0 @@
|
||||||
//which icons to use
|
|
||||||
let window_storage = window.localStorage;
|
|
||||||
console.log(window_storage);
|
|
||||||
icon_state_stored = window_storage.getItem("newicons");
|
|
||||||
newIcons = true;
|
|
||||||
if (icon_state_stored === "false") {toggleIcons()}
|
|
||||||
|
|
||||||
|
|
||||||
/** Toggle icons on the ENTIRE page.
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
function toggleIcons() {
|
|
||||||
newIcons = !newIcons;
|
|
||||||
let imgs = document.getElementsByTagName("IMG");
|
|
||||||
let favicon = document.querySelector("link[rel~='icon']");
|
|
||||||
|
|
||||||
if (newIcons) { //switch to new
|
|
||||||
favicon.href = favicon.href.replace("media/icons/old","media/icons/new");
|
|
||||||
for (const img of imgs) {
|
|
||||||
if (img.src.includes("media/icons/old")) {img.src = img.src.replace("media/icons/old","media/icons/new");}
|
|
||||||
if (img.src.includes("media/items/old")) {img.src = img.src.replace("media/items/old","media/items/new");}
|
|
||||||
}
|
|
||||||
//toggleiconbutton.textContent = "Use Old Icons";
|
|
||||||
window_storage.setItem("newicons","true");
|
|
||||||
} else { //switch to old
|
|
||||||
favicon.href = favicon.href.replace("media/icons/new","media/icons/old");
|
|
||||||
for (const img of imgs) {
|
|
||||||
if (img.src.includes("media/icons/new")) {img.src = img.src.replace("media/icons/new","media/icons/old");}
|
|
||||||
if (img.src.includes("media/items/new")) {img.src = img.src.replace("media/items/new","media/items/old");}
|
|
||||||
}
|
|
||||||
//toggleiconbutton.textContent = "Use New Icons";
|
|
||||||
window_storage.setItem("newicons","false");
|
|
||||||
}
|
|
||||||
}
|
|
264
js/sq2items.js
|
@ -1,264 +0,0 @@
|
||||||
let itemCategories = [ "armor", "accessory", "weapon" ];
|
|
||||||
|
|
||||||
const sq2_translate_mappings = {
|
|
||||||
//"Name": "name",
|
|
||||||
//"Display Name": "displayName",
|
|
||||||
//"tier"Tier": ",
|
|
||||||
//"Set": "set",
|
|
||||||
"Powder Slots": "slots",
|
|
||||||
//"Type": "type",
|
|
||||||
//"armorType", (deleted)
|
|
||||||
//"color", (deleted)
|
|
||||||
//"lore", (deleted)
|
|
||||||
//"material", (deleted)
|
|
||||||
"Drop type": "drop",
|
|
||||||
"Quest requirement": "quest",
|
|
||||||
"Restriction": "restrict",
|
|
||||||
//"Base Neutral Damage": "nDam",
|
|
||||||
//"Base Fire Damage": "fDam",
|
|
||||||
//"Base Water Damage": "wDam",
|
|
||||||
//"Base Air Damage": "aDam",
|
|
||||||
//"Base Thunder Damage": "tDam",
|
|
||||||
//"Base Earth Damage": "eDam",
|
|
||||||
//"Base Attack Speed": "atkSpd",
|
|
||||||
"Health": "hp",
|
|
||||||
"Raw Fire Defense": "fDef",
|
|
||||||
"Raw Water Defense": "wDef",
|
|
||||||
"Raw Air Defense": "aDef",
|
|
||||||
"Raw Thunder Defense": "tDef",
|
|
||||||
"Raw Earth Defense": "eDef",
|
|
||||||
"Combat Level": "lvl",
|
|
||||||
//"Class Requirement": "classReq",
|
|
||||||
"Req Strength": "strReq",
|
|
||||||
"Req Dexterity": "dexReq",
|
|
||||||
"Req Intelligence": "intReq",
|
|
||||||
"Req Agility": "agiReq",
|
|
||||||
"Req Defense": "defReq",
|
|
||||||
"% Health Regen": "hprPct",
|
|
||||||
"Mana Regen": "mr",
|
|
||||||
"% Spell Damage": "sdPct",
|
|
||||||
"% Melee Damage": "mdPct",
|
|
||||||
"Life Steal": "ls",
|
|
||||||
"Mana Steal": "ms",
|
|
||||||
"XP Bonus": "xpb",
|
|
||||||
"Loot Bonus": "lb",
|
|
||||||
"Reflection": "ref",
|
|
||||||
"Strength": "str",
|
|
||||||
"Dexterity": "dex",
|
|
||||||
"Intelligence": "int",
|
|
||||||
"Agility": "agi",
|
|
||||||
"Defense": "def",
|
|
||||||
"Thorns": "thorns",
|
|
||||||
"Exploding": "expd",
|
|
||||||
"Walk Speed": "spd",
|
|
||||||
"Attack Speed Bonus": "atkTier",
|
|
||||||
"Poison": "poison",
|
|
||||||
"Health Bonus": "hpBonus",
|
|
||||||
"Soul Point Regen": "spRegen",
|
|
||||||
"Stealing": "eSteal",
|
|
||||||
"Raw Health Regen": "hprRaw",
|
|
||||||
"Raw Spell": "sdRaw",
|
|
||||||
"Raw Melee": "mdRaw",
|
|
||||||
"% Fire Damage": "fDamPct",
|
|
||||||
"% Water Damage": "wDamPct",
|
|
||||||
"% Air Damage": "aDamPct",
|
|
||||||
"% Thunder Damage": "tDamPct",
|
|
||||||
"% Earth Damage": "eDamPct",
|
|
||||||
"% Fire Defense": "fDefPct",
|
|
||||||
"% Water Defense": "wDefPct",
|
|
||||||
"% Air Defense": "aDefPct",
|
|
||||||
"% Thunder Defense": "tDefPct",
|
|
||||||
"% Earth Defense": "eDefPct",
|
|
||||||
"Fixed IDs": "fixID",
|
|
||||||
"Custom Skin": "skin",
|
|
||||||
//"Item Category": "category",
|
|
||||||
|
|
||||||
"1st Spell Cost %": "spPct1",
|
|
||||||
"1st Spell Cost Raw": "spRaw1",
|
|
||||||
"2nd Spell Cost %": "spPct2",
|
|
||||||
"2nd Spell Cost Raw": "spRaw2",
|
|
||||||
"3rd Spell Cost %": "spPct3",
|
|
||||||
"3rd Spell Cost Raw": "spRaw3",
|
|
||||||
"4th Spell Cost %": "spPct4",
|
|
||||||
"4th Spell Cost Raw": "spRaw4",
|
|
||||||
|
|
||||||
"Rainbow Spell Damage": "rainbowRaw",
|
|
||||||
"Sprint": "sprint",
|
|
||||||
"Sprint Regen": "sprintReg",
|
|
||||||
"Jump Height": "jh",
|
|
||||||
"Loot Quality": "lq",
|
|
||||||
|
|
||||||
"Gather XP Bonus": "gXp",
|
|
||||||
"Gather Speed Bonus": "gSpd",
|
|
||||||
};
|
|
||||||
|
|
||||||
const sq2_special_mappings = {
|
|
||||||
"Sum (skill points)": new SumQuery(["str", "dex", "int", "def", "agi"]),
|
|
||||||
"Sum (Mana Sustain)": new SumQuery(["mr", "ms"]),
|
|
||||||
"Sum (Life Sustain)": new SumQuery(["hpr", "ls"]),
|
|
||||||
"Sum (Health + Health Bonus)": new SumQuery(["hp", "hpBonus"]),
|
|
||||||
"No Strength Req": new NegateQuery("strReq"),
|
|
||||||
"No Dexterity Req": new NegateQuery("dexReq"),
|
|
||||||
"No Intelligence Req": new NegateQuery("intReq"),
|
|
||||||
"No Agility Req": new NegateQuery("agiReq"),
|
|
||||||
"No Defense Req": new NegateQuery("defReq"),
|
|
||||||
};
|
|
||||||
|
|
||||||
let sq2ItemFilters = []
|
|
||||||
for (let x in sq2_translate_mappings) {
|
|
||||||
sq2ItemFilters.push(x);
|
|
||||||
}
|
|
||||||
for (let x in sq2_special_mappings) {
|
|
||||||
sq2ItemFilters.push(x);
|
|
||||||
}
|
|
||||||
|
|
||||||
function applyQuery(items, query) {
|
|
||||||
return items.filter(query.filter, query).sort(query.compare);
|
|
||||||
}
|
|
||||||
|
|
||||||
function displayItems(items_copy) {
|
|
||||||
let items_parent = document.getElementById("search-results");
|
|
||||||
for (let i in items_copy) {
|
|
||||||
if (i > 200) {break;}
|
|
||||||
let item = items_copy[i];
|
|
||||||
let box = document.createElement("div");
|
|
||||||
box.classList.add("col-lg-3", "col-sm-6", "p-2");
|
|
||||||
box.id = "item"+i;
|
|
||||||
box.addEventListener("dblclick", function() {set_item(item);});
|
|
||||||
|
|
||||||
let bckgrdbox = document.createElement("div");
|
|
||||||
bckgrdbox.classList.add("dark-7", "rounded", "px-2", "col-auto");
|
|
||||||
box.appendChild(bckgrdbox);
|
|
||||||
bckgrdbox.id = "item"+i+"b";
|
|
||||||
items_parent.appendChild(box);
|
|
||||||
item.set("powders", []);
|
|
||||||
if (item.get("category") == "weapon") {
|
|
||||||
apply_weapon_powders(item);
|
|
||||||
}
|
|
||||||
displayExpandedItem(item, bckgrdbox.id, true);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
let items_expanded;
|
|
||||||
|
|
||||||
function doItemSearch() {
|
|
||||||
// window.scrollTo(0, 0);
|
|
||||||
let queries = [];
|
|
||||||
queries.push(new NameQuery(document.getElementById("item-name-choice").value.trim()));
|
|
||||||
|
|
||||||
let categoryOrType = document.getElementById("item-category-choice").value;
|
|
||||||
if (itemTypes.includes(categoryOrType)) {
|
|
||||||
queries.push(new IdMatchQuery("type", categoryOrType));
|
|
||||||
}
|
|
||||||
else if (itemCategories.includes(categoryOrType)) {
|
|
||||||
queries.push(new IdMatchQuery("category", categoryOrType));
|
|
||||||
}
|
|
||||||
|
|
||||||
let rarity = document.getElementById("item-rarity-choice").value;
|
|
||||||
if (rarity) {
|
|
||||||
if (rarity === "ANY") {
|
|
||||||
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
queries.push(new IdMatchQuery("tier", rarity));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
let level_dat = document.getElementById("item-level-choice").value ? document.getElementById("item-level-choice").value.split("-") : [1, 106];
|
|
||||||
queries.push(new LevelRangeQuery(parseInt(level_dat[0]), parseInt(level_dat[1])));
|
|
||||||
|
|
||||||
for (let i = 1; i <= 4; ++i) {
|
|
||||||
let raw_dat = document.getElementById("filter"+i+"-choice").value;
|
|
||||||
let filter_dat = sq2_translate_mappings[raw_dat];
|
|
||||||
if (filter_dat !== undefined) {
|
|
||||||
queries.push(new IdQuery(filter_dat));
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
filter_dat = sq2_special_mappings[raw_dat];
|
|
||||||
if (filter_dat !== undefined) {
|
|
||||||
queries.push(filter_dat);
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
let items_copy = items_expanded.slice();
|
|
||||||
document.getElementById("search-results").textContent = "";
|
|
||||||
for (const query of queries) {
|
|
||||||
console.log(items_copy.length);
|
|
||||||
console.log(query, query.filter);
|
|
||||||
items_copy = applyQuery(items_copy, query);
|
|
||||||
console.log(items_copy.length);
|
|
||||||
}
|
|
||||||
document.getElementById("summary").textContent = items_copy.length + " results:"
|
|
||||||
displayItems(items_copy);
|
|
||||||
}
|
|
||||||
|
|
||||||
function resetItemSearch() {
|
|
||||||
resetFields = ["item-name-choice", "item-category-choice", "item-rarity-choice", "item-level-choice", "filter1-choice", "filter2-choice", "filter3-choice", "filter4-choice"]
|
|
||||||
for (const field of resetFields) {
|
|
||||||
document.getElementById(field).value = "";
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
function init_items() {
|
|
||||||
items_expanded = items.filter( (i) => !("remapID" in i) ).map( (i) => expandItem(i) );
|
|
||||||
|
|
||||||
//init dropdowns
|
|
||||||
let filterInputs = new Map([["item-category", ["ALL", "armor", "helmet", "chestplate", "leggings", "boots", "accessory", "ring", "bracelet", "necklace", "weapon", "wand", "spear", "bow", "dagger", "relik"]],
|
|
||||||
["item-rarity", ["ANY", "Normal", "Unique", "Set", "Rare", "Legendary", "Fabled", "Mythic", "Sane"]],
|
|
||||||
["filter1", sq2ItemFilters],
|
|
||||||
["filter2", sq2ItemFilters],
|
|
||||||
["filter3", sq2ItemFilters],
|
|
||||||
["filter4", sq2ItemFilters]]);
|
|
||||||
for (const [field, data] of filterInputs) {
|
|
||||||
let field_choice = document.getElementById(field+"-choice");
|
|
||||||
// show dropdown on click
|
|
||||||
field_choice.onclick = function() {field_choice.dispatchEvent(new Event('input', {bubbles:true}));};
|
|
||||||
filterInputs.set(field, new autoComplete({
|
|
||||||
data: {
|
|
||||||
src: data,
|
|
||||||
},
|
|
||||||
threshold: 0,
|
|
||||||
selector: "#"+ field +"-choice",
|
|
||||||
wrapper: false,
|
|
||||||
resultsList: {
|
|
||||||
maxResults: 100,
|
|
||||||
tabSelect: true,
|
|
||||||
noResults: true,
|
|
||||||
class: "search-box dark-7 rounded-bottom px-2 fw-bold dark-shadow-sm",
|
|
||||||
element: (list, data) => {
|
|
||||||
let position = document.getElementById(field+'-choice').getBoundingClientRect();
|
|
||||||
list.style.top = position.bottom + window.scrollY +"px";
|
|
||||||
list.style.left = position.x+"px";
|
|
||||||
list.style.width = position.width+"px";
|
|
||||||
list.style.maxHeight = position.height * 4 +"px";
|
|
||||||
|
|
||||||
if (!data.results.length) {
|
|
||||||
message = document.createElement('li');
|
|
||||||
message.classList.add('scaled-font');
|
|
||||||
message.textContent = "No results found!";
|
|
||||||
list.prepend(message);
|
|
||||||
};
|
|
||||||
},
|
|
||||||
},
|
|
||||||
resultItem: {
|
|
||||||
class: "scaled-font search-item",
|
|
||||||
selected: "dark-5",
|
|
||||||
},
|
|
||||||
events: {
|
|
||||||
input: {
|
|
||||||
selection: (event) => {
|
|
||||||
if (event.detail.selection.value) {
|
|
||||||
event.target.value = event.detail.selection.value;
|
|
||||||
};
|
|
||||||
},
|
|
||||||
},
|
|
||||||
}
|
|
||||||
}));
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
(async function() {
|
|
||||||
await Promise.resolve(load_init());
|
|
||||||
init_items();
|
|
||||||
})();
|
|
66
js/utils.js
|
@ -1,6 +1,14 @@
|
||||||
let getUrl = window.location;
|
let getUrl = window.location;
|
||||||
const url_base = getUrl.protocol + "//" + getUrl.host + "/" + getUrl.pathname.split('/')[1];
|
const url_base = getUrl.protocol + "//" + getUrl.host + "/" + getUrl.pathname.split('/')[1];
|
||||||
|
|
||||||
|
// huge regex :doom:
|
||||||
|
// replace with navigator.userAgentData.mobile once it has wider support
|
||||||
|
const isMobile = function() {
|
||||||
|
let check = false;
|
||||||
|
(function(a){if(/(android|bb\d+|meego).+mobile|avantgo|bada\/|blackberry|blazer|compal|elaine|fennec|hiptop|iemobile|ip(hone|od)|iris|kindle|lge |maemo|midp|mmp|mobile.+firefox|netfront|opera m(ob|in)i|palm( os)?|phone|p(ixi|re)\/|plucker|pocket|psp|series(4|6)0|symbian|treo|up\.(browser|link)|vodafone|wap|windows ce|xda|xiino/i.test(a)||/1207|6310|6590|3gso|4thp|50[1-6]i|770s|802s|a wa|abac|ac(er|oo|s\-)|ai(ko|rn)|al(av|ca|co)|amoi|an(ex|ny|yw)|aptu|ar(ch|go)|as(te|us)|attw|au(di|\-m|r |s )|avan|be(ck|ll|nq)|bi(lb|rd)|bl(ac|az)|br(e|v)w|bumb|bw\-(n|u)|c55\/|capi|ccwa|cdm\-|cell|chtm|cldc|cmd\-|co(mp|nd)|craw|da(it|ll|ng)|dbte|dc\-s|devi|dica|dmob|do(c|p)o|ds(12|\-d)|el(49|ai)|em(l2|ul)|er(ic|k0)|esl8|ez([4-7]0|os|wa|ze)|fetc|fly(\-|_)|g1 u|g560|gene|gf\-5|g\-mo|go(\.w|od)|gr(ad|un)|haie|hcit|hd\-(m|p|t)|hei\-|hi(pt|ta)|hp( i|ip)|hs\-c|ht(c(\-| |_|a|g|p|s|t)|tp)|hu(aw|tc)|i\-(20|go|ma)|i230|iac( |\-|\/)|ibro|idea|ig01|ikom|im1k|inno|ipaq|iris|ja(t|v)a|jbro|jemu|jigs|kddi|keji|kgt( |\/)|klon|kpt |kwc\-|kyo(c|k)|le(no|xi)|lg( g|\/(k|l|u)|50|54|\-[a-w])|libw|lynx|m1\-w|m3ga|m50\/|ma(te|ui|xo)|mc(01|21|ca)|m\-cr|me(rc|ri)|mi(o8|oa|ts)|mmef|mo(01|02|bi|de|do|t(\-| |o|v)|zz)|mt(50|p1|v )|mwbp|mywa|n10[0-2]|n20[2-3]|n30(0|2)|n50(0|2|5)|n7(0(0|1)|10)|ne((c|m)\-|on|tf|wf|wg|wt)|nok(6|i)|nzph|o2im|op(ti|wv)|oran|owg1|p800|pan(a|d|t)|pdxg|pg(13|\-([1-8]|c))|phil|pire|pl(ay|uc)|pn\-2|po(ck|rt|se)|prox|psio|pt\-g|qa\-a|qc(07|12|21|32|60|\-[2-7]|i\-)|qtek|r380|r600|raks|rim9|ro(ve|zo)|s55\/|sa(ge|ma|mm|ms|ny|va)|sc(01|h\-|oo|p\-)|sdk\/|se(c(\-|0|1)|47|mc|nd|ri)|sgh\-|shar|sie(\-|m)|sk\-0|sl(45|id)|sm(al|ar|b3|it|t5)|so(ft|ny)|sp(01|h\-|v\-|v )|sy(01|mb)|t2(18|50)|t6(00|10|18)|ta(gt|lk)|tcl\-|tdg\-|tel(i|m)|tim\-|t\-mo|to(pl|sh)|ts(70|m\-|m3|m5)|tx\-9|up(\.b|g1|si)|utst|v400|v750|veri|vi(rg|te)|vk(40|5[0-3]|\-v)|vm40|voda|vulc|vx(52|53|60|61|70|80|81|83|85|98)|w3c(\-| )|webc|whit|wi(g |nc|nw)|wmlb|wonu|x700|yas\-|your|zeto|zte\-/i.test(a.substr(0,4))) check = true;})(navigator.userAgent||navigator.vendor||window.opera);
|
||||||
|
return check;
|
||||||
|
}(); // runs immediately, so mobileCheck is a boolean not a function
|
||||||
|
|
||||||
const zip2 = (a, b) => a.map((k, i) => [k, b[i]]);
|
const zip2 = (a, b) => a.map((k, i) => [k, b[i]]);
|
||||||
const zip3 = (a, b, c) => a.map((k, i) => [k, b[i], c[i]]);
|
const zip3 = (a, b, c) => a.map((k, i) => [k, b[i], c[i]]);
|
||||||
|
|
||||||
|
@ -632,16 +640,6 @@ function matchType(object, target) {
|
||||||
return object;
|
return object;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Add multiple classes to a html element
|
|
||||||
*/
|
|
||||||
function addClasses(elem, classes) {
|
|
||||||
for (let _class of classes) {
|
|
||||||
elem.classList.add(_class);
|
|
||||||
}
|
|
||||||
return elem;
|
|
||||||
}
|
|
||||||
|
|
||||||
/** A utility function that reloads the page forcefully.
|
/** A utility function that reloads the page forcefully.
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
|
@ -926,6 +924,17 @@ function make_elem(type, classlist = [], args = {}) {
|
||||||
const ret_elem = document.createElement(type);
|
const ret_elem = document.createElement(type);
|
||||||
ret_elem.classList.add(...classlist);
|
ret_elem.classList.add(...classlist);
|
||||||
for (const i in args) {
|
for (const i in args) {
|
||||||
|
if (i === 'style') {
|
||||||
|
const style_obj = args[i];
|
||||||
|
if (typeof style_obj === 'string' || style_obj instanceof String) {
|
||||||
|
ret_elem.style = style_obj;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
for (const k in style_obj) {
|
||||||
|
ret_elem.style[k] = style_obj[k];
|
||||||
|
}
|
||||||
|
continue;
|
||||||
|
}
|
||||||
ret_elem[i] = args[i];
|
ret_elem[i] = args[i];
|
||||||
}
|
}
|
||||||
return ret_elem;
|
return ret_elem;
|
||||||
|
@ -994,3 +1003,40 @@ function make_SCC_graph(root_node, nodes) {
|
||||||
}
|
}
|
||||||
return sccs;
|
return sccs;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// Toggles display of a certain element, given the ID.
|
||||||
|
function toggle_tab(tab) {
|
||||||
|
let elem = document.getElementById(tab);
|
||||||
|
if (elem.style.display == "none") {
|
||||||
|
elem.style.display = "";
|
||||||
|
} else {
|
||||||
|
elem.style.display = "none";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Toggle display of a certain tab, in a group of tabs, given the target tab ID, and a list of associated tabs.
|
||||||
|
// Also sets visual display of an element with ID of target + "-btn" to selected.
|
||||||
|
function show_tab(target, tabs) {
|
||||||
|
//hide all tabs, then show the tab of the div clicked and highlight the correct button
|
||||||
|
for (const i in tabs) {
|
||||||
|
document.getElementById(tabs[i]).style.display = "none";
|
||||||
|
document.getElementById(tabs[i] + "-btn").classList.remove("selected-btn");
|
||||||
|
}
|
||||||
|
document.getElementById(target).style.display = "";
|
||||||
|
document.getElementById(target + "-btn").classList.add("selected-btn");
|
||||||
|
}
|
||||||
|
|
||||||
|
// mobile navbar appearance control
|
||||||
|
let scrollPos = 0
|
||||||
|
if (screen.width < 992) {
|
||||||
|
document.addEventListener('scroll', (e) => {
|
||||||
|
if (document.documentElement.scrollTop - scrollPos > 20) {
|
||||||
|
document.getElementById("mobile-navbar").style.display = "none";
|
||||||
|
document.getElementById("mobile-navbar-dropdown").style.display = "none";
|
||||||
|
} else if (document.documentElement.scrollTop - scrollPos < -50 || scrollPos < 70) {
|
||||||
|
document.getElementById("mobile-navbar").style.display = "";
|
||||||
|
}
|
||||||
|
scrollPos = document.documentElement.scrollTop;
|
||||||
|
});
|
||||||
|
}
|
|
@ -45,8 +45,51 @@
|
||||||
<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 id="mobile-navbar" class="navbar dark-5 dark-shadow fixed-top d-lg-none pb-0">
|
||||||
|
<div class="container-fluid scaled-font justify-content-center" style="height: 5vh;">
|
||||||
|
<div class="navbar-brand mx-auto scaled-font" style="height: 100%;">
|
||||||
|
<img src="../media/icons/new/compass.png" alt="" style="height: 100%;">
|
||||||
|
<span>WynnGPS</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 row py-5 vh-100 mx-0 mx-lg-auto scaled-font">
|
<div class = "container row py-5 vh-100 mx-0 mx-lg-auto scaled-font mt-lg-2" style="margin-top: 6vh;">
|
||||||
<div id = "mapdiv" class = "col-lg-8 col-sm-12 rounded border border-light border-3">
|
<div id = "mapdiv" class = "col-lg-8 col-sm-12 rounded border border-light border-3">
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
|
|
Before Width: | Height: | Size: 182 B |
Before Width: | Height: | Size: 1.5 KiB |
Before Width: | Height: | Size: 183 B |
Before Width: | Height: | Size: 1.5 KiB |
Before Width: | Height: | Size: 178 B |
Before Width: | Height: | Size: 1.5 KiB |
Before Width: | Height: | Size: 202 B |
Before Width: | Height: | Size: 1.6 KiB |
Before Width: | Height: | Size: 1.6 KiB |
Before Width: | Height: | Size: 1.6 KiB |
Before Width: | Height: | Size: 1.6 KiB |
Before Width: | Height: | Size: 184 B |
Before Width: | Height: | Size: 1.5 KiB |
Before Width: | Height: | Size: 177 B |
Before Width: | Height: | Size: 1.5 KiB |
Before Width: | Height: | Size: 202 B |
Before Width: | Height: | Size: 1.6 KiB |
Before Width: | Height: | Size: 1.6 KiB |
Before Width: | Height: | Size: 1.6 KiB |
Before Width: | Height: | Size: 1.6 KiB |
Before Width: | Height: | Size: 184 B |
Before Width: | Height: | Size: 1.6 KiB |
Before Width: | Height: | Size: 205 B |
Before Width: | Height: | Size: 1.6 KiB |
Before Width: | Height: | Size: 1.6 KiB |
Before Width: | Height: | Size: 1.6 KiB |
Before Width: | Height: | Size: 1.6 KiB |
Before Width: | Height: | Size: 203 B |
Before Width: | Height: | Size: 1.6 KiB |
Before Width: | Height: | Size: 1.6 KiB |
Before Width: | Height: | Size: 1.6 KiB |
Before Width: | Height: | Size: 1.6 KiB |
Before Width: | Height: | Size: 221 B |
Before Width: | Height: | Size: 1.6 KiB |
Before Width: | Height: | Size: 1.6 KiB |
Before Width: | Height: | Size: 1.6 KiB |
Before Width: | Height: | Size: 1.6 KiB |