merge conflict
17
README.md
|
@ -1,7 +1,7 @@
|
|||
# WynnBuilder
|
||||
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
|
||||
|
||||
|
@ -14,6 +14,9 @@ Takes a build's items as input and returns all relevant information
|
|||
- Skillpoints required & left over
|
||||
- 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
|
||||
- Spell boosts, such as Vanish and War Scream
|
||||
- Powder special buffs
|
||||
|
@ -22,12 +25,18 @@ Boosts and Powder specials
|
|||
and more...
|
||||
|
||||
### WynnCrafter
|
||||
|
||||
![wynncrafter screenshot](https://user-images.githubusercontent.com/110062564/192048366-5112d334-f44b-4853-b337-4184628e505e.PNG)
|
||||
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
|
||||
|
||||
|
|
230
builder/doc.html
|
@ -36,20 +36,71 @@
|
|||
<hr/>
|
||||
<a href = "https://discord.gg/CGavnAnerv" target = "_blank"><img src = "../media/icons/discord.png" alt = "WB Discord" title = "WB Discord"><b>WB Discord</b></a>
|
||||
</div>
|
||||
<div class="container-fluid me-4" style="max-width: 95%; display: none">
|
||||
<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. -->
|
||||
<div class = "row scaled-font mx-auto" id = "discord-banner-dev">
|
||||
<div class = "col text-center item-title">Join the <a class = "link" href = "https://discord.gg/CGavnAnerv" target = "_blank">discord</a> today to suggest new features, submit bug reports, and hangout/talk to devs!</div>
|
||||
</div>
|
||||
<div class="row h-100 gx-lg-5 gy-3 mx-2 mx-lg-3 py-3">
|
||||
<div class="row h-100 gx-lg-5 gy-3 mx-2 mx-lg-3 py-3 gx-0">
|
||||
<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="row row-cols-1 row-cols-xl-2 rounded gy-4 gx-5 justify-content-center">
|
||||
<div class="col-auto rounded order-xl-0 order-0">
|
||||
<div class="row h-100 dark-shadow dark-6 rounded" id="helmet-dropdown">
|
||||
<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>
|
||||
<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">
|
||||
<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 class="col-3">
|
||||
<div class="row row-cols-1 h-100 align-items-center">
|
||||
|
@ -73,10 +124,10 @@
|
|||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-auto order-xl-0 order-1">
|
||||
<div class="row h-100 dark-shadow dark-6 rounded" id="ring1-dropdown">
|
||||
<div class="col order-xl-0 order-1 my-0">
|
||||
<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">
|
||||
<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 class="col-3">
|
||||
<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"/>
|
||||
</div>
|
||||
<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 class="col-auto order-xl-0 order-0">
|
||||
<div class="row h-100 dark-shadow dark-6 rounded" id="chestplate-dropdown">
|
||||
<div class="col order-xl-0 order-0">
|
||||
<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">
|
||||
<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 class="col-3">
|
||||
<div class="row row-cols-1 h-100 align-items-center">
|
||||
|
@ -127,10 +177,10 @@
|
|||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-auto order-xl-0 order-1">
|
||||
<div class="row h-100 dark-shadow dark-6 rounded" id="ring2-dropdown">
|
||||
<div class="col order-xl-0 order-1">
|
||||
<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">
|
||||
<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 class="col-3">
|
||||
<div class="row row-cols-1 h-100 align-items-center">
|
||||
|
@ -153,10 +203,10 @@
|
|||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-auto order-xl-0 order-0">
|
||||
<div class="row h-100 dark-shadow dark-6 rounded" id="leggings-dropdown">
|
||||
<div class="col order-xl-0 order-0">
|
||||
<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">
|
||||
<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 class="col-3">
|
||||
<div class="row row-cols-1 h-100 align-items-center">
|
||||
|
@ -180,10 +230,10 @@
|
|||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-auto order-xl-0 order-1">
|
||||
<div class="row h-100 dark-shadow dark-6 rounded" id="bracelet-dropdown">
|
||||
<div class="col order-xl-0 order-1">
|
||||
<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">
|
||||
<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 class="col-3">
|
||||
<div class="row row-cols-1 h-100 align-items-center">
|
||||
|
@ -207,10 +257,10 @@
|
|||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-auto order-xl-0 order-0">
|
||||
<div class="row h-100 dark-shadow dark-6 rounded" id="boots-dropdown">
|
||||
<div class="col order-xl-0 order-0">
|
||||
<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">
|
||||
<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 class="col-3">
|
||||
<div class="row row-cols-1 h-100 align-items-center">
|
||||
|
@ -234,10 +284,10 @@
|
|||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-auto order-xl-0 order-1">
|
||||
<div class="row h-100 dark-shadow dark-6 rounded" id="necklace-dropdown">
|
||||
<div class="col order-xl-0 order-1">
|
||||
<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">
|
||||
<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 class="col-3">
|
||||
<div class="row row-cols-1 h-100 align-items-center">
|
||||
|
@ -260,10 +310,10 @@
|
|||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-auto order-xl-0 order-1">
|
||||
<div class="row h-100 dark-shadow dark-6 rounded" id='weapon-dropdown'>
|
||||
<div class="col order-xl-0 order-1">
|
||||
<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">
|
||||
<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 class="col-3">
|
||||
<div class="row row-cols-1 h-100 align-items-center">
|
||||
|
@ -287,29 +337,25 @@
|
|||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-auto order-xl-0 order-1">
|
||||
<div class="row h-100 dark-shadow dark-6 rounded">
|
||||
<div class="col order-xl-0 order-1 level-input">
|
||||
<div class="row h-100 px-1">
|
||||
<div class="col">
|
||||
<div class="row align-items-center">
|
||||
<div class="col-3 text-nowrap fw-bold scaled-font">
|
||||
<div class="row align-items-center justify-content-left">
|
||||
<div class="col-auto text-nowrap fw-bold scaled-font">
|
||||
Level:
|
||||
</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"/>
|
||||
</div>
|
||||
<div class="col-auto px-1 text-nowrap scaled-font">
|
||||
<button class="button 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 class="col-auto px-1 scaled-font">
|
||||
<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-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>
|
||||
|
@ -390,12 +436,9 @@
|
|||
</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 class="col text-center">
|
||||
<div class="col text-center py-1">
|
||||
<div id="summary-box"></div>
|
||||
<div id="err-box"></div>
|
||||
<div id="stack-box"></div>
|
||||
|
@ -407,8 +450,6 @@
|
|||
</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="row row-cols-1 justify-content-center">
|
||||
|
@ -416,8 +457,8 @@
|
|||
Active boosts
|
||||
</div>
|
||||
<div class="col">
|
||||
<button class="button-boost m-1 border-0 text-white dark-8u dark-shadow-sm" id="vanish-boost" onclick="update_boosts('vanish-boost')">
|
||||
Vanish (+80%)
|
||||
<button class="button-boost m-1 border-0 text-white dark-8u dark-shadow-sm" id="radiance-boost" onclick="update_radiance()">
|
||||
Radiance
|
||||
</button>
|
||||
<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
|
||||
|
@ -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')">
|
||||
Ragnarokkr (+30%)
|
||||
</button>
|
||||
<button class="button-boost m-1 border-0 text-white dark-8u dark-shadow-sm" id="yourtotem-boost" onclick="update_boosts('yourtotem-boost')">
|
||||
Your Totem (+35%)
|
||||
</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 class="button-boost m-1 border-0 text-white dark-8u dark-shadow-sm" id="totem-boost" onclick="update_boosts('totem-boost')">
|
||||
Vengeful Spirit (+20%)
|
||||
</button>
|
||||
<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%)
|
||||
|
@ -446,19 +484,19 @@
|
|||
<div class="col mb-1">
|
||||
<div class="row row-cols-1 rounded text-center dark-5 scaled-font">
|
||||
<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
|
||||
</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
|
||||
</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
|
||||
</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
|
||||
</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
|
||||
</div>
|
||||
</div>
|
||||
|
@ -589,6 +627,10 @@
|
|||
</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="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">
|
||||
|
@ -620,7 +662,7 @@
|
|||
<div class="col-auto rounded">
|
||||
<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">
|
||||
<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 class="col-3">
|
||||
<div class="row row-cols-1 h-100 align-items-center">
|
||||
|
@ -644,7 +686,7 @@
|
|||
<div class="col-auto rounded">
|
||||
<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">
|
||||
<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 class="col-3">
|
||||
<div class="row row-cols-1 h-100 align-items-center">
|
||||
|
@ -668,7 +710,7 @@
|
|||
<div class="col-auto rounded">
|
||||
<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">
|
||||
<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 class="col-3">
|
||||
<div class="row row-cols-1 h-100 align-items-center">
|
||||
|
@ -692,7 +734,7 @@
|
|||
<div class="col-auto rounded">
|
||||
<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">
|
||||
<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 class="col-3">
|
||||
<div class="row row-cols-1 h-100 align-items-center">
|
||||
|
@ -716,7 +758,7 @@
|
|||
<div class="col-auto rounded">
|
||||
<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">
|
||||
<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 class="col-3">
|
||||
<div class="row row-cols-1 h-100 align-items-center">
|
||||
|
@ -740,7 +782,7 @@
|
|||
<div class="col-auto rounded">
|
||||
<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">
|
||||
<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 class="col-3">
|
||||
<div class="row row-cols-1 h-100 align-items-center">
|
||||
|
@ -764,7 +806,7 @@
|
|||
<div class="col-auto rounded">
|
||||
<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">
|
||||
<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 class="col-3">
|
||||
<div class="row row-cols-1 h-100 align-items-center">
|
||||
|
@ -789,12 +831,14 @@
|
|||
</div>
|
||||
<div class = "col dark-6 rounded-bottom my-3 my-xl-1" id = "atree-dropdown" style = "display:none;">
|
||||
<div class="row row-cols-1 row-cols-xl-2">
|
||||
<div class="col border border-semi-light rounded dark-9 hide-scroll" id="atree-ui" style="height: 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 class="col mx-auto" style="height: 90vh; overflow-y: auto;" id="atree-rhs">
|
||||
<div class="col mx-auto" style="height: 2em; overflow-y: auto;" id="atree-header">
|
||||
</div>
|
||||
<div class="col mx-auto" style="" id="atree-warning">
|
||||
</div>
|
||||
<div class="col mx-auto" style="overflow-y: auto;" id="atree-active">
|
||||
</div>
|
||||
</div>
|
||||
|
@ -1131,24 +1175,20 @@
|
|||
</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="col rounded-top">
|
||||
<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')">
|
||||
Offense
|
||||
<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'])">
|
||||
Detailed
|
||||
</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')">
|
||||
Defense
|
||||
</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 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'])">
|
||||
Summary
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div style="display: none;" id="offensive-stats" class="col text-nowrap"></div>
|
||||
<div style="display: none;" id="defensive-stats" class="col text-nowrap"></div>
|
||||
<div id="overall-stats" class="col text-nowrap"></div>
|
||||
<div style="display: none;" id="detailed-stats" class="col text-nowrap"></div>
|
||||
<div id="summary-stats" class="col text-nowrap"></div>
|
||||
</div>
|
||||
</div>
|
||||
<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/build_utils.js"></script>
|
||||
<script type="text/javascript" src="../js/computation_graph.js"></script>
|
||||
<script type="text/javascript">COMPUTE_GRAPH_DEBUG=true;</script>
|
||||
<!-- <script type="text/javascript" src="../js/icons.js"></script> -->
|
||||
<script type="text/javascript" src="../js/sq2icons.js"></script>
|
||||
<script type="text/javascript">COMPUTE_GRAPH_DEBUG=true</script>
|
||||
<script type="text/javascript" src="../js/icons.js"></script>
|
||||
<script type="text/javascript" src="../js/powders.js"></script>
|
||||
<script type="text/javascript" src="../js/skillpoints.js"></script>
|
||||
<script type="text/javascript" src="../js/damage_calc.js"></script>
|
||||
<script type="text/javascript" src="../js/atree_constants_min.js"></script>
|
||||
<script type="text/javascript" src="../js/display_constants.js"></script>
|
||||
<script type="text/javascript" src="../js/display.js"></script>
|
||||
<script type="text/javascript" src="../js/load.js"></script>
|
||||
|
@ -1276,13 +1314,13 @@
|
|||
<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/craft.js"></script>
|
||||
<script type="text/javascript" src="../js/build.js"></script>
|
||||
<script type="text/javascript" src="../js/build_constants.js"></script>
|
||||
<script type="text/javascript" src="../js/build_encode_decode.js"></script>
|
||||
<script type="text/javascript" src="../js/atree.js"></script>
|
||||
<script type="text/javascript" src="../js/builder.js"></script>
|
||||
<script type="text/javascript" src="../js/builder_graph.js"></script>
|
||||
<script type="text/javascript" src="../js/optimize.js"></script>
|
||||
<script type="text/javascript" src="../js/builder/atree_constants_min.js"></script>
|
||||
<script type="text/javascript" src="../js/builder/build.js"></script>
|
||||
<script type="text/javascript" src="../js/builder/builder_constants.js"></script>
|
||||
<script type="text/javascript" src="../js/builder/build_encode_decode.js"></script>
|
||||
<script type="text/javascript" src="../js/builder/atree.js"></script>
|
||||
<script type="text/javascript" src="../js/builder/builder.js"></script>
|
||||
<script type="text/javascript" src="../js/builder/builder_graph.js"></script>
|
||||
|
||||
<div id="graph_body" style="max-width: 100%; height: 100vh">
|
||||
<button id="saveButton">JANKY Export SVG</button>
|
||||
|
|
|
@ -36,20 +36,71 @@
|
|||
<hr/>
|
||||
<a href = "https://discord.gg/CGavnAnerv" target = "_blank"><img src = "../media/icons/discord.png" alt = "WB Discord" title = "WB Discord"><b>WB Discord</b></a>
|
||||
</div>
|
||||
<div class="container-fluid me-4" style="max-width: 95%;">
|
||||
<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. -->
|
||||
<div class = "row scaled-font mx-auto" id = "discord-banner-dev">
|
||||
<div class = "col text-center item-title">Join the <a class = "link" href = "https://discord.gg/CGavnAnerv" target = "_blank">discord</a> today to suggest new features, submit bug reports, and hangout/talk to devs!</div>
|
||||
</div>
|
||||
<div class="row h-100 gx-lg-5 gy-3 mx-2 mx-lg-3 py-3">
|
||||
<div class="row h-100 gx-lg-5 gy-3 mx-2 mx-lg-3 py-3 gx-0">
|
||||
<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="row row-cols-1 row-cols-xl-2 rounded gy-4 gx-5 justify-content-center">
|
||||
<div class="col-auto rounded order-xl-0 order-0">
|
||||
<div class="row h-100 dark-shadow dark-6 rounded" id="helmet-dropdown">
|
||||
<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>
|
||||
<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">
|
||||
<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 class="col-3">
|
||||
<div class="row row-cols-1 h-100 align-items-center">
|
||||
|
@ -73,10 +124,10 @@
|
|||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-auto order-xl-0 order-1">
|
||||
<div class="row h-100 dark-shadow dark-6 rounded" id="ring1-dropdown">
|
||||
<div class="col order-xl-0 order-1 my-0">
|
||||
<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">
|
||||
<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 class="col-3">
|
||||
<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"/>
|
||||
</div>
|
||||
<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 class="col-auto order-xl-0 order-0">
|
||||
<div class="row h-100 dark-shadow dark-6 rounded" id="chestplate-dropdown">
|
||||
<div class="col order-xl-0 order-0">
|
||||
<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">
|
||||
<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 class="col-3">
|
||||
<div class="row row-cols-1 h-100 align-items-center">
|
||||
|
@ -127,10 +177,10 @@
|
|||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-auto order-xl-0 order-1">
|
||||
<div class="row h-100 dark-shadow dark-6 rounded" id="ring2-dropdown">
|
||||
<div class="col order-xl-0 order-1">
|
||||
<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">
|
||||
<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 class="col-3">
|
||||
<div class="row row-cols-1 h-100 align-items-center">
|
||||
|
@ -153,10 +203,10 @@
|
|||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-auto order-xl-0 order-0">
|
||||
<div class="row h-100 dark-shadow dark-6 rounded" id="leggings-dropdown">
|
||||
<div class="col order-xl-0 order-0">
|
||||
<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">
|
||||
<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 class="col-3">
|
||||
<div class="row row-cols-1 h-100 align-items-center">
|
||||
|
@ -180,10 +230,10 @@
|
|||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-auto order-xl-0 order-1">
|
||||
<div class="row h-100 dark-shadow dark-6 rounded" id="bracelet-dropdown">
|
||||
<div class="col order-xl-0 order-1">
|
||||
<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">
|
||||
<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 class="col-3">
|
||||
<div class="row row-cols-1 h-100 align-items-center">
|
||||
|
@ -207,10 +257,10 @@
|
|||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-auto order-xl-0 order-0">
|
||||
<div class="row h-100 dark-shadow dark-6 rounded" id="boots-dropdown">
|
||||
<div class="col order-xl-0 order-0">
|
||||
<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">
|
||||
<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 class="col-3">
|
||||
<div class="row row-cols-1 h-100 align-items-center">
|
||||
|
@ -234,10 +284,10 @@
|
|||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-auto order-xl-0 order-1">
|
||||
<div class="row h-100 dark-shadow dark-6 rounded" id="necklace-dropdown">
|
||||
<div class="col order-xl-0 order-1">
|
||||
<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">
|
||||
<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 class="col-3">
|
||||
<div class="row row-cols-1 h-100 align-items-center">
|
||||
|
@ -260,10 +310,10 @@
|
|||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-auto order-xl-0 order-1">
|
||||
<div class="row h-100 dark-shadow dark-6 rounded" id='weapon-dropdown'>
|
||||
<div class="col order-xl-0 order-1">
|
||||
<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">
|
||||
<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 class="col-3">
|
||||
<div class="row row-cols-1 h-100 align-items-center">
|
||||
|
@ -287,29 +337,25 @@
|
|||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-auto order-xl-0 order-1">
|
||||
<div class="row h-100 dark-shadow dark-6 rounded">
|
||||
<div class="col order-xl-0 order-1 level-input">
|
||||
<div class="row h-100 px-1">
|
||||
<div class="col">
|
||||
<div class="row align-items-center">
|
||||
<div class="col-3 text-nowrap fw-bold scaled-font">
|
||||
<div class="row align-items-center justify-content-left">
|
||||
<div class="col-auto text-nowrap fw-bold scaled-font">
|
||||
Level:
|
||||
</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"/>
|
||||
</div>
|
||||
<div class="col-auto px-1 text-nowrap scaled-font">
|
||||
<button class="button 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 class="col-auto px-1 scaled-font">
|
||||
<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-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>
|
||||
|
@ -390,12 +436,9 @@
|
|||
</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 class="col text-center">
|
||||
<div class="col text-center py-1">
|
||||
<div id="summary-box"></div>
|
||||
<div id="err-box"></div>
|
||||
<div id="stack-box"></div>
|
||||
|
@ -407,8 +450,6 @@
|
|||
</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="row row-cols-1 justify-content-center">
|
||||
|
@ -416,8 +457,8 @@
|
|||
Active boosts
|
||||
</div>
|
||||
<div class="col">
|
||||
<button class="button-boost m-1 border-0 text-white dark-8u dark-shadow-sm" id="vanish-boost" onclick="update_boosts('vanish-boost')">
|
||||
Vanish (+80%)
|
||||
<button class="button-boost m-1 border-0 text-white dark-8u dark-shadow-sm" id="radiance-boost" onclick="update_radiance()">
|
||||
Radiance
|
||||
</button>
|
||||
<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
|
||||
|
@ -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')">
|
||||
Ragnarokkr (+30%)
|
||||
</button>
|
||||
<button class="button-boost m-1 border-0 text-white dark-8u dark-shadow-sm" id="yourtotem-boost" onclick="update_boosts('yourtotem-boost')">
|
||||
Your Totem (+35%)
|
||||
</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 class="button-boost m-1 border-0 text-white dark-8u dark-shadow-sm" id="totem-boost" onclick="update_boosts('totem-boost')">
|
||||
Vengeful Spirit (+20%)
|
||||
</button>
|
||||
<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%)
|
||||
|
@ -446,19 +484,19 @@
|
|||
<div class="col mb-1">
|
||||
<div class="row row-cols-1 rounded text-center dark-5 scaled-font">
|
||||
<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
|
||||
</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
|
||||
</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
|
||||
</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
|
||||
</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
|
||||
</div>
|
||||
</div>
|
||||
|
@ -468,19 +506,19 @@
|
|||
</div>
|
||||
<div class="col skp-tooltip dark-6 rounded-bottom my-3 my-xl-1" >
|
||||
<button class = "button-boost m-1 border-0 text-white dark-8u dark-shadow-sm" id = "Quake-1" onclick = "updatePowderSpecials('Quake-1')">
|
||||
Lv.4 [e4e4]
|
||||
Lv.1
|
||||
</button>
|
||||
<button class = "button-boost m-1 border-0 text-white dark-8u dark-shadow-sm" id = "Quake-2" onclick = "updatePowderSpecials('Quake-2')">
|
||||
Lv.4.5 [e5e4]
|
||||
Lv.2
|
||||
</button>
|
||||
<button class = "button-boost m-1 border-0 text-white dark-8u dark-shadow-sm" id = "Quake-3" onclick = "updatePowderSpecials('Quake-3')">
|
||||
Lv.5 [e5e5]
|
||||
Lv.3
|
||||
</button>
|
||||
<button class = "button-boost m-1 border-0 text-white dark-8u dark-shadow-sm" id = "Quake-4" onclick = "updatePowderSpecials('Quake-4')">
|
||||
Lv.5.5 [e6e5]
|
||||
Lv.4
|
||||
</button>
|
||||
<button class = "button-boost m-1 border-0 text-white dark-8u dark-shadow-sm" id = "Quake-5" onclick = "updatePowderSpecials('Quake-5')">
|
||||
Lv.6 [e6e6]
|
||||
Lv.5
|
||||
</button>
|
||||
</div>
|
||||
<div class="col eDam">
|
||||
|
@ -493,19 +531,19 @@
|
|||
</div>
|
||||
<div class="col skp-tooltip dark-6 rounded-bottom my-3 my-xl-1">
|
||||
<button class = "button-boost m-1 border-0 text-white dark-8u dark-shadow-sm" id = "Chain_Lightning-1" onclick = "updatePowderSpecials('Chain_Lightning-1')">
|
||||
Lv.4 [t4t4]
|
||||
Lv.1
|
||||
</button>
|
||||
<button class = "button-boost m-1 border-0 text-white dark-8u dark-shadow-sm" id = "Chain_Lightning-2" onclick = "updatePowderSpecials('Chain_Lightning-2')">
|
||||
Lv.4.5 [t5t4]
|
||||
Lv.2
|
||||
</button>
|
||||
<button class = "button-boost m-1 border-0 text-white dark-8u dark-shadow-sm" id = "Chain_Lightning-3" onclick = "updatePowderSpecials('Chain_Lightning-3')">
|
||||
Lv.5 [t5t5]
|
||||
Lv.3
|
||||
</button>
|
||||
<button class = "button-boost m-1 border-0 text-white dark-8u dark-shadow-sm" id = "Chain_Lightning-4" onclick = "updatePowderSpecials('Chain_Lightning-4')">
|
||||
Lv.5.5 [t6t5]
|
||||
Lv.4
|
||||
</button>
|
||||
<button class = "button-boost m-1 border-0 text-white dark-8u dark-shadow-sm" id = "Chain_Lightning-5" onclick = "updatePowderSpecials('Chain_Lightning-5')">
|
||||
Lv.6 [t6t6]
|
||||
Lv.5
|
||||
</button>
|
||||
</div>
|
||||
<div class="col tDam">
|
||||
|
@ -518,19 +556,19 @@
|
|||
</div>
|
||||
<div class="col skp-tooltip dark-6 rounded-bottom my-3 my-xl-1">
|
||||
<button class = "button-boost m-1 border-0 text-white dark-8u dark-shadow-sm" id = "Curse-1" onclick = "updatePowderSpecials('Curse-1')">
|
||||
Lv.4 [w4w4]
|
||||
Lv.1
|
||||
</button>
|
||||
<button class = "button-boost m-1 border-0 text-white dark-8u dark-shadow-sm" id = "Curse-2" onclick = "updatePowderSpecials('Curse-2')">
|
||||
Lv.4.5 [w5w4]
|
||||
Lv.2
|
||||
</button>
|
||||
<button class = "button-boost m-1 border-0 text-white dark-8u dark-shadow-sm" id = "Curse-3" onclick = "updatePowderSpecials('Curse-3')">
|
||||
Lv.5 [w5w5]
|
||||
Lv.3
|
||||
</button>
|
||||
<button class = "button-boost m-1 border-0 text-white dark-8u dark-shadow-sm" id = "Curse-4" onclick = "updatePowderSpecials('Curse-4')">
|
||||
Lv.5.5 [w6w5]
|
||||
Lv.4
|
||||
</button>
|
||||
<button class = "button-boost m-1 border-0 text-white dark-8u dark-shadow-sm" id = "Curse-5" onclick = "updatePowderSpecials('Curse-5')">
|
||||
Lv.6 [w6w6]
|
||||
Lv.5
|
||||
</button>
|
||||
</div>
|
||||
<div class="col wDam">
|
||||
|
@ -543,19 +581,19 @@
|
|||
</div>
|
||||
<div class="col skp-tooltip dark-6 rounded-bottom my-3 my-xl-1">
|
||||
<button class = "button-boost m-1 border-0 text-white dark-8u dark-shadow-sm" id = "Courage-1" onclick = "updatePowderSpecials('Courage-1')">
|
||||
Lv.4 [f4f4]
|
||||
Lv.1
|
||||
</button>
|
||||
<button class = "button-boost m-1 border-0 text-white dark-8u dark-shadow-sm" id = "Courage-2" onclick = "updatePowderSpecials('Courage-2')">
|
||||
Lv.4.5 [f5f4]
|
||||
Lv.2
|
||||
</button>
|
||||
<button class = "button-boost m-1 border-0 text-white dark-8u dark-shadow-sm" id = "Courage-3" onclick = "updatePowderSpecials('Courage-3')">
|
||||
Lv.5 [f5f5]
|
||||
Lv.3
|
||||
</button>
|
||||
<button class = "button-boost m-1 border-0 text-white dark-8u dark-shadow-sm" id = "Courage-4" onclick = "updatePowderSpecials('Courage-4')">
|
||||
Lv.5.5 [f6f5]
|
||||
Lv.4
|
||||
</button>
|
||||
<button class = "button-boost m-1 border-0 text-white dark-8u dark-shadow-sm" id = "Courage-5" onclick = "updatePowderSpecials('Courage-5')">
|
||||
Lv.6 [f6f6]
|
||||
Lv.5
|
||||
</button>
|
||||
</div>
|
||||
<div class="col fDam">
|
||||
|
@ -568,19 +606,19 @@
|
|||
</div>
|
||||
<div class="col skp-tooltip dark-6 rounded-bottom my-3 my-xl-1">
|
||||
<button class = "button-boost m-1 border-0 text-white dark-8u dark-shadow-sm" id = "Wind_Prison-1" onclick = "updatePowderSpecials('Wind_Prison-1')">
|
||||
Lv.4 [a4a4]
|
||||
Lv.1
|
||||
</button>
|
||||
<button class = "button-boost m-1 border-0 text-white dark-8u dark-shadow-sm" id = "Wind_Prison-2" onclick = "updatePowderSpecials('Wind_Prison-2')">
|
||||
Lv.4.5 [a5a4]
|
||||
Lv.2
|
||||
</button>
|
||||
<button class = "button-boost m-1 border-0 text-white dark-8u dark-shadow-sm" id = "Wind_Prison-3" onclick = "updatePowderSpecials('Wind_Prison-3')">
|
||||
Lv.5 [a5a5]
|
||||
Lv.3
|
||||
</button>
|
||||
<button class = "button-boost m-1 border-0 text-white dark-8u dark-shadow-sm" id = "Wind_Prison-4" onclick = "updatePowderSpecials('Wind_Prison-4')">
|
||||
Lv.5.5 [a6a5]
|
||||
Lv.4
|
||||
</button>
|
||||
<button class = "button-boost m-1 border-0 text-white dark-8u dark-shadow-sm" id = "Wind_Prison-5" onclick = "updatePowderSpecials('Wind_Prison-5')">
|
||||
Lv.6 [a6a6]
|
||||
Lv.5
|
||||
</button>
|
||||
</div>
|
||||
<div class="col aDam">
|
||||
|
@ -589,6 +627,10 @@
|
|||
</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="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">
|
||||
|
@ -620,7 +662,7 @@
|
|||
<div class="col-auto rounded">
|
||||
<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">
|
||||
<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 class="col-3">
|
||||
<div class="row row-cols-1 h-100 align-items-center">
|
||||
|
@ -644,7 +686,7 @@
|
|||
<div class="col-auto rounded">
|
||||
<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">
|
||||
<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 class="col-3">
|
||||
<div class="row row-cols-1 h-100 align-items-center">
|
||||
|
@ -668,7 +710,7 @@
|
|||
<div class="col-auto rounded">
|
||||
<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">
|
||||
<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 class="col-3">
|
||||
<div class="row row-cols-1 h-100 align-items-center">
|
||||
|
@ -692,7 +734,7 @@
|
|||
<div class="col-auto rounded">
|
||||
<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">
|
||||
<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 class="col-3">
|
||||
<div class="row row-cols-1 h-100 align-items-center">
|
||||
|
@ -716,7 +758,7 @@
|
|||
<div class="col-auto rounded">
|
||||
<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">
|
||||
<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 class="col-3">
|
||||
<div class="row row-cols-1 h-100 align-items-center">
|
||||
|
@ -740,7 +782,7 @@
|
|||
<div class="col-auto rounded">
|
||||
<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">
|
||||
<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 class="col-3">
|
||||
<div class="row row-cols-1 h-100 align-items-center">
|
||||
|
@ -764,7 +806,7 @@
|
|||
<div class="col-auto rounded">
|
||||
<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">
|
||||
<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 class="col-3">
|
||||
<div class="row row-cols-1 h-100 align-items-center">
|
||||
|
@ -789,12 +831,14 @@
|
|||
</div>
|
||||
<div class = "col dark-6 rounded-bottom my-3 my-xl-1" id = "atree-dropdown" style = "display:none;">
|
||||
<div class="row row-cols-1 row-cols-xl-2">
|
||||
<div class="col border border-semi-light rounded dark-9 hide-scroll" id="atree-ui" style="height: 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 class="col mx-auto" style="height: 90vh; overflow-y: auto;" id="atree-rhs">
|
||||
<div class="col mx-auto" style="height: 2em; overflow-y: auto;" id="atree-header">
|
||||
</div>
|
||||
<div class="col mx-auto" style="" id="atree-warning">
|
||||
</div>
|
||||
<div class="col mx-auto" style="overflow-y: auto;" id="atree-active">
|
||||
</div>
|
||||
</div>
|
||||
|
@ -1131,24 +1175,20 @@
|
|||
</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="col rounded-top">
|
||||
<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')">
|
||||
Offense
|
||||
<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'])">
|
||||
Detailed
|
||||
</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')">
|
||||
Defense
|
||||
</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 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'])">
|
||||
Summary
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div style="display: none;" id="offensive-stats" class="col text-nowrap"></div>
|
||||
<div style="display: none;" id="defensive-stats" class="col text-nowrap"></div>
|
||||
<div id="overall-stats" class="col text-nowrap"></div>
|
||||
<div style="display: none;" id="detailed-stats" class="col text-nowrap"></div>
|
||||
<div id="summary-stats" class="col text-nowrap"></div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-xl-3 mb-3 px-0">
|
||||
|
@ -1195,7 +1235,7 @@
|
|||
<div class="col-12 dark-5 scaled-font">
|
||||
<footer class="text-center">
|
||||
<div id="header2">
|
||||
<p>Made by <b class = "hppeng">hppeng</b>, <b class = "ferricles">ferricles</b>, and <b>reschan</b> with <a href = "../atlas" target = "_blank" class = "atlas link">Atlas Inc</a> (JavaScript required to function, nothing works without js)</p>
|
||||
<p>Made by <b class = "hppeng">hppeng</b>, <b class = "ferricles">ferricles</b>, <b>reschan</b>, and <b>blankman</b> with <a href = "../atlas" target = "_blank" class = "atlas link">Atlas Inc</a> (JavaScript required to function, nothing works without js)</p>
|
||||
<p>Hard refresh the page (Ctrl+Shift+R on windows/chrome) if it isn't updating correctly.</p>
|
||||
</div>
|
||||
<div id="credits">
|
||||
|
@ -1262,11 +1302,10 @@
|
|||
<script type="text/javascript" src="../js/utils.js"></script>
|
||||
<script type="text/javascript" src="../js/build_utils.js"></script>
|
||||
<script type="text/javascript" src="../js/computation_graph.js"></script>
|
||||
<script type="text/javascript" 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/skillpoints.js"></script>
|
||||
<script type="text/javascript" src="../js/damage_calc.js"></script>
|
||||
<script type="text/javascript" src="../js/atree_constants_min.js"></script>
|
||||
<script type="text/javascript" src="../js/display_constants.js"></script>
|
||||
<script type="text/javascript" src="../js/display.js"></script>
|
||||
<script type="text/javascript" src="../js/load.js"></script>
|
||||
|
@ -1274,13 +1313,12 @@
|
|||
<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/craft.js"></script>
|
||||
<script type="text/javascript" src="../js/build.js"></script>
|
||||
<script type="text/javascript" src="../js/build_constants.js"></script>
|
||||
<script type="text/javascript" src="../js/build_encode_decode.js"></script>
|
||||
<script type="text/javascript" src="../js/atree.js"></script>
|
||||
<script type="text/javascript" src="../js/builder.js"></script>
|
||||
<script type="text/javascript" src="../js/builder_graph.js"></script>
|
||||
<script type="text/javascript" src="../js/optimize.js"></script>
|
||||
|
||||
<script type="text/javascript" src="../js/builder/build.js"></script>
|
||||
<script type="text/javascript" src="../js/builder/builder_constants.js"></script>
|
||||
<script type="text/javascript" src="../js/builder/build_encode_decode.js"></script>
|
||||
<script type="text/javascript" src="../js/builder/atree.js"></script>
|
||||
<script type="text/javascript" src="../js/builder/builder_graph.js"></script>
|
||||
<script type="text/javascript" src="../js/builder/builder.js"></script>
|
||||
<!--script type="text/javascript" src="../js/builder/optimize.js"></script-->
|
||||
</body>
|
||||
</html>
|
||||
|
|
1001
builder2.html
74202
clean.json
|
@ -31,7 +31,50 @@
|
|||
<hr/>
|
||||
<a href = "https://discord.gg/CGavnAnerv" target = "_blank"><img src = "../media/icons/discord.png" alt = "WB Discord" title = "WB Discord"><b>WB Discord</b></a>
|
||||
</div>
|
||||
<div class="container 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="col col-lg-5">
|
||||
<!--crafter ui-->
|
||||
|
@ -39,7 +82,7 @@
|
|||
<div class="col" id="recipe-dropdown">
|
||||
<div class="row dark-shadow dark-5 rounded">
|
||||
<div id = "recipe-img-loc" class = "col-auto px-lg-1 g-0 dark-7 rounded-end my-auto text-center scaled-item-icon">
|
||||
<img id = "recipe-img" class = "img-fluid rounded Crafted-shadow" src = "../media/items/new/generic-potion.png">
|
||||
<div 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 class = "col ps-3">
|
||||
<div class = "row row-cols-2 align-items-center">
|
||||
|
@ -279,11 +322,9 @@
|
|||
</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/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/skillpoints.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/craft.js"></script>
|
||||
<script type="text/javascript" src="../js/crafter.js"></script>
|
||||
<script type="text/javascript" src="../js/expr_parser.js"></script>
|
||||
</body>
|
||||
</html>
|
||||
|
|
121
css/items.css
|
@ -1,32 +1,105 @@
|
|||
.searchbox {
|
||||
grid-column: 1;
|
||||
padding: 0%;
|
||||
display: grid;
|
||||
grid-template-columns: repeat(4, 1fr);
|
||||
width: 100%;
|
||||
gap: 5px;
|
||||
/* type selectors */
|
||||
|
||||
#type-box {
|
||||
cursor: pointer;
|
||||
overflow: auto;
|
||||
}
|
||||
#type-box > div {
|
||||
display: inline-block;
|
||||
width: calc(100% / 12);
|
||||
float: left;
|
||||
}
|
||||
|
||||
.items {
|
||||
grid-column: 1;
|
||||
padding: 0%;
|
||||
display: grid;
|
||||
grid-template-columns: repeat(auto-fit, minmax(250px, 1fr));
|
||||
width: 100%;
|
||||
gap: 5px;
|
||||
grid-template-rows: masonry;
|
||||
.type-selected {
|
||||
background-color: #0a0;
|
||||
}
|
||||
|
||||
.itemsearch {
|
||||
padding: 0%;
|
||||
display: grid;
|
||||
grid-template-columns: 1fr;
|
||||
width: 100%;
|
||||
gap: 5px;
|
||||
/* rarity selectors */
|
||||
|
||||
#rarity-box {
|
||||
cursor: pointer;
|
||||
width: 58.33%;
|
||||
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 {
|
||||
width: 100%;
|
||||
max-width: 200px;
|
||||
#rarity-normal { color: #FFFFFF; }
|
||||
#rarity-normal.rarity-selected { background-color: #FFFFFF; }
|
||||
#rarity-unique { color: #FFFF55; }
|
||||
#rarity-unique.rarity-selected { background-color: #FFFF55; }
|
||||
#rarity-set { color: #55FF55; }
|
||||
#rarity-set.rarity-selected { background-color: #55FF55; }
|
||||
#rarity-rare { color: #FF55FF; }
|
||||
#rarity-rare.rarity-selected { background-color: #FF55FF; }
|
||||
#rarity-legendary { color: #55FFFF; }
|
||||
#rarity-legendary.rarity-selected { background-color: #55FFFF; }
|
||||
#rarity-fabled { color: #FF5555; }
|
||||
#rarity-fabled.rarity-selected { background-color: #FF5555; }
|
||||
#rarity-mythic { color: #AA00AA; }
|
||||
#rarity-mythic.rarity-selected { background-color: #AA00AA; }
|
||||
|
||||
/* 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 */
|
||||
|
||||
|
||||
.slider {
|
||||
-webkit-appearance: none;
|
||||
background: #AAAAAA;
|
||||
|
@ -46,7 +45,6 @@ input[type=range]:focus {
|
|||
outline: none; /* Removes the border. */
|
||||
}
|
||||
|
||||
|
||||
/* equipment field specifics */
|
||||
/* inputs and dropdowns */
|
||||
.form-control {
|
||||
|
@ -63,6 +61,7 @@ ul.search-box {
|
|||
position: absolute;
|
||||
padding: 0;
|
||||
overflow: auto;
|
||||
z-index: 10;
|
||||
}
|
||||
|
||||
li.search-item {
|
||||
|
@ -102,10 +101,15 @@ input.equipment-input {
|
|||
font-weight: bold;
|
||||
background-color: hsl(0, 0%, 21%) !important;
|
||||
border-radius: 0.375rem !important;
|
||||
border-color: rgba(33, 37, 41, 1) !important;
|
||||
min-height: calc(1.2 * var(--scaled-fontsize) + 2px);
|
||||
padding: 0rem 0.5rem;
|
||||
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 {
|
||||
|
@ -174,11 +178,11 @@ input.equipment-input {
|
|||
}
|
||||
|
||||
.scaled-item-icon {
|
||||
width: 8rem;
|
||||
width: 6rem;
|
||||
}
|
||||
|
||||
.scaled-item-icon img {
|
||||
width: 6.5rem;
|
||||
width: 6rem;
|
||||
}
|
||||
|
||||
.scaled-bckgrd {
|
||||
|
@ -187,15 +191,19 @@ input.equipment-input {
|
|||
}
|
||||
|
||||
.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 {
|
||||
--scaled-fontsize: 1rem;
|
||||
--scaled-fontsize: max(1rem, 16px);
|
||||
}
|
||||
.scaled-font {
|
||||
font-size: 1rem;
|
||||
font-size: max(1rem, 16px);
|
||||
}
|
||||
|
||||
.box-title {
|
||||
|
@ -211,7 +219,7 @@ input.equipment-input {
|
|||
}
|
||||
|
||||
.skp-tooltip {
|
||||
font-size: .625rem;
|
||||
font-size: 1rem;
|
||||
}
|
||||
|
||||
.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) {
|
||||
: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;
|
||||
}
|
||||
|
@ -273,11 +357,11 @@ input.equipment-input {
|
|||
}
|
||||
|
||||
.scaled-item-icon {
|
||||
width: 4rem;
|
||||
width: 3.2rem;
|
||||
}
|
||||
|
||||
.scaled-item-icon img {
|
||||
width: 3.5rem;
|
||||
width: 2.7rem;
|
||||
}
|
||||
|
||||
.scaled-bckgrd {
|
||||
|
@ -289,7 +373,6 @@ input.equipment-input {
|
|||
width: 3.5rem;
|
||||
}
|
||||
|
||||
|
||||
.warning {
|
||||
font-size: .8rem;
|
||||
}
|
||||
|
@ -460,3 +543,16 @@ a:hover {
|
|||
.ferricles{
|
||||
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/>
|
||||
<a href = "https://discord.gg/CGavnAnerv" target = "_blank"><img src = "../media/icons/discord.png" alt = "WB Discord" title = "WB Discord"><b>WB Discord</b></a>
|
||||
</div>
|
||||
<div class = "container 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 px-1">
|
||||
<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>
|
||||
<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>
|
||||
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">
|
||||
<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>
|
||||
<div class = "row section" title = "Example 1: With Tomes">
|
||||
<code class="full-width">
|
||||
|
@ -959,7 +1030,7 @@
|
|||
</div> -->
|
||||
</div>
|
||||
<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>
|
||||
|
||||
</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/display_constants.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>
|
||||
</body>
|
||||
</html>
|
||||
|
|
172
items/index.html
|
@ -18,6 +18,7 @@
|
|||
<link rel="stylesheet" href="../css/sq2bs.css">
|
||||
<link rel="stylesheet" href="../css/sidebar.css">
|
||||
<link rel="stylesheet" href="../css/wynnstyles.css">
|
||||
<link rel="stylesheet" href="../css/items.css">
|
||||
</head>
|
||||
<body class = "text-light d-flex justify-content-center" id = "body">
|
||||
<div id="main-sidebar" class="sidebar dark-7 dark-shadow">
|
||||
|
@ -31,101 +32,128 @@
|
|||
<hr/>
|
||||
<a href = "https://discord.gg/CGavnAnerv" target = "_blank"><img src = "../media/icons/discord.png" alt = "WB Discord" title = "WB Discord"><b>WB Discord</b></a>
|
||||
</div>
|
||||
<div 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 = "col">
|
||||
<div class = "row">
|
||||
<div class = "row" style = "margin-top: 3ch;">
|
||||
<div class = "col text-end">
|
||||
<a href = "../items_adv/">Advanced Item Search</a>
|
||||
</div>
|
||||
</div>
|
||||
<div class = "col-auto" style = "width: 12.5%;"></div>
|
||||
<div class = "col-lg-4">
|
||||
<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">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)"/>
|
||||
<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"/>
|
||||
<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-auto"></p>
|
||||
</div>
|
||||
</div>
|
||||
<div class = "row">
|
||||
<div class = "col-lg-3 col-sm-12">
|
||||
<div class = "col fw-bold">Filter 1:</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 class = "col-lg col-sm-12">
|
||||
<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>
|
||||
<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>
|
||||
</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 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">
|
||||
<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!
|
||||
</button>
|
||||
</div>
|
||||
<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
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class = "row box-title justify-content-center" id = "summary">
|
||||
</div>
|
||||
<div class = "row" id = "search-results">
|
||||
|
@ -134,6 +162,7 @@
|
|||
</div>
|
||||
</div>
|
||||
<script src="https://cdn.jsdelivr.net/npm/@tarekraafat/autocomplete.js@10.2.6/dist/autoComplete.min.js"></script>
|
||||
<script type="text/javascript" src="../js/drag_drop_touch.js"></script>
|
||||
<script type="text/javascript" src="../js/utils.js"></script>
|
||||
<script type="text/javascript" src="../js/build_utils.js"></script>
|
||||
<script type="text/javascript" src="../js/icons.js"></script>
|
||||
|
@ -141,10 +170,9 @@
|
|||
<script type="text/javascript" src="../js/display_constants.js"></script>
|
||||
<script type="text/javascript" src="../js/display.js"></script>
|
||||
<script type="text/javascript" src="../js/query.js"></script>
|
||||
<script type="text/javascript" src="../js/query_2.js"></script>
|
||||
<script type="text/javascript" src="../js/expr_parser.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>
|
||||
</body>
|
||||
</html>
|
||||
|
|
|
@ -16,7 +16,7 @@
|
|||
|
||||
|
||||
<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/wynnstyles.css">
|
||||
</head>
|
||||
|
@ -39,7 +39,7 @@
|
|||
<a href="../credits.txt" class="link">Additional credits</a>
|
||||
</div>
|
||||
<div class = "col text-center" id = "help">
|
||||
<a href="items_2_help.html" class="link" target="_blank">Search Guide</a>
|
||||
<a href="items_adv_help.html" class="link" target="_blank">Search Guide</a>
|
||||
</div>
|
||||
<div class = "col text-end">
|
||||
<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/build_utils.js"></script>
|
||||
<script type="text/javascript" src="/js/icons.js"></script>
|
||||
<script type="text/javascript" src="/js/powders.js"></script>
|
||||
<script type="text/javascript" src="/js/damage_calc.js"></script>
|
||||
<script type="text/javascript" src="/js/display_constants.js"></script>
|
||||
<script type="text/javascript" src="/js/display.js"></script>
|
||||
<script type="text/javascript" src="/js/query_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/load.js"></script>
|
||||
<script type="text/javascript" src="/js/items_2.js"></script>
|
||||
<script type="text/javascript" src="/js/items_adv.js"></script>
|
||||
</body>
|
||||
</html>
|
||||
|
|
|
@ -221,6 +221,6 @@
|
|||
docsFns.append(genDocEntry(entry[0], entry[1], null, entry[2]));
|
||||
}
|
||||
</script>
|
||||
<script type="text/javascript" src="../js/sq2icons.js"></script>
|
||||
<script type="text/javascript" src="../js/icons.js"></script>
|
||||
</body>
|
||||
</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.
|
||||
* @param skp - the integer skillpoint count to be converted
|
||||
*/
|
||||
|
@ -8,7 +12,7 @@ function skillPointsToPercentage(skp){
|
|||
skp = 150;
|
||||
}
|
||||
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).toFixed(3);
|
||||
//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));
|
||||
//weaponTypes.push("sword");
|
||||
//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 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
|
||||
/*"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"
|
||||
"critDamPct",
|
||||
"spPct1Final", "spPct2Final", "spPct3Final", "spPct4Final"
|
||||
];
|
||||
// Extra fake IDs (reserved for use in spell damage calculation) : damMult, defMult, poisonPct, activeMajorIDs
|
||||
let str_item_fields = [ "name", "displayName", "lore", "color", "tier", "set", "type", "material", "drop", "quest", "restrict", "category", "atkSpd" ]
|
||||
|
||||
//File reading for ID translations for JSON purposes
|
||||
let reversetranslations = new Map();
|
||||
let translations = new Map([["name", "name"], ["displayName", "displayName"], ["tier", "tier"], ["set", "set"], ["sockets", "slots"], ["type", "type"], ["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)
|
||||
for (const [k, v] of translations) {
|
||||
reversetranslations.set(v, k);
|
||||
|
@ -123,16 +129,7 @@ let nonRolledIDs = [
|
|||
"nDam_", "fDam_", "wDam_", "aDam_", "tDam_", "eDam_",
|
||||
"majorIds",
|
||||
"damMobs",
|
||||
"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).
|
||||
"defMobs"
|
||||
];
|
||||
let rolledIDs = [
|
||||
"hprPct",
|
||||
|
@ -161,7 +158,7 @@ let rolledIDs = [
|
|||
"spPct2", "spRaw2",
|
||||
"spPct3", "spRaw3",
|
||||
"spPct4", "spRaw4",
|
||||
"pDamRaw",
|
||||
"rSdRaw",
|
||||
"sprint",
|
||||
"sprintReg",
|
||||
"jh",
|
||||
|
@ -176,7 +173,8 @@ let rolledIDs = [
|
|||
"aMdPct","aMdRaw","aSdPct","aSdRaw",/*"aDamPct,"*/"aDamRaw","aDamAddMin","aDamAddMax",
|
||||
"nMdPct","nMdRaw","nSdPct","nSdRaw","nDamPct","nDamRaw","nDamAddMin","nDamAddMax", // neutral which is now an element
|
||||
/*"mdPct","mdRaw","sdPct","sdRaw",*/"damPct","damRaw","damAddMin","damAddMax", // These are the old ids. Become proportional.
|
||||
"rMdPct","rMdRaw","rSdPct",/*"rSdRaw",*/"rDamPct","rDamRaw","rDamAddMin","rDamAddMax" // rainbow (the "element" of all minus neutral). rSdRaw is rainraw
|
||||
"rMdPct","rMdRaw","rSdPct",/*"rSdRaw",*/"rDamPct","rDamRaw","rDamAddMin","rDamAddMax", // rainbow (the "element" of all minus neutral). rSdRaw is rainraw
|
||||
"spPct1Final", "spPct2Final", "spPct3Final", "spPct4Final"
|
||||
];
|
||||
let reversedIDs = [ "spPct1", "spRaw1", "spPct2", "spRaw2", "spPct3", "spRaw3", "spPct4", "spRaw4" ];
|
||||
|
||||
|
@ -199,7 +197,7 @@ function expandItem(item) {
|
|||
let val = (item[id] || 0);
|
||||
if (val > 0) { // positive rolled IDs
|
||||
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));
|
||||
} else {
|
||||
maxRolls.set(id,idRound(val*1.3));
|
||||
|
@ -208,7 +206,7 @@ function expandItem(item) {
|
|||
} else if (val < 0) { //negative rolled IDs
|
||||
if (reversedIDs.includes(id)) {
|
||||
maxRolls.set(id,idRound(val*1.3));
|
||||
minRolls.set(id,idRound(val*0.7));
|
||||
minRolls.set(id,idRound(val*0.3));
|
||||
}
|
||||
else {
|
||||
maxRolls.set(id,idRound(val*0.7));
|
||||
|
@ -231,8 +229,15 @@ function expandItem(item) {
|
|||
}
|
||||
|
||||
class Item {
|
||||
constructor(item_obj) {
|
||||
this.statMap = expandItem(item_obj);
|
||||
constructor(item_obj = null) {
|
||||
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.50], ["bow",0.60], ["wand", 0.80], ["dagger", 1.0], ["spear",1.0], ["sword", 1.10]]);
|
||||
const classDefenseMultipliers = new Map([ ["relik",0.60], ["bow",0.70], ["wand", 0.80], ["dagger", 1.0], ["spear", 1.0]]);
|
||||
|
||||
/*
|
||||
* Class that represents a wynn player's build.
|
||||
|
@ -10,16 +15,11 @@ class Build{
|
|||
/**
|
||||
* @description Construct a build.
|
||||
* @param {Number} level : Level of the player.
|
||||
* @param {String[]} equipment : List of equipment names that make up the build.
|
||||
* In order: boots, Chestplate, Leggings, Boots, Ring1, Ring2, Brace, Neck
|
||||
*
|
||||
* @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.
|
||||
* @param {String[]} items: List of equipment names that make up the build.
|
||||
* In order: Helmet, Chestplate, Leggings, Boots, Ring1, Ring2, Brace, Neck, Tomes [x7].
|
||||
* @param {Item} weapon: Weapon that this build is using.
|
||||
*/
|
||||
constructor(level, equipment, tomes, weapon){
|
||||
constructor(level, items, weapon){
|
||||
if (level < 1) { //Should these be constants?
|
||||
this.level = 1;
|
||||
} else if (level > 106) {
|
||||
|
@ -34,15 +34,18 @@ class Build{
|
|||
document.getElementById("level-choice").value = this.level;
|
||||
|
||||
this.availableSkillpoints = levelToSkillPoints(this.level);
|
||||
this.equipment = equipment;
|
||||
this.tomes = tomes;
|
||||
this.equipment = items;
|
||||
this.weapon = weapon;
|
||||
this.items = this.equipment.concat(tomes, [this.weapon]);
|
||||
// return [equip_order, best_skillpoints, final_skillpoints, best_total];
|
||||
this.items = this.equipment.concat([this.weapon]);
|
||||
|
||||
// calc skillpoints requires statmaps only
|
||||
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)
|
||||
this.base_skillpoints = result[1];
|
||||
// How many skillpoints the build ended up with (5 number)
|
||||
|
@ -60,7 +63,6 @@ class Build{
|
|||
return [this.equipment,this.weapon].flat();
|
||||
}
|
||||
|
||||
|
||||
/* 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.
|
||||
*/
|
||||
|
@ -126,9 +128,9 @@ class Build{
|
|||
}
|
||||
}
|
||||
}
|
||||
statMap.set("poisonPct", 100);
|
||||
statMap.set("critDamPct", 100);
|
||||
statMap.set("healPct", 100);
|
||||
statMap.set("poisonPct", 0);
|
||||
statMap.set("critDamPct", 0);
|
||||
statMap.set("healPct", 0);
|
||||
|
||||
// The stuff relevant for damage calculation!!! @ferricles
|
||||
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() {
|
||||
const buildList = document.getElementById("build-choice");
|
||||
|
@ -44,6 +47,8 @@ function loadBuild() {
|
|||
let saveName = document.getElementById("build-name").value;
|
||||
|
||||
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])
|
||||
document.getElementById("loaded-error").textContent = "";
|
||||
document.getElementById("loaded-build").textContent = "Build loaded";
|
||||
|
@ -60,6 +65,9 @@ function resetFields(){
|
|||
for (const i of equipment_inputs) {
|
||||
setValue(i, "");
|
||||
}
|
||||
for (const i of tomeInputs) {
|
||||
setValue(i, "");
|
||||
}
|
||||
setValue("str-skp", "0");
|
||||
setValue("dex-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
|
||||
function init_autocomplete() {
|
||||
|
@ -239,8 +219,9 @@ function init_autocomplete() {
|
|||
for (const eq of tome_keys) {
|
||||
// build dropdown
|
||||
let tome_arr = [];
|
||||
for (const tome of tomeLists.get(eq.replace(/[0-9]/g, ''))) {
|
||||
let tome_obj = tomeMap.get(tome);
|
||||
let tome_aliases = new Map();
|
||||
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") {
|
||||
continue;
|
||||
}
|
||||
|
@ -248,8 +229,10 @@ function init_autocomplete() {
|
|||
if (tome_obj["name"].includes('No ' + eq.charAt(0).toUpperCase())) {
|
||||
continue;
|
||||
}
|
||||
let tome_name = tome;
|
||||
let tome_alias = tome_obj['alias'];
|
||||
tome_arr.push(tome_name);
|
||||
tome_arr.push(tome_alias);
|
||||
tome_aliases.set(tome_alias, tome_name);
|
||||
}
|
||||
|
||||
// create dropdown
|
||||
|
@ -284,14 +267,18 @@ function init_autocomplete() {
|
|||
class: "scaled-font search-item",
|
||||
selected: "dark-5",
|
||||
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: {
|
||||
input: {
|
||||
selection: (event) => {
|
||||
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'));
|
||||
},
|
||||
|
@ -320,9 +307,8 @@ function collapse_element(elmnt) {
|
|||
document.querySelector(elmnt).style.removeProperty('display');
|
||||
}
|
||||
|
||||
function init() {
|
||||
async function init() {
|
||||
console.log("builder.js init");
|
||||
init_autocomplete();
|
||||
|
||||
// Other "main" stuff
|
||||
// Spell dropdowns
|
||||
|
@ -344,6 +330,7 @@ function init() {
|
|||
}
|
||||
|
||||
// Masonry setup
|
||||
try {
|
||||
let masonry = Macy({
|
||||
container: "#masonry-container",
|
||||
columns: 1,
|
||||
|
@ -355,7 +342,6 @@ function init() {
|
|||
x: 20,
|
||||
y: 20,
|
||||
}
|
||||
|
||||
});
|
||||
|
||||
let search_masonry = Macy({
|
||||
|
@ -369,9 +355,16 @@ function init() {
|
|||
x: 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();
|
||||
for (const item_node of item_nodes) {
|
||||
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?')) {
|
||||
hardReload();
|
||||
}
|
||||
console.log(item_node);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
@ -390,7 +384,5 @@ window.onerror = function(message, source, lineno, colno, error) {
|
|||
};
|
||||
|
||||
(async function() {
|
||||
let load_promises = [ load_init(), load_ing_init(), load_tome_init() ];
|
||||
await Promise.all(load_promises);
|
||||
init();
|
||||
await init();
|
||||
})();
|
|
@ -1,3 +1,7 @@
|
|||
/**
|
||||
* File containing compute graph structure of the builder page.
|
||||
*/
|
||||
|
||||
let armor_powder_node = new (class extends ComputeNode {
|
||||
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 {
|
||||
constructor() { super('builder-boost-input'); }
|
||||
|
||||
|
@ -23,8 +29,7 @@ let boosts_node = new (class extends ComputeNode {
|
|||
let elem = document.getElementById(key + "-boost")
|
||||
if (elem.classList.contains("toggleOn")) {
|
||||
damage_boost += value;
|
||||
if (key === "warscream") { def_boost += .10 }
|
||||
if (key === "vanish") { def_boost += .15 }
|
||||
if (key === "warscream") { def_boost += .20 }
|
||||
}
|
||||
}
|
||||
let res = new Map();
|
||||
|
@ -90,12 +95,10 @@ class PowderSpecialCalcNode extends ComputeNode {
|
|||
for (const [special, power] of powder_specials) {
|
||||
if (special["weaponSpecialEffects"].has("Damage Boost")) {
|
||||
let name = special["weaponSpecialName"];
|
||||
if (name === "Courage" || name === "Curse") { //courage and curse are is universal damage boost
|
||||
stats.set("sdPct", special.weaponSpecialEffects.get("Damage Boost")[power-1]);
|
||||
stats.set("mdPct", special.weaponSpecialEffects.get("Damage Boost")[power-1]);
|
||||
if (name === "Courage" || name === "Curse" || name == "Wind Prison") { // Master mod all the way
|
||||
stats.set("damMult."+name, special.weaponSpecialEffects.get("Damage Boost")[power-1]);
|
||||
// legacy
|
||||
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.
|
||||
*
|
||||
* Signature: ItemInputNode(powdering: Optional[list[powder]]) => Item | null
|
||||
* Signature: ItemInputNode() => Item | null
|
||||
*/
|
||||
class ItemInputNode extends InputNode {
|
||||
/**
|
||||
|
@ -143,8 +146,6 @@ class ItemInputNode extends InputNode {
|
|||
}
|
||||
|
||||
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
|
||||
let item_text = this.input_field.value;
|
||||
if (!item_text) {
|
||||
|
@ -158,10 +159,6 @@ class ItemInputNode extends InputNode {
|
|||
else if (tomeMap.has(item_text)) { item = new Item(tomeMap.get(item_text)); }
|
||||
|
||||
if (item) {
|
||||
if (powdering !== undefined) {
|
||||
const max_slots = item.statMap.get('slots');
|
||||
item.statMap.set('powders', powdering.slice(0, max_slots));
|
||||
}
|
||||
let type_match;
|
||||
if (this.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');
|
||||
}
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
@ -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.
|
||||
*
|
||||
|
@ -217,7 +233,6 @@ class ItemInputDisplayNode extends ComputeNode {
|
|||
this.input_field = document.getElementById(eq+"-choice");
|
||||
this.health_field = document.getElementById(eq+"-health");
|
||||
this.level_field = document.getElementById(eq+"-lv");
|
||||
this.powder_field = document.getElementById(eq+"-powder"); // possibly None
|
||||
this.image = item_image;
|
||||
this.fail_cb = true;
|
||||
}
|
||||
|
@ -242,18 +257,11 @@ class ItemInputDisplayNode extends ComputeNode {
|
|||
this.input_field.classList.add("is-invalid");
|
||||
return null;
|
||||
}
|
||||
if (this.powder_field && item.statMap.has('powders')) {
|
||||
this.powder_field.placeholder = "powders";
|
||||
}
|
||||
|
||||
if (item.statMap.has('NONE')) {
|
||||
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');
|
||||
this.input_field.classList.add(tier);
|
||||
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 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);
|
||||
if (isNaN(dps)) {
|
||||
dps = dps[1];
|
||||
|
@ -374,41 +383,39 @@ class URLUpdateNode extends ComputeNode {
|
|||
* Create a "build" object from a set of equipments.
|
||||
* Returns a new Build object, or null if all items are NONE items.
|
||||
*
|
||||
* Signature: BuildAssembleNode(helmet-input: Item,
|
||||
* chestplate-input: Item,
|
||||
* leggings-input: Item,
|
||||
* boots-input: Item,
|
||||
* ring1-input: Item,
|
||||
* ring2-input: Item,
|
||||
* bracelet-input: Item,
|
||||
* necklace-input: Item,
|
||||
* weapon-input: Item,
|
||||
* level-input: int) => Build | null
|
||||
* Signature: BuildAssembleNode(helmet: Item,
|
||||
* chestplate: Item,
|
||||
* leggings: Item,
|
||||
* boots: Item,
|
||||
* ring1: Item,
|
||||
* ring2: Item,
|
||||
* bracelet: Item,
|
||||
* necklace: Item,
|
||||
* weapon: Item,
|
||||
* level: int) => Build | null
|
||||
*/
|
||||
class BuildAssembleNode extends ComputeNode {
|
||||
constructor() { super("builder-make-build"); }
|
||||
|
||||
compute_func(input_map) {
|
||||
let equipments = [
|
||||
input_map.get('helmet-input'),
|
||||
input_map.get('chestplate-input'),
|
||||
input_map.get('leggings-input'),
|
||||
input_map.get('boots-input'),
|
||||
input_map.get('ring1-input'),
|
||||
input_map.get('ring2-input'),
|
||||
input_map.get('bracelet-input'),
|
||||
input_map.get('necklace-input')
|
||||
input_map.get('helmet'),
|
||||
input_map.get('chestplate'),
|
||||
input_map.get('leggings'),
|
||||
input_map.get('boots'),
|
||||
input_map.get('ring1'),
|
||||
input_map.get('ring2'),
|
||||
input_map.get('bracelet'),
|
||||
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 = [
|
||||
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 weapon = input_map.get('weapon');
|
||||
let level = parseInt(input_map.get('level-input'));
|
||||
if (isNaN(level)) {
|
||||
level = 106;
|
||||
|
@ -440,15 +447,25 @@ class PlayerClassNode extends ValueCheckComputeNode {
|
|||
* Read an input field and parse into a list of powderings.
|
||||
* 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 {
|
||||
|
||||
constructor(name, input_field) { super(name, input_field); }
|
||||
constructor(name, input_field) { super(name, input_field); this.fail_cb = true; }
|
||||
|
||||
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
|
||||
// also, error handling is missing
|
||||
let input = this.input_field.value.trim();
|
||||
let powdering = [];
|
||||
let errorederrors = [];
|
||||
|
@ -456,12 +473,29 @@ class PowderInputNode extends InputNode {
|
|||
let first = input.slice(0, 2);
|
||||
let powder = powderIDs.get(first);
|
||||
if (powder === undefined) {
|
||||
return null;
|
||||
if (first.length > 0) {
|
||||
errorederrors.push(first);
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
} else {
|
||||
powdering.push(powder);
|
||||
}
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
@ -566,8 +600,9 @@ class SpellDamageCalcNode extends ComputeNode {
|
|||
// TODO: move preprocessing to separate node/node chain
|
||||
for (const part of spell_parts) {
|
||||
let spell_result;
|
||||
const part_id = spell.base_spell + '.' + part.name
|
||||
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 = {
|
||||
type: "damage",
|
||||
normal_min: results[2].map(x => x[0]),
|
||||
|
@ -579,7 +614,10 @@ class SpellDamageCalcNode extends ComputeNode {
|
|||
}
|
||||
} else if ('power' in part) {
|
||||
// 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 = {
|
||||
type: "heal",
|
||||
heal_amount: _heal_amount
|
||||
|
@ -588,12 +626,14 @@ class SpellDamageCalcNode extends ComputeNode {
|
|||
else {
|
||||
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_result_map.set(part.name, spell_result);
|
||||
spell_result_map.set(name, spell_result);
|
||||
}
|
||||
for (const part of spell_parts) {
|
||||
if ('hits' in part) {
|
||||
if (!('hits' in part)) { continue; }
|
||||
let spell_result = {
|
||||
normal_min: [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.name = part.name;
|
||||
const {name, display = true} = part;
|
||||
spell_result.name = name;
|
||||
spell_result.display = display;
|
||||
spell_results.push(spell_result);
|
||||
spell_result_map.set(part.name, spell_result);
|
||||
}
|
||||
spell_result_map.set(name, spell_result);
|
||||
}
|
||||
return spell_results;
|
||||
}
|
||||
|
@ -674,13 +715,13 @@ class BuildDisplayNode extends ComputeNode {
|
|||
compute_func(input_map) {
|
||||
const build = input_map.get('build');
|
||||
const stats = input_map.get('stats');
|
||||
displayBuildStats('overall-stats', build, build_all_display_commands, stats);
|
||||
displayBuildStats("offensive-stats", build, build_offensive_display_commands, stats);
|
||||
displayBuildStats('summary-stats', build, build_overall_display_commands, stats);
|
||||
displayBuildStats("detailed-stats", build, build_detailed_display_commands, stats);
|
||||
displaySetBonuses("set-info", build);
|
||||
// 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);
|
||||
}
|
||||
}
|
||||
|
@ -705,7 +746,7 @@ class DisplayBuildWarningsNode extends ComputeNode {
|
|||
input_map.get('def'),
|
||||
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;
|
||||
for (let i in skp_order){ //big bren
|
||||
const assigned = skillpoints[i] - base_totals[i] + min_assigned[i]
|
||||
|
@ -727,20 +768,16 @@ class DisplayBuildWarningsNode extends ComputeNode {
|
|||
|
||||
let summarybox = document.getElementById("summary-box");
|
||||
summarybox.textContent = "";
|
||||
let skpRow = document.createElement("p");
|
||||
|
||||
let remainingSkp = document.createElement("p");
|
||||
remainingSkp.classList.add("scaled-font");
|
||||
let remainingSkpTitle = document.createElement("b");
|
||||
remainingSkpTitle.textContent = "Assigned " + total_assigned + " skillpoints. Remaining skillpoints: ";
|
||||
let remainingSkp = make_elem("p", ['scaled-font', 'my-0']);
|
||||
let remainingSkpTitle = make_elem("b", [], { textContent: "Assigned " + total_assigned + " skillpoints. Remaining skillpoints: " });
|
||||
let remainingSkpContent = document.createElement("b");
|
||||
remainingSkpContent.textContent = "" + (levelToSkillPoints(build.level) - total_assigned);
|
||||
remainingSkpContent.classList.add(levelToSkillPoints(build.level) - total_assigned < 0 ? "negative" : "positive");
|
||||
|
||||
remainingSkp.appendChild(remainingSkpTitle);
|
||||
remainingSkp.appendChild(remainingSkpContent);
|
||||
remainingSkp.append(remainingSkpTitle);
|
||||
remainingSkp.append(remainingSkpContent);
|
||||
|
||||
summarybox.append(skpRow);
|
||||
summarybox.append(remainingSkp);
|
||||
if(total_assigned > levelToSkillPoints(build.level)){
|
||||
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.
|
||||
*
|
||||
|
@ -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() {
|
||||
this.mark_dirty();
|
||||
this.update();
|
||||
|
@ -928,9 +1042,11 @@ class SumNumberInputNode extends InputNode {
|
|||
}
|
||||
|
||||
let item_nodes = [];
|
||||
let item_nodes_map = new Map();
|
||||
let powder_nodes = [];
|
||||
let edit_input_nodes = [];
|
||||
let skp_inputs = [];
|
||||
let equip_inputs = [];
|
||||
let build_node;
|
||||
let stat_agg_node;
|
||||
let edit_agg_node;
|
||||
|
@ -939,25 +1055,53 @@ let atree_graph_creator;
|
|||
function builder_graph_init() {
|
||||
// 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).
|
||||
for (const [eq, display_elem, none_item] of zip3(equipment_fields, build_fields, none_items)) {
|
||||
let input_field = document.getElementById(eq+"-choice");
|
||||
let item_image = document.getElementById(eq+"-img");
|
||||
|
||||
let item_input = new ItemInputNode(eq+'-input', input_field, none_item);
|
||||
equip_inputs.push(item_input);
|
||||
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_map.set(eq, item_input);
|
||||
new ItemInputDisplayNode(eq+'-input-display', eq, item_image).link_to(item_input);
|
||||
new ItemDisplayNode(eq+'-item-display', display_elem).link_to(item_input);
|
||||
//new PrintNode(eq+'-debug').link_to(item_input);
|
||||
//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]])) {
|
||||
let input_field = document.getElementById(eq+"-choice");
|
||||
let item_image = document.getElementById(eq+"-img");
|
||||
|
||||
let item_input = new ItemInputNode(eq+'-input', input_field, none_item);
|
||||
equip_inputs.push(item_input);
|
||||
item_nodes.push(item_input);
|
||||
new ItemInputDisplayNode(eq+'-input-display', eq, item_image).link_to(item_input);
|
||||
build_node.link_to(item_input, eq);
|
||||
}
|
||||
|
||||
// weapon image changer node.
|
||||
|
@ -965,38 +1109,12 @@ function builder_graph_init() {
|
|||
let weapon_dps = document.getElementById("weapon-dps");
|
||||
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
|
||||
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();
|
||||
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
|
||||
|
||||
// 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.
|
||||
|
||||
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_merge.link_to(class_node, 'player-class');
|
||||
pre_scale_agg_node.link_to(atree_stats, 'atree-raw-stats');
|
||||
atree_scaling.link_to(pre_scale_agg_node, 'scale-stats');
|
||||
stat_agg_node.link_to(pre_scale_agg_node, 'pre-scaling');
|
||||
stat_agg_node.link_to(atree_scaling, 'atree-scaling');
|
||||
pre_scale_agg_node.link_to(atree_raw_stats, 'atree-raw-stats');
|
||||
radiance_node.link_to(pre_scale_agg_node, 'stats');
|
||||
atree_scaling.link_to(radiance_node, 'scale-stats');
|
||||
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');
|
||||
|
||||
// ---------------------------------------------------------------
|
||||
// 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();
|
||||
}
|
||||
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
|
||||
const atree_state = atree_state_node.value;
|
||||
if (atree_data.length > 0) {
|
||||
try {
|
||||
const active_nodes = decode_atree(atree_node.value, atree_data);
|
||||
for (const node of active_nodes) {
|
||||
atree_set_state(atree_state.get(node.ability.id), true);
|
||||
}
|
||||
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 node_debug_stack = [];
|
||||
let COMPUTE_GRAPH_DEBUG = false;
|
||||
let COMPUTE_GRAPH_DEBUG = true;
|
||||
class ComputeNode {
|
||||
/**
|
||||
* Make a generic compute node.
|
||||
|
@ -15,7 +15,7 @@ class ComputeNode {
|
|||
this.value = null;
|
||||
this.name = name;
|
||||
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:
|
||||
// 2: dirty
|
||||
// 1: possibly dirty
|
||||
|
@ -39,6 +39,13 @@ class ComputeNode {
|
|||
if (this.dirty == 2) {
|
||||
let calc_inputs = new Map();
|
||||
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);
|
||||
}
|
||||
this.value = this.compute_func(calc_inputs);
|
||||
|
@ -213,7 +220,7 @@ class PrintNode extends ComputeNode {
|
|||
*
|
||||
* Signature: InputNode() => str
|
||||
*/
|
||||
class InputNode extends ComputeNode {
|
||||
class InputNode extends ValueCheckComputeNode {
|
||||
constructor(name, input_field) {
|
||||
super(name);
|
||||
this.input_field = input_field;
|
||||
|
|
|
@ -397,4 +397,8 @@ class Craft{
|
|||
statMap.set("crafted", true);
|
||||
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() {
|
||||
//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 {
|
||||
document.getElementById("recipe-choice").addEventListener("change", (event) => {
|
||||
document.getElementById("recipe-choice").addEventListener("input", (event) => {
|
||||
updateMaterials();
|
||||
updateCraftedImage();
|
||||
calculateCraftSchedule();
|
||||
});
|
||||
document.getElementById("recipe-choice").addEventListener("oninput", (event) => {
|
||||
document.getElementById("recipe-choice").addEventListener("input", (event) => {
|
||||
updateCraftedImage();
|
||||
});
|
||||
document.getElementById("level-choice").addEventListener("change", (event) => {
|
||||
document.getElementById("level-choice").addEventListener("input", (event) => {
|
||||
updateMaterials();
|
||||
calculateCraftSchedule();
|
||||
});
|
||||
|
||||
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-2-"+i).setAttribute("onclick", document.getElementById("mat-2-"+i).getAttribute("onclick") + "; calculateCraftSchedule();");
|
||||
document.getElementById("mat-1-"+i).addEventListener("click", (e) => calculateCraftSchedule());
|
||||
document.getElementById("mat-2-"+i).addEventListener("click", (e) => calculateCraftSchedule());
|
||||
}
|
||||
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"]) {
|
||||
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();
|
||||
decodeCraft(ing_url_tag);
|
||||
} catch (error) {
|
||||
|
@ -259,11 +248,9 @@ function populateFields() {
|
|||
ing_list.appendChild(el);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
/*
|
||||
Copies the CR Hash (CR-blahblahblah)
|
||||
* Copies the CR Hash (CR-blahblahblah)
|
||||
*/
|
||||
function copyRecipeHash() {
|
||||
if (player_craft) {
|
||||
|
@ -345,9 +332,16 @@ function toggleMaterial(buttonId) {
|
|||
function updateCraftedImage() {
|
||||
let input = document.getElementById("recipe-choice");
|
||||
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
|
||||
|
|
|
@ -188,7 +188,7 @@ function getCustomFromHash(hash) {
|
|||
|
||||
/** 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 attackSpeeds from build.js.
|
||||
* @dep Requires the use of attackSpeeds from `builder/build.js`.
|
||||
*/
|
||||
class Custom {
|
||||
/**
|
||||
|
@ -336,4 +336,7 @@ class Custom {
|
|||
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() {
|
||||
|
||||
try {
|
||||
populateFields();
|
||||
decodeCustom(custom_url_tag);
|
||||
|
@ -181,7 +180,11 @@ function calculateCustom() {
|
|||
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) {
|
||||
//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))];
|
||||
len = -1;
|
||||
} else if (id === "type") {
|
||||
val = types[Base64.toInt(tag.charAt(2))];
|
||||
val = item_types[Base64.toInt(tag.charAt(2))];
|
||||
len = -1;
|
||||
} else if (id === "atkSpd") {
|
||||
val = attackSpeeds[Base64.toInt(tag.charAt(2))];
|
||||
|
@ -313,7 +316,7 @@ function populateFields() {
|
|||
tier_list.appendChild(el);
|
||||
}
|
||||
let type_list = document.getElementById("type-list");
|
||||
for (const type of types) {
|
||||
for (const type of item_types) {
|
||||
let el = document.createElement("option");
|
||||
el.value = type;
|
||||
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.
|
||||
* 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) {
|
||||
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
|
||||
let total_min = 0;
|
||||
let total_max = 0;
|
||||
let save_prop = [];
|
||||
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 damageBoost = 1 + skill_boost[i] + static_boost
|
||||
+ ((stats.get(damage_specific) + stats.get(damage_elements[i]+'DamPct')) /100);
|
||||
if (i > 0) {
|
||||
damageBoost += stats.get('r'+specific_boost_str+'Pct') / 100;
|
||||
}
|
||||
damages[i][0] *= Math.max(damageBoost, 0);
|
||||
damages[i][1] *= Math.max(damageBoost, 0);
|
||||
// Collect total damage post %boost
|
||||
total_min += damages[i][0];
|
||||
total_max += damages[i][1];
|
||||
}
|
||||
|
||||
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 rainbow_raw = stats.get('r'+specific_boost_str+'Raw') + stats.get('rDamRaw');
|
||||
for (let i in damages) {
|
||||
let save_obj = save_prop[i];
|
||||
let damages_obj = damages[i];
|
||||
let damage_prefix = damage_elements[i] + specific_boost_str;
|
||||
// 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?
|
||||
// TODO: compute actual chance of 0 damage. For now we just copy max ratio
|
||||
if (total_min === 0) {
|
||||
min_boost += (damages_obj[1] / total_max) * prop_raw;
|
||||
min_boost += (save_obj[1] / total_max) * prop_raw;
|
||||
}
|
||||
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
|
||||
// TODO: compute actual chance of 0 damage. For now we just copy max ratio
|
||||
if (total_elem_min === 0) {
|
||||
min_boost += (damages_obj[1] / total_elem_max) * rainbow_raw;
|
||||
min_boost += (save_obj[1] / total_elem_max) * rainbow_raw;
|
||||
}
|
||||
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[1] += max_boost * total_convert;
|
||||
|
@ -193,7 +202,7 @@ function calculateSpellDamage(stats, weapon, _conversions, use_spell_damage, ign
|
|||
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) {
|
||||
const res = [
|
||||
|
@ -243,17 +252,21 @@ spell_damage: {
|
|||
name: str != "total" Name of the part.
|
||||
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)
|
||||
display: bool To show part or not (for some spells there are too many intermediate calc parts). Default: True
|
||||
}
|
||||
spell_heal: {
|
||||
name: str != "total" Name of the part.
|
||||
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).
|
||||
display: bool To show part or not (for some spells there are too many intermediate calc parts). Default: True
|
||||
}
|
||||
spell_total: {
|
||||
name: str != "total" Name of the part.
|
||||
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.
|
||||
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
|
||||
}
|
||||
|
||||
|
||||
|
|
557
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) {
|
||||
suffix = (typeof suffix !== 'undefined') ? suffix : "";
|
||||
|
@ -63,7 +72,8 @@ function displayBuildStats(parent_id,build,command_group,stats){
|
|||
let active_elem;
|
||||
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"];
|
||||
|
||||
for (const command of display_commands) {
|
||||
|
@ -100,24 +110,8 @@ function displayBuildStats(parent_id,build,command_group,stats){
|
|||
if (reversedIDs.includes(id)) {
|
||||
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);
|
||||
if (id === "poison" && 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) {
|
||||
if (id === "ls" && id_val != 0) {
|
||||
let row = make_elem('div', ['row']);
|
||||
let value_elem = make_elem('div', ['col', 'text-end']);
|
||||
|
||||
|
@ -259,7 +253,7 @@ function displayExpandedItem(item, parent_id){
|
|||
if (item.get("custom")) {
|
||||
item_link = "../custom/#" + item.get("hash");
|
||||
} else if (item.get("crafted")) {
|
||||
a_item_link = "../crafter/#" + item.get("hash");
|
||||
item_link = "../crafter/#" + item.get("hash");
|
||||
} else {
|
||||
item_link = "../item/#" + item.get("displayName");
|
||||
}
|
||||
|
@ -286,11 +280,18 @@ function displayExpandedItem(item, parent_id){
|
|||
parent_div.appendChild(nolink_row);
|
||||
|
||||
if (item.has("type")) {
|
||||
let img = make_elem("img", [], {
|
||||
src: "../media/items/" + (newIcons ? "new/":"old/") + "generic-" + item.get("type") + ".png",
|
||||
let img = make_elem("div", [], {
|
||||
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 bckgrd = make_elem("div", ["col", "px-0", "d-flex", "align-items-center", "justify-content-center", 'scaled-bckgrd'], { // , "no-collapse"
|
||||
|
@ -377,33 +378,33 @@ function displayExpandedItem(item, parent_id){
|
|||
}
|
||||
}
|
||||
//Show powder specials ;-;
|
||||
let nonConsumables = ["relik", "wand", "bow", "spear", "dagger", "chestplate", "helmet", "leggings", "boots"];//, "ring", "bracelet", "necklace"];
|
||||
if(nonConsumables.includes(item.get("type"))) {
|
||||
let powder_special = document.createElement("div");
|
||||
powder_special.classList.add("col");
|
||||
let powder_specials_check = ["relik", "wand", "bow", "spear", "dagger", "chestplate", "helmet", "leggings", "boots"];
|
||||
if(powder_specials_check.includes(item.get("type"))) {
|
||||
let powder_special = make_elem("div", ['col']);
|
||||
let powders = item.get("powders");
|
||||
let element = "";
|
||||
let power = 0;
|
||||
let element;
|
||||
let power_index;
|
||||
for (let i = 0; i < powders.length; i++) {
|
||||
let firstPowderType = skp_elements[Math.floor(powders[i]/6)];
|
||||
if (element !== "") break;
|
||||
else if (powders[i]%6 > 2) { //t4+
|
||||
const firstPowderType = skp_elements[Math.floor(powders[i]/6)];
|
||||
const powder1_power = powders[i] % 6;
|
||||
if (powder1_power > 2) { //t4+
|
||||
for (let j = i+1; j < powders.length; j++) {
|
||||
let currentPowderType = skp_elements[Math.floor(powders[j]/6)]
|
||||
if (powders[j] % 6 > 2 && firstPowderType === currentPowderType) {
|
||||
const currentPowderType = skp_elements[Math.floor(powders[j]/6)]
|
||||
const powder2_power = powders[j] % 6;
|
||||
if (powder2_power > 2 && firstPowderType === currentPowderType) {
|
||||
element = currentPowderType;
|
||||
power = Math.round(((powders[i] % 6 + powders[j] % 6 + 2) / 2 - 4) * 2);
|
||||
power_index = powder1_power + powder2_power - 6;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (element) { break; } // terminate early if already found.
|
||||
}
|
||||
if (element !== "") {//powder special is "[e,t,w,f,a]+[0,1,2,3,4]"
|
||||
let powderSpecial = powderSpecialStats[ skp_elements.indexOf(element)];
|
||||
let specialSuffixes = new Map([ ["Duration", " sec"], ["Radius", " blocks"], ["Chains", ""], ["Damage", "%"], ["Damage Boost", "%"], ["Knockback", " blocks"] ]);
|
||||
let specialTitle = document.createElement("span");
|
||||
let specialEffects = document.createElement("span");
|
||||
addClasses(specialTitle, [damageClasses[skp_elements.indexOf(element) + 1]]);
|
||||
if (element) {//powder special is "[e,t,w,f,a]+[0,1,2,3,4]"
|
||||
const powderSpecial = powderSpecialStats[skp_elements.indexOf(element)];
|
||||
const specialSuffixes = new Map([ ["Duration", " sec"], ["Radius", " blocks"], ["Chains", ""], ["Damage", "%"], ["Damage Boost", "%"], ["Knockback", " blocks"] ]);
|
||||
const specialTitle = make_elem("span", [damageClasses[skp_elements.indexOf(element) + 1]]);
|
||||
const specialEffects = document.createElement("span");
|
||||
let effects;
|
||||
if (item.get("category") === "weapon") {//weapon
|
||||
effects = powderSpecial["weaponSpecialEffects"];
|
||||
|
@ -414,9 +415,9 @@ function displayExpandedItem(item, parent_id){
|
|||
}
|
||||
for (const [key,value] of effects.entries()) {
|
||||
if (key !== "Description") {
|
||||
let effect = document.createElement("p");
|
||||
effect.classList.add("m-0");
|
||||
effect.textContent = key + ": " + value[power] + specialSuffixes.get(key);
|
||||
let effect = make_elem("p", ["m-0"], {
|
||||
textContent: key + ": " + value[power_index] + specialSuffixes.get(key)
|
||||
});
|
||||
if(key === "Damage"){
|
||||
effect.textContent += elementIcons[skp_elements.indexOf(element)];
|
||||
}
|
||||
|
@ -428,16 +429,15 @@ function displayExpandedItem(item, parent_id){
|
|||
specialTitle.textContent += "[ " + effects.get("Description") + " ]";
|
||||
}
|
||||
}
|
||||
powder_special.appendChild(specialTitle);
|
||||
powder_special.appendChild(specialEffects);
|
||||
powder_special.append(specialTitle, specialEffects);
|
||||
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") {
|
||||
let dura_elem = document.createElement("div");
|
||||
dura_elem.classList.add("col");
|
||||
let dura = [];
|
||||
let dura_elem = make_elem("div", ["col"]);
|
||||
let dura;
|
||||
let suffix = "";
|
||||
if(nonConsumables.includes(item.get("type"))) {
|
||||
dura = item.get("durability");
|
||||
|
@ -446,9 +446,9 @@ function displayExpandedItem(item, parent_id){
|
|||
dura = item.get("duration");
|
||||
dura_elem.textContent = "Duration: "
|
||||
suffix = " sec."
|
||||
let charges = document.createElement("b");
|
||||
charges.textContent = "Charges: " + item.get("charges");
|
||||
parent_div.appendChild(charges);
|
||||
parent_div.appendChild(make_elem('b', [], {
|
||||
textContent: "Charges: " + item.get("charges")
|
||||
}));
|
||||
}
|
||||
|
||||
if (typeof(dura) === "string") {
|
||||
|
@ -461,9 +461,7 @@ function displayExpandedItem(item, parent_id){
|
|||
}
|
||||
//Show item tier
|
||||
if (item.get("tier") && item.get("tier") !== " ") {
|
||||
let item_desc_elem = document.createElement("div");
|
||||
item_desc_elem.classList.add("col");
|
||||
item_desc_elem.classList.add(item.get("tier"));
|
||||
let item_desc_elem = make_elem("div", ["col", item.get("tier")]);
|
||||
if (tome_types.includes(item.get("type"))) {
|
||||
tome_type_map = new Map([["weaponTome", "Weapon Tome"],["armorTome", "Armor Tome"],["guildTome", "Guild Tome"]]);
|
||||
item_desc_elem.textContent = item.get("tier")+" "+tome_type_map.get(item.get("type"));
|
||||
|
@ -475,20 +473,19 @@ function displayExpandedItem(item, parent_id){
|
|||
|
||||
//Show item hash if applicable
|
||||
if (item.get("crafted") || item.get("custom")) {
|
||||
let item_desc_elem = document.createElement("p");
|
||||
item_desc_elem.classList.add('itemp');
|
||||
item_desc_elem.style.maxWidth = "100%";
|
||||
item_desc_elem.style.wordWrap = "break-word";
|
||||
item_desc_elem.style.wordBreak = "break-word";
|
||||
item_desc_elem.textContent = item.get("hash");
|
||||
parent_div.append(item_desc_elem);
|
||||
parent_div.append(make_elem('p', ['itemp'], {
|
||||
style: {
|
||||
maxWidth: '100%',
|
||||
wordWrap: 'break-word',
|
||||
wordBreak: 'break-word'
|
||||
},
|
||||
textContent: item.get('hash')
|
||||
}));
|
||||
}
|
||||
|
||||
if (item.get("category") === "weapon") {
|
||||
let total_damages = item.get("basedps");
|
||||
let base_dps_elem = document.createElement("p");
|
||||
base_dps_elem.classList.add("left");
|
||||
base_dps_elem.classList.add("itemp");
|
||||
let base_dps_elem = make_elem("p", ["left", "itemp"]);
|
||||
if (item.get("tier") === "Crafted") {
|
||||
let base_dps_min = total_damages[0];
|
||||
let base_dps_max = total_damages[1];
|
||||
|
@ -498,8 +495,7 @@ function displayExpandedItem(item, parent_id){
|
|||
else {
|
||||
base_dps_elem.textContent = "Base DPS: "+(total_damages);
|
||||
}
|
||||
parent_div.appendChild(document.createElement("p"));
|
||||
parent_div.appendChild(base_dps_elem);
|
||||
parent_div.append(make_elem("p"), 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 = "";
|
||||
if (build.statMap.get('poison') <= 0) {
|
||||
if (statMap.get('poison') <= 0) {
|
||||
overallparent_elem.style = "display: none";
|
||||
return;
|
||||
}
|
||||
|
@ -1003,7 +999,8 @@ function displayPoisonDamage(overallparent_elem, build) {
|
|||
title_elemavg.append(make_elem('span', [], { textContent: "Poison Stats" }));
|
||||
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");
|
||||
overallpoisonDamage.append(
|
||||
|
@ -1257,8 +1254,8 @@ function displayPowderSpecials(parent_elem, powderSpecials, stats, weapon, overa
|
|||
//iterate through the special and display its effects.
|
||||
let powder_special = make_elem("p", ["pt-3"]);
|
||||
let specialSuffixes = new Map([ ["Duration", " sec"], ["Radius", " blocks"], ["Chains", ""], ["Damage", "%"], ["Damage Boost", "%"], ["Knockback", " blocks"] ]);
|
||||
let specialTitle = document.createElement("p");
|
||||
let specialEffects = document.createElement("p");
|
||||
let specialTitle = make_elem("p");
|
||||
let specialEffects = make_elem("p");
|
||||
specialTitle.classList.add(damageClasses[powderSpecialStats.indexOf(special[0]) + 1]);
|
||||
let effects = special[0]["weaponSpecialEffects"];
|
||||
let power = special[1];
|
||||
|
@ -1382,7 +1379,7 @@ function displayPowderSpecials(parent_elem, powderSpecials, stats, weapon, overa
|
|||
}
|
||||
|
||||
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) {
|
||||
|
@ -1445,6 +1442,7 @@ function displaySpellDamage(parent_elem, _overallparent_elem, stats, spell, spel
|
|||
|
||||
for (let i = 0; i < spell_results.length; ++i) {
|
||||
const spell_info = spell_results[i];
|
||||
if (!spell_info.display) { continue; }
|
||||
|
||||
let part_div = make_elem("p", ["pt-3"]);
|
||||
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);
|
||||
} else if (spell_info.type === "heal") {
|
||||
let heal_amount = spell_info.heal_amount;
|
||||
let healLabel = document.createElement("p");
|
||||
healLabel.textContent = heal_amount;
|
||||
// healLabel.classList.add("damagep");
|
||||
let healLabel = make_elem("p", ["Set"], {textContent: heal_amount.toFixed(2)});
|
||||
part_div.append(healLabel);
|
||||
if (spell_info.name === spell.display) {
|
||||
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);
|
||||
}
|
||||
|
||||
/** 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) {
|
||||
//up and down arrow - done ugly
|
||||
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: ",
|
||||
"hprPct":"Health Regen %: ",
|
||||
"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 %: ",
|
||||
"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: ",
|
||||
"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 %: ",
|
||||
"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: ",
|
||||
"ms":"Mana Steal: ",
|
||||
"ref":"Reflection: ",
|
||||
|
@ -70,7 +98,6 @@ let idPrefixes = {"displayName": "",
|
|||
"spRaw3":"3rd Spell Cost Raw: ",
|
||||
"spPct4":"4th Spell Cost %: ",
|
||||
"spRaw4":"4th Spell Cost Raw: ",
|
||||
"rainbowRaw":"Rainbow Spell Damage Raw: ",
|
||||
"sprint":"Sprint Bonus: ",
|
||||
"sprintReg":"Sprint Regen Bonus: ",
|
||||
"jh":"Jump Height: ",
|
||||
|
@ -117,9 +144,37 @@ let idSuffixes = {"displayName": "",
|
|||
"hprRaw":"",
|
||||
"hprPct":"%",
|
||||
"sdRaw":"",
|
||||
"rSdRaw":"",
|
||||
"nSdRaw":"",
|
||||
"eSdRaw":"",
|
||||
"tSdRaw":"",
|
||||
"wSdRaw":"",
|
||||
"fSdRaw":"",
|
||||
"aSdRaw":"",
|
||||
"sdPct":"%",
|
||||
"rSdPct":"%",
|
||||
"nSdPct":"%",
|
||||
"eSdPct":"%",
|
||||
"tSdPct":"%",
|
||||
"wSdPct":"%",
|
||||
"fSdPct":"%",
|
||||
"aSdPct":"%",
|
||||
"mdRaw":"",
|
||||
"rMdRaw":"",
|
||||
"nMdRaw":"",
|
||||
"eMdRaw":"",
|
||||
"tMdRaw":"",
|
||||
"wMdRaw":"",
|
||||
"fMdRaw":"",
|
||||
"aMdRaw":"",
|
||||
"mdPct":"%",
|
||||
"rMdPct":"%",
|
||||
"nMdPct":"%",
|
||||
"eMdPct":"%",
|
||||
"tMdPct":"%",
|
||||
"wMdPct":"%",
|
||||
"fMdPct":"%",
|
||||
"aMdPct":"%",
|
||||
"mr":"/5s",
|
||||
"ms":"/3s",
|
||||
"ref":"%",
|
||||
|
@ -147,7 +202,6 @@ let idSuffixes = {"displayName": "",
|
|||
"spRaw3":"",
|
||||
"spPct4":"%",
|
||||
"spRaw4":"",
|
||||
"rainbowRaw":"",
|
||||
"sprint":"%",
|
||||
"sprintReg":"%",
|
||||
"jh":"",
|
||||
|
@ -209,25 +263,16 @@ let posModSuffixes = {
|
|||
/*
|
||||
* Display commands
|
||||
*/
|
||||
let build_all_display_commands = [
|
||||
let build_overall_display_commands = [
|
||||
"#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",
|
||||
|
@ -236,24 +281,65 @@ let build_all_display_commands = [
|
|||
"gXp", "gSpd",
|
||||
];
|
||||
|
||||
let build_offensive_display_commands = [
|
||||
let build_detailed_display_commands = [
|
||||
"#defense-stats",
|
||||
"str", "dex", "int", "def", "agi",
|
||||
"!spacer",
|
||||
"mr", "ms",
|
||||
"sdRaw", "sdPct",
|
||||
"mdRaw", "mdPct",
|
||||
"ref", "thorns",
|
||||
"hprRaw", "hprPct",
|
||||
"ls",
|
||||
"poison",
|
||||
"expd",
|
||||
"spd",
|
||||
"atkTier",
|
||||
"rainbowRaw",
|
||||
"sdRaw", "nSdRaw", "rSdRaw",
|
||||
"sdPct", "nSdPct", "rSdPct",
|
||||
"mdRaw", "nMdRaw", "rMdRaw",
|
||||
"mdPct", "nMdPct", "rMdPct",
|
||||
"!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",
|
||||
"!elemental",
|
||||
"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 = [
|
||||
'#defense-stats',
|
||||
// defense stats [hp, ehp, hpr, ]
|
||||
|
@ -283,8 +369,10 @@ let sq2_item_display_commands = [
|
|||
"str", "dex", "int", "def", "agi",
|
||||
"hpBonus",
|
||||
"hprRaw", "hprPct",
|
||||
"sdRaw", "sdPct",
|
||||
"mdRaw", "mdPct",
|
||||
"sdRaw", "nSdRaw", "eSdRaw", "tSdRaw", "wSdRaw", "fSdRaw", "aSdRaw", "rSdRaw",
|
||||
"sdPct", "nSdPct", "eSdPct", "tSdPct", "wSdPct", "fSdPct", "aSdPct", "rSdPct",
|
||||
"mdRaw", "nMdRaw", "eMdRaw", "tMdRaw", "wMdRaw", "fMdRaw", "aMdRaw", "rMdRaw",
|
||||
"mdPct", "nMdPct", "eMdPct", "tMdPct", "wMdPct", "fMdPct", "aMdPct", "rMdPct",
|
||||
"mr", "ms",
|
||||
"ref", "thorns",
|
||||
"ls",
|
||||
|
@ -297,7 +385,6 @@ let sq2_item_display_commands = [
|
|||
"fDefPct", "wDefPct", "aDefPct", "tDefPct", "eDefPct",
|
||||
"!elemental",
|
||||
"spPct1", "spRaw1", "spPct2", "spRaw2", "spPct3", "spRaw3", "spPct4", "spRaw4",
|
||||
"rainbowRaw",
|
||||
"sprint", "sprintReg",
|
||||
"jh",
|
||||
"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;
|
||||
icon_state_stored = window_storage.getItem("newicons");
|
||||
newIcons = true;
|
||||
if (icon_state_stored === "false") {toggleIcons()}
|
||||
if (window_storage.getItem("newicons") === "false") {
|
||||
toggleIcons();
|
||||
}
|
||||
|
||||
/** Toggle icons on the ENTIRE page.
|
||||
*
|
||||
*/
|
||||
function toggleIcons() {
|
||||
newIcons = !newIcons;
|
||||
let imgs = document.getElementsByTagName("IMG");
|
||||
let favicon = document.querySelector("link[rel~='icon']");
|
||||
let toggleiconbutton = document.getElementById("toggle-icon-button");
|
||||
window_storage.setItem("newicons", newIcons.toString());
|
||||
let newOrOld = (newIcons ? "new" : "old");
|
||||
|
||||
if (newIcons) { //switch to new
|
||||
favicon.href = favicon.href.replace("media/icons/old","media/icons/new");
|
||||
let imgs = document.getElementsByTagName("img");
|
||||
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) {
|
||||
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");}
|
||||
// if doesn't contain, replace() does nothing
|
||||
img.src = img.src.replace("media/icons/" + (newIcons ? "old" : "new"), "media/icons/" + newOrOld);
|
||||
}
|
||||
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");
|
||||
for (let i = 0; i < divs.length; i++) {
|
||||
divs.item(i).style.backgroundImage = "url('../media/items/" + (newIcons ? "new" : "old") + ".png')";
|
||||
}
|
||||
}
|
495
js/items.js
|
@ -1,17 +1,12 @@
|
|||
const translate_mappings = {
|
||||
// commented out filters
|
||||
//"Name": "name",
|
||||
//"Display Name": "displayName",
|
||||
//"tier"Tier": ",
|
||||
//"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",
|
||||
//"Drop type": "drop", BROKEN
|
||||
//"Quest requirement": "quest", BROKEN
|
||||
//"Restriction": "restrict", BROKEN
|
||||
//"Base Neutral Damage": "nDam",
|
||||
//"Base Fire Damage": "fDam",
|
||||
//"Base Water Damage": "wDam",
|
||||
|
@ -19,6 +14,13 @@ const translate_mappings = {
|
|||
//"Base Thunder Damage": "tDam",
|
||||
//"Base Earth Damage": "eDam",
|
||||
//"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",
|
||||
"Raw Fire Defense": "fDef",
|
||||
"Raw Water Defense": "wDef",
|
||||
|
@ -26,7 +28,6 @@ const translate_mappings = {
|
|||
"Raw Thunder Defense": "tDef",
|
||||
"Raw Earth Defense": "eDef",
|
||||
"Combat Level": "lvl",
|
||||
//"Class Requirement": "classReq",
|
||||
"Req Strength": "strReq",
|
||||
"Req Dexterity": "dexReq",
|
||||
"Req Intelligence": "intReq",
|
||||
|
@ -67,10 +68,6 @@ const translate_mappings = {
|
|||
"% 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",
|
||||
|
@ -79,129 +76,180 @@ const translate_mappings = {
|
|||
"3rd Spell Cost Raw": "-spRaw3",
|
||||
"4th Spell Cost %": "-spPct4",
|
||||
"4th Spell Cost Raw": "-spRaw4",
|
||||
|
||||
"Rainbow Spell Damage": "rainbowRaw",
|
||||
"Rainbow Spell Damage Raw": "rainbowRaw",
|
||||
"Sprint": "sprint",
|
||||
"Sprint Regen": "sprintReg",
|
||||
"Jump Height": "jh",
|
||||
"Loot Quality": "lq",
|
||||
|
||||
"Gather XP Bonus": "gXp",
|
||||
"Gather Speed Bonus": "gSpd",
|
||||
"Gather Speed Bonus": "gSpd"
|
||||
};
|
||||
|
||||
const special_mappings = {
|
||||
"Sum (skill points)": "s:str+dex+int+def+agi",
|
||||
"Sum (Mana Sustain)": "s:mr+ms",
|
||||
"Sum (Life Sustain)": "s:hpr+ls",
|
||||
"Sum (Health + Health Bonus)": "s:hp+hpBonus",
|
||||
"No Strength Req": "f:strReq=0",
|
||||
"No Dexterity Req": "f:dexReq=0",
|
||||
"No Intelligence Req": "f:intReq=0",
|
||||
"No Agility Req": "f:agiReq=0",
|
||||
"No Defense Req": "f:defReq=0",
|
||||
"Sum (skill points)": "str+dex+int+def+agi",
|
||||
"Sum (Mana Sustain)": "mr+ms",
|
||||
"Sum (Life Sustain)": "hpr+ls",
|
||||
"Sum (Health + Health Bonus)": "hp+hpBonus",
|
||||
"Base DPS": "(nDam+fDam+wDam+aDam+tDam+eDam) * atkspdmod(atkspd)"
|
||||
};
|
||||
|
||||
let itemFilters = document.getElementById("filter-items");
|
||||
if (itemFilters) {
|
||||
let item_filters = [];
|
||||
for (let x in translate_mappings) {
|
||||
let el = document.createElement("option");
|
||||
el.value = x;
|
||||
itemFilters.appendChild(el);
|
||||
item_filters.push(x);
|
||||
}
|
||||
for (let x in special_mappings) {
|
||||
let el = document.createElement("option");
|
||||
el.value = x;
|
||||
itemFilters.appendChild(el);
|
||||
}
|
||||
item_filters.push(x);
|
||||
}
|
||||
|
||||
let itemCategories = [ "armor", "accessory", "weapon" ];
|
||||
let item_categories = ["armor", "accessory", "weapon"];
|
||||
|
||||
function applyQuery(items, query) {
|
||||
return items.filter(query.filter, query).sort(query.compare);
|
||||
}
|
||||
const types = {bow: false, spear: false, wand: false, dagger: false, relik: false, helmet: false, chestplate: false, leggings: false, boots: false, ring: false, bracelet: false, necklace: false};
|
||||
const rarities = {normal: true, unique: true, set: true, rare: true, legendary: true, fabled: true, mythic: true};
|
||||
const filters = [], excludes = [];
|
||||
let filter_id_counter = 0;
|
||||
|
||||
function displayItems(results) {
|
||||
let items_parent = document.getElementById("main");
|
||||
for (let i in results) {
|
||||
let item = results[i].itemExp;
|
||||
let box = document.createElement("div");
|
||||
box.classList.add("box");
|
||||
box.id = "item"+i;
|
||||
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].itemExp;
|
||||
let box = make_elem('div', ['col-lg-3', 'col-sm-6', 'p-2'], {id: 'item'+i});
|
||||
|
||||
let bckgrdbox = make_elem("div", ["dark-7", "rounded", "px-2", "col-auto"], {id: 'item'+i+'b'});
|
||||
box.append(bckgrdbox);
|
||||
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);
|
||||
let queries = [];
|
||||
queries.push('f:name?="'+document.getElementById("item-name-choice").value.trim()+'"');
|
||||
|
||||
let categoryOrType = document.getElementById("item-category-choice").value;
|
||||
if (itemTypes.includes(categoryOrType)) {
|
||||
queries.push('f:type="'+categoryOrType+'"');
|
||||
}
|
||||
else if (itemCategories.includes(categoryOrType)) {
|
||||
queries.push('f:cat="'+categoryOrType+'"');
|
||||
// name
|
||||
if (document.getElementById("item-name-choice").value != "") {
|
||||
queries.push("f:name?=\"" + document.getElementById("item-name-choice").value.trim() + "\"");
|
||||
}
|
||||
|
||||
let rarity = document.getElementById("item-rarity-choice").value;
|
||||
if (rarity) {
|
||||
if (rarity === "ANY") {
|
||||
|
||||
// types
|
||||
let allTypes = true, noTypes = true;
|
||||
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("-");
|
||||
queries.push('f:(lvl>='+parseInt(level_dat[0])+'&lvl<='+parseInt(level_dat[1])+')');
|
||||
|
||||
for (let i = 1; i <= 4; ++i) {
|
||||
let raw_dat = document.getElementById("filter"+i+"-choice").value;
|
||||
let filter_dat = translate_mappings[raw_dat];
|
||||
if (filter_dat !== undefined) {
|
||||
queries.push("s:"+filter_dat);
|
||||
queries.push("f:"+filter_dat+"!=0");
|
||||
continue;
|
||||
// rarities
|
||||
let allRarities = true, noRarities = true;
|
||||
let rarityQuery = "f:("
|
||||
for (const rarity of Object.keys(rarities)) {
|
||||
if (rarities[rarity]) {
|
||||
rarityQuery += "tiername=\"" + rarity + "\"|";
|
||||
noRarities = false;
|
||||
} else {
|
||||
allRarities = false;
|
||||
}
|
||||
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";
|
||||
let sortQueries = [];
|
||||
// filters
|
||||
for (const filter of filters) {
|
||||
let min = parseInt(filter.min_elem.value);
|
||||
let max = parseInt(filter.max_elem.value);
|
||||
if (min > max) {
|
||||
document.getElementById("summary").innerHTML = "Error: The minimum of filter " + filter.input_elem.value + " (" + min + ") is greater than its maximum (" + max + ")";
|
||||
return;
|
||||
}
|
||||
let zero_in_min_max = (isNaN(min) || min < 0) && (isNaN(max) || max > 0);
|
||||
|
||||
let raw_name = filter.input_elem.value;
|
||||
if (raw_name == "") {
|
||||
continue; // empty
|
||||
}
|
||||
let filter_name = translate_mappings[raw_name];
|
||||
if (filter_name === undefined) {
|
||||
filter_name = special_mappings[raw_name];
|
||||
if (filter_name === undefined) {
|
||||
document.getElementById("summary").innerHTML = "Error: The filter \"" + filter.input_elem.value + "\" is not recognized";
|
||||
return;
|
||||
}
|
||||
filter_name = "(" + filter_name + ")";
|
||||
}
|
||||
|
||||
if (!isNaN(min)) {
|
||||
queries.push("f:" + filter_name + ">=" + min);
|
||||
}
|
||||
if (!isNaN(max)) {
|
||||
queries.push("f:" + filter_name + "<=" + max);
|
||||
}
|
||||
if (zero_in_min_max) {
|
||||
queries.push("f:" + filter_name + "!=0");
|
||||
}
|
||||
queries.push("s:" + (filter.ascending ? "0-" : "") + filter_name);
|
||||
}
|
||||
|
||||
// excludes
|
||||
for (const exclude of excludes) {
|
||||
let raw_name = exclude.input_elem.value;
|
||||
if (raw_name == "") {
|
||||
continue; // empty
|
||||
}
|
||||
let filter_name = translate_mappings[raw_name];
|
||||
if (filter_name === undefined) {
|
||||
filter_name = special_mappings[raw_name];
|
||||
if (filter_name === undefined) {
|
||||
document.getElementById("summary").innerHTML = "Error: The excluded filter \"" + exclude.input_elem.value + "\" is not recognized";
|
||||
return;
|
||||
}
|
||||
filter_name = "(" + filter_name + ")";
|
||||
}
|
||||
queries.push("f:" + filter_name + "=0");
|
||||
}
|
||||
|
||||
let filter_query = "true";
|
||||
let sort_queries = [];
|
||||
console.log(queries);
|
||||
for (const query of queries) {
|
||||
if (query.startsWith("s:")) {
|
||||
sortQueries.push(query.slice(2));
|
||||
sort_queries.push(query.slice(2));
|
||||
}
|
||||
else if (query.startsWith("f:")) {
|
||||
filterQuery = filterQuery + "&" + query.slice(2);
|
||||
filter_query = filter_query + "&" + query.slice(2);
|
||||
}
|
||||
}
|
||||
console.log(filterQuery);
|
||||
console.log(sortQueries);
|
||||
document.getElementById("search-results").textContent = "";
|
||||
let results = [];
|
||||
try {
|
||||
const filterExpr = exprParser.parse(filterQuery);
|
||||
const sortExprs = sortQueries.map(q => exprParser.parse(q));
|
||||
for (let i = 0; i < searchDb.length; ++i) {
|
||||
const item = searchDb[i][0];
|
||||
const itemExp = searchDb[i][1];
|
||||
if (checkBool(filterExpr.resolve(item, itemExp))) {
|
||||
results.push({ item, itemExp, sortKeys: sortExprs.map(e => e.resolve(item, itemExp)) });
|
||||
const filter_expr = expr_parser.parse(filter_query);
|
||||
const sort_exprs = sort_queries.map(q => expr_parser.parse(q));
|
||||
for (let i = 0; i < search_db.length; ++i) {
|
||||
const item = search_db[i][0];
|
||||
const itemExp = search_db[i][1];
|
||||
if (checkBool(filter_expr.resolve(item, itemExp))) {
|
||||
results.push({ item, itemExp, sortKeys: sort_exprs.map(e => e.resolve(item, itemExp)) });
|
||||
}
|
||||
}
|
||||
results.sort((a, b) => {
|
||||
|
@ -211,13 +259,264 @@ function doItemSearch() {
|
|||
document.getElementById("summary").textContent = e.message;
|
||||
return;
|
||||
}
|
||||
document.getElementById("summary").textContent = results.length + " results."
|
||||
document.getElementById("summary").textContent = results.length + " results:";
|
||||
document.getElementById("summary").style.color = "white";
|
||||
displayItems(results);
|
||||
}
|
||||
|
||||
function init_items() {
|
||||
searchDb = items.filter( i => ! i.remapID ).map( i => [i, expandItem(i, [])] );
|
||||
exprParser = new ExprParser(itemQueryProps, itemQueryFuncs);
|
||||
search_db = items.filter( i => ! i.remapID ).map( i => [i, expandItem(i, [])] );
|
||||
expr_parser = new ExprParser(itemQueryProps, itemQueryFuncs);
|
||||
|
||||
// init type buttons
|
||||
for (const type of Object.keys(types)) {
|
||||
document.getElementById("type-" + type).addEventListener("click", function() {
|
||||
types[type] = !types[type];
|
||||
this.classList.toggle("type-selected");
|
||||
});
|
||||
}
|
||||
document.getElementById("all-types").addEventListener("click", function() {
|
||||
for (const type of Object.keys(types)) {
|
||||
types[type] = true;
|
||||
document.getElementById("type-" + type).classList.add("type-selected");
|
||||
}
|
||||
});
|
||||
document.getElementById("none-types").addEventListener("click", function() {
|
||||
for (const type of Object.keys(types)) {
|
||||
types[type] = false;
|
||||
document.getElementById("type-" + type).classList.remove("type-selected");
|
||||
}
|
||||
});
|
||||
|
||||
// init rarity buttons
|
||||
for (const rarity of Object.keys(rarities)) {
|
||||
document.getElementById("rarity-" + rarity).addEventListener("click", function() {
|
||||
rarities[rarity] = !rarities[rarity];
|
||||
this.classList.toggle("rarity-selected");
|
||||
});
|
||||
}
|
||||
document.getElementById("all-rarities").addEventListener("click", function() {
|
||||
for (const rarity of Object.keys(rarities)) {
|
||||
rarities[rarity] = true;
|
||||
document.getElementById("rarity-" + rarity).classList.add("rarity-selected");
|
||||
}
|
||||
});
|
||||
document.getElementById("none-rarities").addEventListener("click", function() {
|
||||
for (const rarity of Object.keys(rarities)) {
|
||||
rarities[rarity] = false;
|
||||
document.getElementById("rarity-" + rarity).classList.remove("rarity-selected");
|
||||
}
|
||||
});
|
||||
|
||||
// filters
|
||||
document.getElementById("add-filter").addEventListener("click", create_filter);
|
||||
document.getElementById("add-exclude").addEventListener("click", create_exclude);
|
||||
create_filter();
|
||||
filters[0].input_elem.value = "Combat Level";
|
||||
init_filter_drag();
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
function init_items2() {
|
||||
function init_items_adv() {
|
||||
const itemList = document.getElementById('item-list');
|
||||
const itemListFooter = document.getElementById('item-list-footer');
|
||||
|
||||
|
@ -328,7 +328,11 @@ function init_items2() {
|
|||
for (let i = 0; i < searchMax; i++) {
|
||||
const result = searchResults[i];
|
||||
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) {
|
||||
const sortKeyListContainer = document.createElement('div');
|
||||
sortKeyListContainer.classList.add('row');
|
||||
|
@ -391,4 +395,7 @@ function init_items2() {
|
|||
.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
|
||||
|
||||
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.
|
||||
*/
|
||||
async function load() {
|
||||
|
||||
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!
|
||||
let url = baseUrl + "/compress.json?"+new Date();
|
||||
let result = await (await fetch(url)).json();
|
||||
|
@ -150,7 +169,7 @@ async function load_init() {
|
|||
console.log("Skipping load...")
|
||||
}
|
||||
else {
|
||||
load_in_progress = true
|
||||
load_in_progress = true;
|
||||
if (reload) {
|
||||
console.log("Using new data...")
|
||||
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.
|
||||
for (const it of itemTypes) {
|
||||
for (const it of item_types) {
|
||||
itemLists.set(it, []);
|
||||
}
|
||||
|
||||
|
@ -254,5 +273,9 @@ function init_maps() {
|
|||
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
|
||||
|
||||
|
@ -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.
|
||||
*/
|
||||
async function load_ings() {
|
||||
|
||||
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!
|
||||
let url = baseUrl + "/ingreds_compress.json?"+new Date();
|
||||
url = url.replace(/\w+.html/, "") ;
|
||||
let result = await (await fetch(url)).json();
|
||||
|
||||
result = await (await fetch(url)).json();
|
||||
ings = result;
|
||||
|
||||
url = url.replace("/ingreds_compress.json", "/recipes_compress.json");
|
||||
url = baseUrl + "/recipes_compress.json?"+new Date();
|
||||
result = await (await fetch(url)).json();
|
||||
recipes = result.recipes;
|
||||
|
||||
|
@ -197,7 +216,7 @@ function init_ing_maps() {
|
|||
posMods: {"left": 0, "right": 0, "above": 0, "under": 0, "touching": 0, "notTouching": 0}
|
||||
};
|
||||
ing.id = 4001 + ing.pid;
|
||||
ing.diplayName = ing.name;
|
||||
ing.displayName = ing.name;
|
||||
switch(i) {
|
||||
case 0:
|
||||
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
|
||||
|
||||
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.
|
||||
*/
|
||||
async function load_tome() {
|
||||
|
||||
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!
|
||||
let url = baseUrl + "/tomes.json?"+new Date();
|
||||
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", "armorTome", "No Armor Tome"],
|
||||
["tome", "guildTome", "No Guild Tome"]
|
||||
];
|
||||
let none_tomes;
|
||||
|
||||
function init_tome_maps() {
|
||||
//warp
|
||||
tomeMap = new Map();
|
||||
|
@ -135,12 +151,13 @@ function init_tome_maps() {
|
|||
tomeLists.set(it, []);
|
||||
}
|
||||
|
||||
none_tomes = [];
|
||||
for (let i = 0; i < 3; i++) {
|
||||
let tome = Object();
|
||||
tome.slots = 0;
|
||||
tome.category = none_tomes[i][0];
|
||||
tome.type = none_tomes[i][1];
|
||||
tome.name = none_tomes[i][2];
|
||||
tome.category = none_tomes_info[i][0];
|
||||
tome.type = none_tomes_info[i][1];
|
||||
tome.name = none_tomes_info[i][2];
|
||||
tome.displayName = tome.name;
|
||||
tome.set = null;
|
||||
tome.quest = null;
|
||||
|
@ -159,7 +176,7 @@ function init_tome_maps() {
|
|||
//dependency - load.js
|
||||
clean_item(tome);
|
||||
|
||||
none_tomes[i] = tome;
|
||||
none_tomes.push(tome);
|
||||
}
|
||||
tomes = tomes.concat(none_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
|
||||
|
||||
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("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("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("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("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("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"] ]),150), //t
|
||||
_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", [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", [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();
|
||||
}
|
||||
|
||||
//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
|
||||
for (const powderID of powders) {
|
||||
const powder = powderStats[powderID];
|
||||
|
@ -181,14 +220,15 @@ function calc_weapon_powder(weapon, damageBases) {
|
|||
damages[element+1][0] += powder.min;
|
||||
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.
|
||||
let present_elements = []
|
||||
for (const damage of damages) {
|
||||
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];
|
||||
}
|
||||
|
|
649
js/query.js
|
@ -1,115 +1,550 @@
|
|||
let queryTypeMap = new Map();
|
||||
|
||||
class NameQuery {
|
||||
constructor(string) { this.queryString = string.toLowerCase(); }
|
||||
|
||||
filter(item) {
|
||||
if (item.get("restrict") && item.get("restrict") === "DEPRECATED") {
|
||||
return false;
|
||||
}
|
||||
return (item.get("displayName").toLowerCase().includes(this.queryString));
|
||||
// dynamic type casts
|
||||
function checkBool(v) {
|
||||
if (typeof v !== 'boolean') throw new Error(`Expected boolean, but got ${typeof v}`);
|
||||
return v;
|
||||
}
|
||||
|
||||
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 {
|
||||
constructor(id) {
|
||||
this.id = id;
|
||||
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) {
|
||||
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');
|
||||
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()');
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
filter(item) {
|
||||
return item.get(this.id) && (item.get(this.id) == this.value);
|
||||
}
|
||||
}
|
||||
|
||||
class SumQuery {
|
||||
constructor(ids) {
|
||||
let getters = [];
|
||||
for (const id of ids) {
|
||||
if (nonRolledIDs.includes(id)) {
|
||||
getters.push(a => a.get(id));
|
||||
}
|
||||
else {
|
||||
getters.push(a => a.get("maxRolls").get(id));
|
||||
}
|
||||
|
||||
}
|
||||
this.compare = function(a, b) {
|
||||
let balance = 0;
|
||||
for (const getter of getters) {
|
||||
if (getter(a)) { balance -= getter(a); }
|
||||
if (getter(b)) { balance += getter(b); }
|
||||
}
|
||||
return balance;
|
||||
};
|
||||
}
|
||||
|
||||
filter(item) {
|
||||
// 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;
|
||||
}
|
||||
|
|
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)));
|
||||
}
|
||||
}
|
||||
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.
|
||||
permute_check(1, best_skillpoints, final_skillpoints, best_activeSetCounts, allFalse.slice(), 0, []);
|
||||
}
|
||||
|
||||
// add extra sp bonus
|
||||
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;
|
||||
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 zip3 = (a, b, c) => a.map((k, i) => [k, b[i], c[i]]);
|
||||
|
||||
|
@ -632,16 +640,6 @@ function matchType(object, target) {
|
|||
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.
|
||||
*
|
||||
*/
|
||||
|
@ -926,6 +924,17 @@ function make_elem(type, classlist = [], args = {}) {
|
|||
const ret_elem = document.createElement(type);
|
||||
ret_elem.classList.add(...classlist);
|
||||
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];
|
||||
}
|
||||
return ret_elem;
|
||||
|
@ -994,3 +1003,40 @@ function make_SCC_graph(root_node, nodes) {
|
|||
}
|
||||
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/>
|
||||
<a href = "https://discord.gg/CGavnAnerv" target = "_blank"><img src = "../media/icons/discord.png" alt = "WB Discord" title = "WB Discord"><b>WB Discord</b></a>
|
||||
</div>
|
||||
<div id="mobile-navbar" class="navbar dark-5 dark-shadow fixed-top d-lg-none pb-0">
|
||||
<div class="container-fluid scaled-font justify-content-center" style="height: 5vh;">
|
||||
<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>
|
||||
|
|
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 |