Merge branch 'UI_test' into compute_graph

This commit is contained in:
hppeng 2022-06-19 11:43:02 -07:00
commit 7bd27a9675
25 changed files with 2393 additions and 1213 deletions

View file

@ -49,12 +49,11 @@
<a onclick = "toggleIcons()"><img src = "../media/icons/new/reload.png" alt = "" title = "Swap items on page"><b>Swap Icon Style</b></a>
<hr/>
</div>
<div class="my-container">
<div class="col">
<div class="row h-100 gx-lg-5 gy-3 mx-2 mx-lg-0">
<div class="container-fluid me-4" style="max-width: 95%;">
<div class="row h-100 gx-lg-5 gy-3 mx-2 mx-lg-3 py-3">
<div class="col-xl-6">
<div class="row row-cols-1 mb-3">
<div class="col py-3">
<div class="row row-cols-1 mb-3 gy-4">
<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">
@ -184,7 +183,7 @@
<input class="equipment-input text-light form-control" id="leggings-choice" name="leggings-choice" placeholder="No leggings" value="" tabindex="1"/>
</div>
<div class="col d-flex justify-content-end">
<input class="equipment-input text-light form-control" type="text" id="leggings-powder" name="leggings-powder" placeholder="no powders" tabindex="1"/>
<input class="equipment-input text-light form-control" type="text" id="leggings-powder" name="leggings-powder" placeholder="powders" tabindex="1"/>
</div>
</div>
</div>
@ -277,8 +276,8 @@
</div>
<div class="col-3">
<div class="row row-cols-1 h-100 align-items-center">
<div class="col scaled-font fw-bold gx-3" id="weapon-dps">
base dps: 0
<div class="col text-nowrap scaled-font fw-bold gx-3 Damage base_dps" id="weapon-dps">
0
</div>
<div class="col text-nowrap scaled-font lvl fw-bold gx-3" id="weapon-lv">
0
@ -299,18 +298,19 @@
</div>
<div class="col-auto order-xl-0 order-1">
<div class="row h-100 dark-shadow dark-6 rounded">
<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 class="img-fluid rounded" src="../media/icons/new/Gears.png">
</div>
<div class="col">
<div class="row align-items-center">
<div class="col-3 text-nowrap scaled-font">
<div class="col-3 text-nowrap fw-bold scaled-font">
Level:
</div>
<div class="col d-flex justify-content-end">
<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="sq2ResetFields()">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(player_build)">Copy short</button>
@ -324,7 +324,8 @@
</div>
</div>
</div>
<div class="col py-3">
</div>
<div class="col">
<div class="row row-cols-1 gy-2 rounded dark-5 dark-shadow">
<div class="col">
<div class="row row-cols-2 row-cols-xl-5 gy-2 justify-content-center">
@ -413,8 +414,8 @@
</div>
</div>
</div>
<div class="col mb-5">
<div class="row row-cols-1 gy-3">
<div class="col">
<div class="row row-cols-1 gy-4">
<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">
@ -456,7 +457,7 @@
<div class="col g-0 rounded">
<div class="row row-cols-1 h-100 align-items-center">
<div class="col d-flex justify-content-end">
<input class="equipment-input border-dark text-light dark-5 rounded scaled-font form-control form-control-sm" id="weaponTome1-choice" name="weaponTome1-choice" placeholder="No Tome" value=""/>
<input class="equipment-input border-dark text-light dark-10 rounded scaled-font form-control form-control-sm" id="weaponTome1-choice" name="weaponTome1-choice" placeholder="No Tome" value=""/>
</div>
</div>
</div>
@ -480,7 +481,7 @@
<div class="col g-0 rounded">
<div class="row row-cols-1 h-100 align-items-center">
<div class="col d-flex justify-content-end">
<input class="equipment-input border-dark text-light dark-5 rounded scaled-font form-control form-control-sm" id="weaponTome2-choice" name="weaponTome2-choice" placeholder="No Tome" value=""/>
<input class="equipment-input border-dark text-light dark-10 rounded scaled-font form-control form-control-sm" id="weaponTome2-choice" name="weaponTome2-choice" placeholder="No Tome" value=""/>
</div>
</div>
</div>
@ -504,7 +505,7 @@
<div class="col g-0 rounded">
<div class="row row-cols-1 h-100 align-items-center">
<div class="col d-flex justify-content-end">
<input class="equipment-input border-dark text-light dark-5 rounded scaled-font form-control form-control-sm" id="armorTome1-choice" name="armorTome1-choice" placeholder="No Tome" value=""/>
<input class="equipment-input border-dark text-light dark-10 rounded scaled-font form-control form-control-sm" id="armorTome1-choice" name="armorTome1-choice" placeholder="No Tome" value=""/>
</div>
</div>
</div>
@ -528,7 +529,7 @@
<div class="col g-0 rounded">
<div class="row row-cols-1 h-100 align-items-center">
<div class="col d-flex justify-content-end">
<input class="equipment-input border-dark text-light dark-5 rounded scaled-font form-control form-control-sm" id="armorTome2-choice" name="armorTome2-choice" placeholder="No Tome" value=""/>
<input class="equipment-input border-dark text-light dark-10 rounded scaled-font form-control form-control-sm" id="armorTome2-choice" name="armorTome2-choice" placeholder="No Tome" value=""/>
</div>
</div>
</div>
@ -552,7 +553,7 @@
<div class="col g-0 rounded">
<div class="row row-cols-1 h-100 align-items-center">
<div class="col d-flex justify-content-end">
<input class="equipment-input border-dark text-light dark-5 rounded scaled-font form-control form-control-sm" id="armorTome3-choice" name="armorTome3-choice" placeholder="No Tome" value=""/>
<input class="equipment-input border-dark text-light dark-10 rounded scaled-font form-control form-control-sm" id="armorTome3-choice" name="armorTome3-choice" placeholder="No Tome" value=""/>
</div>
</div>
</div>
@ -576,7 +577,7 @@
<div class="col g-0 rounded">
<div class="row row-cols-1 h-100 align-items-center">
<div class="col d-flex justify-content-end">
<input class="equipment-input border-dark text-light dark-5 rounded scaled-font form-control form-control-sm" id="armorTome4-choice" name="armorTome4-choice" placeholder="No Tome" value=""/>
<input class="equipment-input border-dark text-light dark-10 rounded scaled-font form-control form-control-sm" id="armorTome4-choice" name="armorTome4-choice" placeholder="No Tome" value=""/>
</div>
</div>
</div>
@ -600,7 +601,7 @@
<div class="col g-0 rounded">
<div class="row row-cols-1 h-100 align-items-center">
<div class="col d-flex justify-content-end">
<input class="equipment-input border-dark text-light dark-5 rounded scaled-font form-control form-control-sm" id="guildTome1-choice" name="guildTome1-choice" placeholder="No Tome" value=""/>
<input class="equipment-input border-dark text-light dark-10 rounded scaled-font form-control form-control-sm" id="guildTome1-choice" name="guildTome1-choice" placeholder="No Tome" value=""/>
</div>
</div>
</div>
@ -618,7 +619,7 @@
Spell Damage %:
</div>
<div class = "row">
<input type = "number" placeholder = "0" id="sdPct" name="sdPct" value="0" class="border-semi-dark border-2 text-light dark-5 rounded scaled-font form-control form-control-sm" oninput = "updateStats()"/>
<input type = "number" placeholder = "0" id="sdPct" name="sdPct" value="0" class="border-dark text-light dark-10 rounded scaled-font form-control form-control-sm" oninput = "updateStats()"/>
</div>
<div class = "row" id = "sdPct-base">
Original Value: 0
@ -629,7 +630,7 @@
Spell Damage Raw:
</div>
<div class = "row">
<input type = "number" placeholder = "0" id="sdRaw" name="sdRaw" value="0" class="border-semi-dark border-2 text-light dark-5 rounded scaled-font form-control form-control-sm" oninput = "updateStats()"/>
<input type = "number" placeholder = "0" id="sdRaw" name="sdRaw" value="0" class="border-dark text-light dark-10 rounded scaled-font form-control form-control-sm" oninput = "updateStats()"/>
</div>
<div class = "row" id = "sdRaw-base">
Original Value: 0
@ -640,7 +641,7 @@
Melee Damage %:
</div>
<div class = "row">
<input type = "number" placeholder = "0" id="mdPct" name="mdPct" value="0" class="border-semi-dark border-2 text-light dark-5 rounded scaled-font form-control form-control-sm" oninput = "updateStats()"/>
<input type = "number" placeholder = "0" id="mdPct" name="mdPct" value="0" class="border-dark text-light dark-10 rounded scaled-font form-control form-control-sm" oninput = "updateStats()"/>
</div>
<div class = "row" id = "mdPct-base">
Original Value: 0
@ -651,7 +652,7 @@
Melee Damage Raw:
</div>
<div class = "row">
<input type = "number" placeholder = "0" id="mdRaw" name="mdRaw" value="0" class="border-semi-dark border-2 text-light dark-5 rounded scaled-font form-control form-control-sm" oninput = "updateStats()"/>
<input type = "number" placeholder = "0" id="mdRaw" name="mdRaw" value="0" class="border-dark text-light dark-10 rounded scaled-font form-control form-control-sm" oninput = "updateStats()"/>
</div>
<div class = "row" id = "mdRaw-base">
Original Value: 0
@ -664,7 +665,7 @@
Poison:
</div>
<div class = "row">
<input type = "number" placeholder = "0" id="poison" name="poison" value="0" class="border-semi-dark border-2 text-light dark-5 rounded scaled-font form-control form-control-sm" oninput = "updateStats()"/>
<input type = "number" placeholder = "0" id="poison" name="poison" value="0" class="border-dark text-light dark-10 rounded scaled-font form-control form-control-sm" oninput = "updateStats()"/>
</div>
<div class = "row" id = "poison-base">
Original Value: 0
@ -675,7 +676,7 @@
Damage %:
</div>
<div class = "row">
<input type = "number" placeholder = "0" id="eDamPct" name="eDamPct" value="0" class="border-semi-dark border-2 text-light dark-5 rounded scaled-font form-control form-control-sm" oninput = "updateStats()"/>
<input type = "number" placeholder = "0" id="eDamPct" name="eDamPct" value="0" class="border-dark text-light dark-10 rounded scaled-font form-control form-control-sm" oninput = "updateStats()"/>
</div>
<div class = "row" id = "eDamPct-base">
Original Value: 0
@ -686,7 +687,7 @@
Damage %:
</div>
<div class = "row">
<input type = "number" placeholder = "0" id="tDamPct" name="tDamPct" value="0" class="border-semi-dark border-2 text-light dark-5 rounded scaled-font form-control form-control-sm" oninput = "updateStats()"/>
<input type = "number" placeholder = "0" id="tDamPct" name="tDamPct" value="0" class="border-dark text-light dark-10 rounded scaled-font form-control form-control-sm" oninput = "updateStats()"/>
</div>
<div class = "row" id = "tDamPct-base">
Original Value: 0
@ -697,7 +698,7 @@
Damage %:
</div>
<div class = "row">
<input type = "number" placeholder = "0" id="wDamPct" name="wDamPct" value="0" class="border-semi-dark border-2 text-light dark-5 rounded scaled-font form-control form-control-sm" oninput = "updateStats()"/>
<input type = "number" placeholder = "0" id="wDamPct" name="wDamPct" value="0" class="border-dark text-light dark-10 rounded scaled-font form-control form-control-sm" oninput = "updateStats()"/>
</div>
<div class = "row" id = "wDamPct-base">
Original Value: 0
@ -710,7 +711,7 @@
Damage %:
</div>
<div class = "row">
<input type = "number" placeholder = "0" id="fDamPct" name="fDamPct" value="0" class="border-semi-dark border-2 text-light dark-5 rounded scaled-font form-control form-control-sm" oninput = "updateStats()"/>
<input type = "number" placeholder = "0" id="fDamPct" name="fDamPct" value="0" class="border-dark text-light dark-10 rounded scaled-font form-control form-control-sm" oninput = "updateStats()"/>
</div>
<div class = "row" id = "fDamPct-base">
Original Value: 0
@ -721,7 +722,7 @@
Damage %:
</div>
<div class = "row">
<input type = "number" placeholder = "0" id="aDamPct" name="aDamPct" value="0" class="border-semi-dark border-2 text-light dark-5 rounded scaled-font form-control form-control-sm" oninput = "updateStats()"/>
<input type = "number" placeholder = "0" id="aDamPct" name="aDamPct" value="0" class="border-dark text-light dark-10 rounded scaled-font form-control form-control-sm" oninput = "updateStats()"/>
</div>
<div class = "row" id = "aDamPct-base">
Original Value: 0
@ -732,7 +733,7 @@
+ Tier:
</div>
<div class = "row">
<input type = "number" placeholder = "0" id="atkTier" name="atkTier" value="0" class="border-semi-dark border-2 text-light dark-5 rounded scaled-font form-control form-control-sm" oninput = "updateStats()"/>
<input type = "number" placeholder = "0" id="atkTier" name="atkTier" value="0" class="border-dark text-light dark-10 rounded scaled-font form-control form-control-sm" oninput = "updateStats()"/>
</div>
<div class = "row" id = "atkTier-base">
Original Value: 0
@ -751,7 +752,7 @@
Defense %:
</div>
<div class = "row">
<input type = "number" placeholder = "0" id="eDefPct" name="eDefPct" value="0" class="border-semi-dark border-2 text-light dark-5 rounded scaled-font form-control form-control-sm" oninput = "updateStats()"/>
<input type = "number" placeholder = "0" id="eDefPct" name="eDefPct" value="0" class="border-dark text-light dark-10 rounded scaled-font form-control form-control-sm" oninput = "updateStats()"/>
</div>
<div class = "row" id = "eDefPct-base">
Original Value: 0
@ -762,7 +763,7 @@
Defense %:
</div>
<div class = "row">
<input type = "number" placeholder = "0" id="tDefPct" name="tDefPct" value="0" class="border-semi-dark border-2 text-light dark-5 rounded scaled-font form-control form-control-sm" oninput = "updateStats()"/>
<input type = "number" placeholder = "0" id="tDefPct" name="tDefPct" value="0" class="border-dark text-light dark-10 rounded scaled-font form-control form-control-sm" oninput = "updateStats()"/>
</div>
<div class = "row" id = "tDefPct-base">
Original Value: 0
@ -773,7 +774,7 @@
Defense %:
</div>
<div class = "row">
<input type = "number" placeholder = "0" id="wDefPct" name="wDefPct" value="0" class="border-semi-dark border-2 text-light dark-5 rounded scaled-font form-control form-control-sm" oninput = "updateStats()"/>
<input type = "number" placeholder = "0" id="wDefPct" name="wDefPct" value="0" class="border-dark text-light dark-10 rounded scaled-font form-control form-control-sm" oninput = "updateStats()"/>
</div>
<div class = "row" id = "wDefPct-base">
Original Value: 0
@ -784,7 +785,7 @@
Defense %:
</div>
<div class = "row">
<input type = "number" placeholder = "0" id="fDefPct" name="fDefPct" value="0" class="border-semi-dark border-2 text-light dark-5 rounded scaled-font form-control form-control-sm" oninput = "updateStats()"/>
<input type = "number" placeholder = "0" id="fDefPct" name="fDefPct" value="0" class="border-dark text-light dark-10 rounded scaled-font form-control form-control-sm" oninput = "updateStats()"/>
</div>
<div class = "row" id = "fDefPct-base">
Original Value: 0
@ -797,7 +798,7 @@
Defense %:
</div>
<div class = "row">
<input type = "number" placeholder = "0" id="aDefPct" name="aDefPct" value="0" class="border-semi-dark border-2 text-light dark-5 rounded scaled-font form-control form-control-sm" oninput = "updateStats()"/>
<input type = "number" placeholder = "0" id="aDefPct" name="aDefPct" value="0" class="border-dark text-light dark-10 rounded scaled-font form-control form-control-sm" oninput = "updateStats()"/>
</div>
<div class = "row" id = "aDefPct-base">
Original Value: 0
@ -808,7 +809,7 @@
Health Regen Raw:
</div>
<div class = "row">
<input type = "number" placeholder = "0" id="hprRaw" name="hprRaw" value="0" class="border-semi-dark border-2 text-light dark-5 rounded scaled-font form-control form-control-sm" oninput = "updateStats()"/>
<input type = "number" placeholder = "0" id="hprRaw" name="hprRaw" value="0" class="border-dark text-light dark-10 rounded scaled-font form-control form-control-sm" oninput = "updateStats()"/>
</div>
<div class = "row" id = "hprRaw-base">
Original Value: 0
@ -819,7 +820,7 @@
Health Regen %:
</div>
<div class = "row">
<input type = "number" placeholder = "0" id="hprPct" name="hprPct" value="0" class="border-semi-dark border-2 text-light dark-5 rounded scaled-font form-control form-control-sm" oninput = "updateStats()"/>
<input type = "number" placeholder = "0" id="hprPct" name="hprPct" value="0" class="border-dark text-light dark-10 rounded scaled-font form-control form-control-sm" oninput = "updateStats()"/>
</div>
<div class = "row" id = "hprPct-base">
Original Value: 0
@ -830,7 +831,7 @@
Health Bonus:
</div>
<div class = "row">
<input type = "number" placeholder = "0" id="hpBonus" name="hpBonus" value="0" class="border-semi-dark border-2 text-light dark-5 rounded scaled-font form-control form-control-sm" oninput = "updateStats()"/>
<input type = "number" placeholder = "0" id="hpBonus" name="hpBonus" value="0" class="border-dark text-light dark-10 rounded scaled-font form-control form-control-sm" oninput = "updateStats()"/>
</div>
<div class = "row" id = "hpBonus-base">
Original Value: 0
@ -846,7 +847,7 @@
1st Spell Cost %:
</div>
<div class = "row">
<input type = "number" placeholder = "0" id="spPct1" name="spPct1" value="0" class="border-semi-dark border-2 text-light dark-5 rounded scaled-font form-control form-control-sm" oninput = "updateStats()"/>
<input type = "number" placeholder = "0" id="spPct1" name="spPct1" value="0" class="border-dark text-light dark-10 rounded scaled-font form-control form-control-sm" oninput = "updateStats()"/>
</div>
<div class = "row" id = "spPct1-base">
Original Value: 0
@ -857,7 +858,7 @@
2nd Spell Cost %:
</div>
<div class = "row">
<input type = "number" placeholder = "0" id="spPct2" name="spPct2" value="0" class="border-semi-dark border-2 text-light dark-5 rounded scaled-font form-control form-control-sm" oninput = "updateStats()"/>
<input type = "number" placeholder = "0" id="spPct2" name="spPct2" value="0" class="border-dark text-light dark-10 rounded scaled-font form-control form-control-sm" oninput = "updateStats()"/>
</div>
<div class = "row" id = "spPct2-base">
Original Value: 0
@ -868,7 +869,7 @@
3rd Spell Cost %:
</div>
<div class = "row">
<input type = "number" placeholder = "0" id="spPct3" name="spPct3" value="0" class="border-semi-dark border-2 text-light dark-5 rounded scaled-font form-control form-control-sm" oninput = "updateStats()"/>
<input type = "number" placeholder = "0" id="spPct3" name="spPct3" value="0" class="border-dark text-light dark-10 rounded scaled-font form-control form-control-sm" oninput = "updateStats()"/>
</div>
<div class = "row" id = "spPct3-base">
Original Value: 0
@ -879,7 +880,7 @@
4th Spell Cost %:
</div>
<div class = "row">
<input type = "number" placeholder = "0" id="spPct4" name="spPct4" value="0" class="border-semi-dark border-2 text-light dark-5 rounded scaled-font form-control form-control-sm" oninput = "updateStats()"/>
<input type = "number" placeholder = "0" id="spPct4" name="spPct4" value="0" class="border-dark text-light dark-10 rounded scaled-font form-control form-control-sm" oninput = "updateStats()"/>
</div>
<div class = "row" id = "spPct4-base">
Original Value: 0
@ -892,7 +893,7 @@
1st Spell Cost Raw:
</div>
<div class = "row">
<input type = "number" placeholder = "0" id="spRaw1" name="spRaw1" value="0" class="border-semi-dark border-2 text-light dark-5 rounded scaled-font form-control form-control-sm" oninput = "updateStats()"/>
<input type = "number" placeholder = "0" id="spRaw1" name="spRaw1" value="0" class="border-dark text-light dark-10 rounded scaled-font form-control form-control-sm" oninput = "updateStats()"/>
</div>
<div class = "row" id = "spRaw1-base">
Original Value: 0
@ -903,7 +904,7 @@
2nd Spell Cost Raw:
</div>
<div class = "row">
<input type = "number" placeholder = "0" id="spRaw2" name="spRaw2" value="0" class="border-semi-dark border-2 text-light dark-5 rounded scaled-font form-control form-control-sm" oninput = "updateStats()"/>
<input type = "number" placeholder = "0" id="spRaw2" name="spRaw2" value="0" class="border-dark text-light dark-10 rounded scaled-font form-control form-control-sm" oninput = "updateStats()"/>
</div>
<div class = "row" id = "spRaw2-base">
Original Value: 0
@ -914,7 +915,7 @@
3rd Spell Cost Raw:
</div>
<div class = "row">
<input type = "number" placeholder = "0" id="spRaw3" name="spRaw3" value="0" class="border-semi-dark border-2 text-light dark-5 rounded scaled-font form-control form-control-sm" oninput = "updateStats()"/>
<input type = "number" placeholder = "0" id="spRaw3" name="spRaw3" value="0" class="border-dark text-light dark-10 rounded scaled-font form-control form-control-sm" oninput = "updateStats()"/>
</div>
<div class = "row" id = "spRaw3-base">
Original Value: 0
@ -925,7 +926,7 @@
4th Spell Cost Raw:
</div>
<div class = "row">
<input type = "number" placeholder = "0" id="spRaw4" name="spRaw4" value="0" class="border-semi-dark border-2 text-light dark-5 rounded scaled-font form-control form-control-sm" oninput = "updateStats()"/>
<input type = "number" placeholder = "0" id="spRaw4" name="spRaw4" value="0" class="border-dark text-light dark-10 rounded scaled-font form-control form-control-sm" oninput = "updateStats()"/>
</div>
<div class = "row" id = "spRaw4-base">
Original Value: 0
@ -1238,30 +1239,30 @@
<div id="overall-stats" class="col text-nowrap"></div>
</div>
</div>
<div class="col-xl-3 mb-3">
<div class="col-xl-3 mb-3 px-0">
<div class="row row-cols-1 gy-3 mb-4 text-center scaled-font">
<div class = "col">
<div class = "spell-display dark-5 rounded dark-shadow py-2 border border-dark" id="build-melee-statsAvg">melee</div>
<div class = "spell-display dark-5 rounded-bottom py-2 dark-shadow" id = "build-melee-stats" style="display: none;"></div>
</div>
<div class = "col">
<div class="spell-display dark-5 rounded dark-shadow py-2 border border-dark" id="build-poison-stats">poison</div>
<div class = "col spell-display dark-5 rounded dark-shadow py-2 border border-dark" id="build-poison-stats">poison</div>
</div>
<div class = "col">
<div class="spell-display spell-expand dark-5 rounded dark-shadow py-2 border border-dark" id="spell0-infoAvg">spell1</div>
<div class = "spell-display dark-5 rounded dark-shadow py-2" id = "spell0-info" style="display: none;">Spell 1</div>
<div class = "col spell-display spell-expand dark-5 rounded dark-shadow pt-2 border border-dark" id="spell0-infoAvg">spell1</div>
<div class = "col spell-display dark-5 rounded dark-shadow py-2" id = "spell0-info" style="display: none;">Spell 1</div>
</div>
<div class = "col">
<div class="spell-display spell-expand dark-5 rounded dark-shadow py-2 border border-dark" id="spell1-infoAvg">spell2</div>
<div class = "spell-display dark-5 rounded dark-shadow py-2" id = "spell1-info" style="display: none;">Spell 2</div>
<div class = "col spell-display spell-expand dark-5 rounded dark-shadow pt-2 border border-dark" id="spell1-infoAvg">spell2</div>
<div class = "col spell-display dark-5 rounded dark-shadow py-2" id = "spell1-info" style="display: none;">Spell 2</div>
</div>
<div class = "col">
<div class="spell-display spell-expand dark-5 rounded dark-shadow py-2 border border-dark" id="spell2-infoAvg">spell3</div>
<div class = "spell-display dark-5 rounded dark-shadow py-2" id = "spell2-info" style="display: none;">Spell 3</div>
<div class = "col spell-display spell-expand dark-5 rounded dark-shadow pt-2 border border-dark" id="spell2-infoAvg">spell3</div>
<div class = "col spell-display dark-5 rounded dark-shadow py-2" id = "spell2-info" style="display: none;">Spell 3</div>
</div>
<div class = "col">
<div class="spell-display spell-expand dark-5 rounded dark-shadow py-2 border border-dark" id="spell3-infoAvg">spell4</div>
<div class = "spell-display dark-5 rounded dark-shadow py-2" id = "spell3-info" style="display: none;">Spell 4</div>
<div class = "col spell-display spell-expand dark-5 rounded dark-shadow pt-2 border border-dark" id="spell3-infoAvg">spell4</div>
<div class = "col spell-display dark-5 rounded dark-shadow py-2" id = "spell3-info" style="display: none;">Spell 4</div>
</div>
<div class = "col">
<div class = "spell-display dark-5 rounded dark-shadow py-2 border border-dark" id = "powder-special-stats"></div>
@ -1270,7 +1271,7 @@
</div>
</div>
</div>
</div>
<div class="row mx-2 mx-lg-3">
<div class="col" id="masonry-container">
<div id="helmet-tooltip" class="rounded row row-cols-1 g-0 scaled-font float-tooltip border border-3 border-dark dark-shadow p-3">
</div>
@ -1308,7 +1309,9 @@
</div>
<div class = "rounded row row-cols-1 g-0 scaled-font float-tooltip border border-3 border-dark p-3" id = "set-info"></div>
</div>
<div class="col dark-5 scaled-font">
</div>
<div class="row mx-2 mx-lg-3">
<div class="col-12 dark-5 scaled-font">
<footer class="text-center">
<div id="header2">
<p>Made by <b class = "hppeng">hppeng</b> and <b class = "ferricles">ferricles</b> with <a href = "../atlas" target = "_blank" class = "atlas link">Atlas Inc</a> (JavaScript required to function, nothing works without js)</p>
@ -1320,7 +1323,8 @@
</footer>
</div>
</div>
<div class="container h-75 mx-0 mx-lg-auto dark-2 border border-4 scaled-font align-self-center" style="position: fixed; z-index: 2; overflow: auto; display: none;" id="search-container">
</div>
<div class="container h-75 mx-0 mx-lg-auto dark-2 border border-4 scaled-font align-self-center" style="position: fixed; z-index: 2000; overflow: auto; display: none;" id="search-container">
<div class="row justify-content-end">
<div class="col-auto">
<button type="button" class="btn-close btn-close-white" aria-label="Close" onclick="document.querySelector('#search-container').style.display = 'none';"></button>

View file

@ -46,7 +46,7 @@
<p class = "text-right mb-0 scaled-font fw-bold">Type:</p>
</div>
<div class = "col-7 px-0">
<input class="recipeinput border-dark text-light dark-5 rounded scaled-font form-control form-control-sm" list="recipe-choices" id="recipe-choice" name="recipe-choice" placeholder="Potion"/>
<input class="recipeinput border-dark text-light dark-10 rounded scaled-font form-control form-control-sm" list="recipe-choices" id="recipe-choice" name="recipe-choice" placeholder="Potion"/>
<datalist id="recipe-choices">
</datalist>
</div>
@ -56,7 +56,7 @@
<p class = "text-right mb-0 scaled-font fw-bold">Lv:</p>
</div>
<div class = "col-7 px-0">
<input class="levelinput border-dark text-light dark-5 rounded scaled-font form-control form-control-sm" list="level-choices" id="level-choice" name="level-choice" placeholder="103-105" />
<input class="levelinput border-dark text-light dark-10 rounded scaled-font form-control form-control-sm" list="level-choices" id="level-choice" name="level-choice" placeholder="103-105" />
<datalist id="level-choices">
</datalist>
</div>
@ -71,17 +71,17 @@
<p class = "text-right mb-0 scaled-font fw-bold">Attack Speed</p>
</div>
<div class = "row h-50">
<div class = "col">
<div class = "col-4 pl-1">
<button class = "button rounded scaled-font fw-bold text-light dark-5" id = "slow-atk-button" onclick = "toggleAtkSpd('slow-atk-button')">
Slow
</button>
</div>
<div class = "col">
<div class = "col-4 px-0">
<button class = "button rounded scaled-font fw-bold text-light dark-5" id = "normal-atk-button" onclick = "toggleAtkSpd('normal-atk-button')">
Normal
</button>
</div>
<div class = "col">
<div class = "col-4 pr-1">
<button class = "button rounded scaled-font fw-bold text-light dark-5" id = "fast-atk-button" onclick = "toggleAtkSpd('fast-atk-button')">
Fast
</button>
@ -132,7 +132,7 @@
<p class = "mb-0 scaled-font fw-bold">Ing 1:</p>
</div>
<div class = "col-9 px-0">
<input class="inginput border-dark text-light dark-5 rounded scaled-font form-control form-control-sm" list="ing-choices-1" id="ing-choice-1" name="ing-choice-1" placeholder="No Ingredient" />
<input class="inginput border-dark text-light dark-10 rounded scaled-font form-control form-control-sm" list="ing-choices-1" id="ing-choice-1" name="ing-choice-1" placeholder="No Ingredient" />
<datalist id="ing-choices-1">
</datalist>
</div>
@ -144,7 +144,7 @@
<p class = "mb-0 scaled-font fw-bold">Ing 2:</p>
</div>
<div class = "col-9 px-0">
<input class="inginput border-dark text-light dark-5 rounded scaled-font form-control form-control-sm" list="ing-choices-2" id="ing-choice-2" name="ing-choice-2" placeholder="No Ingredient" />
<input class="inginput border-dark text-light dark-10 rounded scaled-font form-control form-control-sm" list="ing-choices-2" id="ing-choice-2" name="ing-choice-2" placeholder="No Ingredient" />
<datalist id="ing-choices-2">
</datalist>
</div>
@ -158,7 +158,7 @@
<p class = "mb-0 scaled-font fw-bold">Ing 3:</p>
</div>
<div class = "col-9 px-0">
<input class="inginput border-dark text-light dark-5 rounded scaled-font form-control form-control-sm" list="ing-choices-3" id="ing-choice-3" name="ing-choice-3" placeholder="No Ingredient" />
<input class="inginput border-dark text-light dark-10 rounded scaled-font form-control form-control-sm" list="ing-choices-3" id="ing-choice-3" name="ing-choice-3" placeholder="No Ingredient" />
<datalist id="ing-choices-3">
</datalist>
</div>
@ -170,7 +170,7 @@
<p class = "mb-0 scaled-font fw-bold">Ing 4:</p>
</div>
<div class = "col-9 px-0">
<input class="inginput border-dark text-light dark-5 rounded scaled-font form-control form-control-sm" list="ing-choices-4" id="ing-choice-4" name="ing-choice-4" placeholder="No Ingredient" />
<input class="inginput border-dark text-light dark-10 rounded scaled-font form-control form-control-sm" list="ing-choices-4" id="ing-choice-4" name="ing-choice-4" placeholder="No Ingredient" />
<datalist id="ing-choices-4">
</datalist>
</div>
@ -184,7 +184,7 @@
<p class = "mb-0 scaled-font fw-bold">Ing 5:</p>
</div>
<div class = "col-9 px-0">
<input class="inginput border-dark text-light dark-5 rounded scaled-font form-control form-control-sm" list="ing-choices-5" id="ing-choice-5" name="ing-choice-5" placeholder="No Ingredient" />
<input class="inginput border-dark text-light dark-10 rounded scaled-font form-control form-control-sm" list="ing-choices-5" id="ing-choice-5" name="ing-choice-5" placeholder="No Ingredient" />
<datalist id="ing-choices-5">
</datalist>
</div>
@ -196,7 +196,7 @@
<p class = "mb-0 scaled-font fw-bold">Ing 6:</p>
</div>
<div class = "col-9 px-0">
<input class="inginput border-dark text-light dark-5 rounded scaled-font form-control form-control-sm" list="ing-choices-6" id="ing-choice-6" name="ing-choice-6" placeholder="No Ingredient" />
<input class="inginput border-dark text-light dark-10 rounded scaled-font form-control form-control-sm" list="ing-choices-6" id="ing-choice-6" name="ing-choice-6" placeholder="No Ingredient" />
<datalist id="ing-choices-6">
</datalist>
</div>
@ -204,23 +204,23 @@
</div>
</div>
<div class = "row rounded dark-shadow dark-6 py-2">
<div class = "col">
<button class = "button rounded scaled-font fw-bold text-light dark-5" id = "craft-button" onclick = "calculateCraft()">
Craft Item
</button>
</div>
<div class = "col">
<div class = "row rounded dark-shadow dark-6 py-2 gy-3">
<div class = "col-lg-2 col-sm-6">
<button class = "button rounded scaled-font fw-bold text-light dark-5" id = "reset-button" onclick = "resetFields()">
Reset
</button>
</div>
<div class = "col">
<div class = "col-lg-3 col-sm-6">
<button class = "button rounded scaled-font fw-bold text-light dark-5" id = "copy-hash-button" onclick = "copyRecipeHash()">
Copy Hash
</button>
</div>
<div class = "col-lg-4 col-sm-6">
<button class = "button rounded scaled-font fw-bold text-light dark-5" id = "copy-button" onclick = "copyRecipe()">
Copy Short
</button>
</div>
<div class = "col">
<div class = "col-lg-3 col-sm-6">
<button class = "button rounded scaled-font fw-bold text-light dark-5" id = "share-button" onclick = "shareRecipe()">
Copy Long
</button>

85
css/dev.css Normal file
View file

@ -0,0 +1,85 @@
/* General Styling - used for all elements on /dev/ */
.row > * {
margin-bottom: 0.75rem;
margin-left: 0.5rem;
padding-left: 0 !important; /*Override grid.scss (bs) */
}
.row {
overflow-wrap: break-word;
}
.section {
margin-top: 1rem;
margin-bottom: 1rem;
margin-left: 0.5rem;
margin-right: 0.5rem;
border-left: 3px solid white;
border-radius: 0.1rem;
/* padding-right: 0rem !important;
padding-left: 0rem !important; */
}
.section-title:hover{
font-weight: bold;
}
.section-title {
margin-bottom: 1.5rem;;
}
ul {
/*Needed to override <ul> style in sq2bs.css*/
list-style-type: circle;
}
.indent {
margin-left: 2rem;
}
/* Math */
math, number {
font-family: 'CMU Serif', 'Cambria Math', 'Times New Roman', serif;
}
number {
color: rgb(17, 234, 9);
}
.full-width {
width: 100%;
text-align: center;
}
/* Variable Sizing (specific to dev page) */
@media screen and (max-width: 600px) {
.section-title > * {
font-size: 3.5rem;
}
.page-title {
font-size: 6rem;
}
}
@media screen and (min-width: 600px) and (max-width: 1400px) {
.section-title > * {
font-size: 1.25rem;
}
.page-title {
font-size: 4rem;
}
}
@media screen and (min-width: 1400px) {
.section-title > *{
font-size: 1.5rem;
}
.page-title {
font-size: 4.5rem;
}
}

View file

@ -358,6 +358,10 @@ input.equipment-input {
background-color: hsl(0, 0%, 16%) !important;
}
.dark-10 {
background-color: hsl(0, 0%, 20%) !important;
}
.dark-1u {
background-color: hsl(0, 0%, 5%);
}
@ -430,3 +434,17 @@ input[type=number]::-webkit-outer-spin-button {
-moz-appearance: none;
appearance: none;
}
/* Make links bold when hovered over */
.clickable:hover {
font-weight: bold;
}
a:hover {
font-weight: bold;
}
.button {
border-color: #fff;
}

View file

@ -34,6 +34,7 @@ Wynn-Related CSS
}
/* Tier Colors */
.Normal {
@ -132,6 +133,10 @@ Wynn-Related CSS
/* Damages */
.base_dps:before { /* Little Dagger icon */
content: "\1F5E1";
}
.Damage {
color: rgb(255, 198, 85)
}

903
dev/index.html Normal file
View file

@ -0,0 +1,903 @@
<!DOCTYPE html>
<html scroll-behavior="smooth">
<head>
<title>WynnBuilder Dev</title>
<link rel="icon" href="../media/icons/new/atlas64.png">
<link rel="manifest" href="manifest.json">
<meta name="viewport" content="width=device-width, initial-scale=.45, user-scalable=no">
<!-- nunito font, copying wynnbuilder, which is copying wynndata -->
<link rel="preconnect" href="https://fonts.googleapis.com">
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
<link href="https://fonts.googleapis.com/css2?family=Nunito&display=swap" rel="stylesheet">
<link href="https://fonts.googleapis.com/css2?family=Nunito&display=swap" rel="stylesheet">
<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.1.3/dist/css/bootstrap.min.css" rel="stylesheet"
integrity="sha384-1BmE4kWBq78iYhFldvKuhfTAU6auU8tT94WrHftjDbrCEXSU1oBoqyl2QvZ6jIW3" crossorigin="anonymous">
<link rel="stylesheet"
href="https://cdn.jsdelivr.net/npm/@tarekraafat/autocomplete.js@10.2.6/dist/css/autoComplete.min.css">
<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/dev.css">
</head>
<body id="body" class="all" style="overflow-y: scroll">
<div id="main-sidebar" class="sidebar dark-7 dark-shadow">
<a href="../builder/"><img src="../media/icons/new/builder.png" alt="WynnBuilder"
title="WynnBuilder"><b>WynnBuilder</b></a>
<a href="../crafter/"><img src="../media/icons/new/crafter.png" alt="WynnCrafter"
title="WynnCrafter"><b>WynnCrafter</b></a>
<a href="../items/"><img src="../media/icons/new/searcher.png" alt="WynnAtlas"
title="WynnAtlas"><b>WynnAtlas</b></a>
<a href="../custom/"><img src="../media/icons/new/custom.png" alt="WynnCustom"
title="WynnCustom"><b>WynnCustom</b></a>
<a href="../map/"><img src="../media/icons/new/compass.png" alt="WynnGPS" title="WynnGPS"><b>WynnGPS</b></a>
<a href="../wynnfo/"><img src="../media/icons/new/book.png" alt="Wynnfo"
title="WynnCrafter"><b>WynnCrafter</b></a>
<a href="" onclick="toggleIcons()"><img src="../media/icons/new/reload.png" alt=""
title="Swap items on page"><b>Swap Icon Style</b></a>
<hr />
</div>
<div class="container text-light px-5 scaled-font">
<div class="row justify-content-center page-title">
Wynnbuilder Developer Page
</div>
<div class="row">
Welcome to the Wynnbuilder page for developers! Here we provide documentation and specifications for our
website. Read through these sections to learn more about how WynnBuilder works!
</div>
<div class="row section" title="Decoding WynnBuilder links">
<p>
This section is about the encoding schemes Wynnbuilder uses for its various saveable items (builds,
crafted items, and custom items).
</p>
<p>
We use a Base 64 (B64) encode/decode system in most shareable links. It would be quite clunky to put a
bunch of numbers (the data we save and read) into one link. To save some space, we compress the
base 10 numerical alphabet into a custom B64 alphabet.
</p>
<div class="row section" title="WB Base 64 (B64)">
<p>
The Wynnbuilder B64 character table:
</p>
<pre class="full-width">
0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz+-
^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^
| | | | | | | | | | | | |
0 5 10 15 20 25 30 35 40 45 50 55 60 </pre>
<p>
The B64 encoding of a number (in the 0 to 63 range) is equal to the character at the index
within the above string.
</p>
<p>
For example, if we have a set of items with id numbers in the range [<number>0</number>,
<number>10000</number>], we need at most 3 B64 characters to encode any of these items
in the link! The item of id <number>1337</number> corresponds to the B64 hash <code>0Kv</code>:
<math>1337 = 0 * 4096 + 20 * 64 + 57</math>, <number>0</number> maps to <code>0</code>,
<number>20</number> maps to <code>K</code>, and <number>57</number> maps to <code>v</code>.
</p>
<p>
Decoding is a little different. We can either interpret the B64 string as a <b>signed</b> or <b>unsigned</b> number (signed: using 2s complement binary).
</p>
<p>
Things that should be interpreted as <b>signed</b> are:
</p>
<ul class = "indent">
<li>Skill Points</li>
<li>Any numerical identification value for custom items</li>
</ul>
<p>
Things that should be interpreted as <b>unsigned</b> are:
</p>
<ul class = "indent">
<li>Item ID numbers</li>
<li>Tome ID numbers</li>
<li>Build Level</li>
<li>Ingredient ID numbers</li>
<li>Recipe ID numbers</li>
<li>Powder numbers</li>
</ul>
</div>
<p>
Now that we understand the B64 system, we can move on to the way builds, crafted items, and custom items are stored in links.
</p>
<div class="row section" title="Builds">
<p>
First, what do we need in order to encode an entire build?
</p>
<p>
Wynnbuilder mainly runs calculations for damages and defense. Therefore, we need:
</p>
<ul class="indent">
<li>The build's items (equipment, tomes)</li>
<li>The skill points distributed by the user (and user level)</li>
<li>Item powderings</li>
</ul>
<p>
Wynnbuilder assigns each item in the Wynncraft item pool to a unique ID number.
<!-- For example, the bracelet <b class="atlas">Atlas</b>
has an id number of <number>167</number>. We can then store all of a build's item pool items in a link with the items' id numbers. A
similar idea is used for skill points and powders. However, we know how many different skills there are already (5), so we can encode
the user's assignment of skill points in 5 numbers. With powders, it's a little different. There are 31 "states" of powder: 1 for no
powder and then 5 elements with 6 tiers of powder for each element. We will know how many available powder slots we have based on our
equipment. We can then put all of these numbers in a specific order (after running B64 encoding) to get our build link. -->
</p>
<div class = "row section" title = "ID number specifics">
<p>
For items, you can download the item DB here: <a href = "../clean.json" target = "_blank">clean.json</a>. Each item has an id value that can be put in a map. The NoneItem ID numbers start at 10000 in the canonical order: [helmet, chestplate, leggings, boots, ring 1, ring 2, bracelet, necklace, weapon] (No Weapon has an id of 10008).
</p>
<p>
For tomes, you can download the tome DB here: <a href = "../tome_map.json" target = "_blank">tome_map.json</a>. The NoneTome ID numbers start at 61 in the order [no weapon tome, no armor tome, no guild tome] so that we can store tome IDs in 1 B64 character.
</p>
<p>
For powders: id numbers <number>1</number> through <number>30</number> map to Earth I, Earth II, ..., Earth VI,
etc. in the order Earth, Thunder, Water, Fire, Air. 0 is the id number for no powder.
</p>
</div>
<p>
All build links will end in "#[version number]_[build hash]".
</p>
<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.
</p>
<div class = "row section" title = "Example 1: With Tomes">
<code class="full-width">
https://hppeng-wynn.github.io/builder/#6_06W2SH0D40Qq2SK2SL02d0og0Qi191V-E0i2C1g0000100nZ6ZU6FCDo
</code>
<p>
Build hash format:
</p>
<ul class = "indent">
<li>
<number>9</number> items from <code>idMap</code> (<number>3</number> B64 characters each):
<code>06W</code>,
<code>2SH</code>,
<code>0D4</code>,
<code>0Qq</code>,
<code>2SK</code>,
<code>2SL</code>,
<code>02d</code>,
<code>0og</code>,
<code>0Qi</code>
</li>
<li>
<number>5</number> skill point totals (<number>2</number> B64 characters each):
<code>19</code>,
<code>1V</code>,
<code>-E</code>,
<code>0i</code>,
<code>2C</code>
</li>
<li>
<number>1</number> player level (<number>2</number> B64 characters):
<code>1g</code>
</li>
<li>
A <b>variable</b> number of powder "blocks" (<number>5</number> B64 characters which give us <number>6</number> powders per block).
<ul class = "indent">
<li>For each of the 5 powderable equipment fields [helmet, chestplate, leggings, boots, weapon], we will have the following:</li>
<li><number>1</number> B64 character that says that we need <number>n</number> blocks for this item.</li>
<li><number>n</number> blocks of <number>5</number> B64 characters.</li>
<li>
Since there are 4 <code>0</code>s (B64 0 = 0 unsigned) in this example, we have no powders on any of the armor piece (no blocks).
</li>
<li>
Then, we have <code>1</code> (B64 1 = 1 unsigned). There is 1 block of powders to decode for the weapon item. That is <code>00nZ6</code>.
</li>
<ul class = "indent">
<li>The unsigned equivalent of <code>00nZ6</code> in binary is 30 <b>binary</b> bits long (omitted). Each section of 5 bits directly corresponds to an powder ID.</li>
</ul>
</ul>
</li>
<li>
<number>7</number> tomes (<number>1</number> character each):
<code>ZU6FCDo</code>
<ul class = "indent">
<li>The order of tomes listed is [2x weapon tome, 4x armor tome, 1x guild tome].</li>
</ul>
</li>
</ul>
</div>
</div>
<div class="row section" title="Version 5">
<p>
Version 5 was made to allow for the ability to save custom items. To learn the specifics about custom item encoding, refer to the Custom Items section.
</p>
<p>
As of the last version of this documentation, version 5 is only used for encoding when there are custom items (and no tomes) in the build.
</p>
<div class = "row section" title = "Example 1: With Custom Item">
<code class = "full-width">
https://hppeng-wynn.github.io/builder/#5_06W00mCI-10000JCustom%20Chestplate0220510G020Fe0M0201a0D40Qq2SK2SL02d0og0Qi191V-E0i2C1g0000100nZ6zz++++-
</code>
<p>
Build Hash format:
</p>
<ul class = "indent">
<li>
<number>9</number> items from <code>idMap</code> (<number>3</number> B64 characters each):
<code>06W</code>,
<code>00m</code> (with the custom item <code>CI-10000JCustom%20Chestplate0220510G020Fe0M0201a</code>),
<code>0D4</code>,
<code>0Qq</code>,
<code>2SK</code>,
<code>2SL</code>,
<code>02d</code>,
<code>0og</code>,
<code>0Qi</code>
<ul class = "indent">
<li>Starting in this version, to encode a custom item we substitute in the length of the full hash of a custom item ("CI-[gibberish]") in <number>3</number> B64 characters for the item ID, followed by the full hash.</li>
<li>When decoding build links of this version or higher, you must check whether or not the 3 characters after the current item are "CI-". If they are, the current 3 characters are the B64 representation of the unsigned length of the custom item hash (<math>n</math>), in characters. Then the next <math>n</math> characters make up the full custom item hash.</li>
<li>No existing item has an item ID of "CI-" in B64, so we can define a special case check for this "id number".</li>
<li>Further details on parsing and loading this custom item are in the Custom Item section.</li>
</ul>
</li>
<li>
<number>5</number> skill point totals (<number>2</number> B64 characters each):
<code>19</code>,
<code>1V</code>,
<code>-E</code>,
<code>0i</code>,
<code>2C</code>
</li>
<li>
<number>1</number> player level (<number>2</number> B64 characters):
<code>1g</code>
</li>
<li>
A <b>variable</b> number of powder "blocks" (<number>5</number> B64 characters which give us <number>6</number> powders per block).
<ul class = "indent">
<li>For each of the 5 powderable equipment fields [helmet, chestplate, leggings, boots, weapon], we will have the following:</li>
<li><number>1</number> B64 character that says that we need <number>n</number> blocks for this item.</li>
<li><number>n</number> blocks of <number>5</number> B64 characters.</li>
<li>
Since there are 4 <code>0</code>s (B64 0 = 0 unsigned) in this example, we have no powders on any of the armor piece (no blocks).
</li>
<li>
Then, we have <code>1</code> (B64 1 = 1 unsigned). There is 1 block of powders to decode for the weapon item. That is <code>00nZ6</code>.
</li>
<ul class = "indent">
<li>The unsigned equivalent of <code>00nZ6</code> in binary is 30 <b>binary</b> bits long (omitted). Each section of 5 bits directly corresponds to an powder ID.</li>
</ul>
</ul>
</li>
</ul>
</div>
<p>
It is possible that version 5 links will have an extra tome section at the end like above (see: Version 6 section). We ignore this in decoding.
</p>
</div>
<div class="row section" title="Version 4">
<p>
Version 4 was made to allow for the ability to save crafted items. To learn the specifics about crafted item encoding, refer to the Crafted Items section.
</p>
<p>
As of the last version of this documentation, version 4 is the default version and is used when there are no custom items or tomes in the build.
</p>
<div class = "row section" title = "Example 1: No Crafted Items">
<code class = "full-width">
https://hppeng-wynn.github.io/builder/#4_06W2SH0D40Qq2SK2SL02d0og0Qi191V-E0i2C1g0000100nZ6zz++++-
</code>
<p>
Build Hash format:
</p>
<ul class = "indent">
<li>
<number>9</number> items from <code>idMap</code> (<number>3</number> N64 characters each):
<code>06W</code>,
<code>2SH</code>,
<code>0D4</code>,
<code>0Qq</code>,
<code>2SK</code>,
<code>2SL</code>,
<code>02d</code>,
<code>0og</code>,
<code>0Qi</code>
</li>
<li>
<number>5</number> skill point totals (<number>2</number> B64 characters each):
<code>19</code>,
<code>1V</code>,
<code>-E</code>,
<code>0i</code>,
<code>2C</code>
</li>
<li>
<number>1</number> player level (<number>2</number> B64 characters):
<code>1g</code>
</li>
<li>
A <b>variable</b> number of powder "blocks" (<number>5</number> B64 characters which give us <number>6</number> powders per block).
<ul class = "indent">
<li>For each of the 5 powderable equipment fields [helmet, chestplate, leggings, boots, weapon], we will have the following:</li>
<li><number>1</number> B64 character that says that we need <number>n</number> blocks for this item.</li>
<li><number>n</number> blocks of <number>5</number> B64 characters.</li>
<li>
Since there are 4 <code>0</code>s (B64 0 = 0 unsigned) in this example, we have no powders on any of the armor piece (no blocks).
</li>
<li>
Then, we have <code>1</code> (B64 1 = 1 unsigned). There is 1 block of powders to decode for the weapon item. That is <code>00nZ6</code>.
</li>
<ul class = "indent">
<li>The unsigned equivalent of <code>00nZ6</code> in binary is 30 <b>binary</b> bits long (omitted). Each section of 5 bits directly corresponds to an powder ID.</li>
</ul>
</ul>
</li>
</ul>
</div>
<div class = "row section" title = "Example 2: With Crafted Items">
<code class = "full-width">
https://hppeng-wynn.github.io/builder/#4_06WCR-1628i8v8v94948f210D40Qq2SK2SL02d0og0Qi1Q1V-E0l2C1g0000100nZ6zz++++-
</code>
<p>
Build Hash format:
</p>
<ul class = "indent">
<li>
<number>9</number> items from <code>idMap</code> (<number>3</number> B64 characters each):
<code>06W</code>,
<code>CR-1628i8v8v94948f21</code>,
<code>0D4</code>,
<code>0Qq</code>,
<code>2SK</code>,
<code>2SL</code>,
<code>02d</code>,
<code>0og</code>,
<code>0Qi</code>
<ul class = "indent">
<li>Starting in this version, you can substitute in the full hash of a crafted item ("CR-[gibberish]") for the 3-character hash of an item pool item.</li>
<li>The way we can tell that an item is a crafted item is when the 3-character hash of the 'item' is "CR-". No existing item has an item ID of "CR-" in B64, so we can define a special case check for this "id number".</li>
<li>Further details on parsing and loading this custom item are in the Crafted Item section.</li>
</ul>
</li>
<li>
<number>5</number> skill point totals (<number>2</number> B64 characters each):
<code>19</code>,
<code>1V</code>,
<code>-E</code>,
<code>0i</code>,
<code>2C</code>
</li>
<li>
<number>1</number> player level (<number>2</number> B64 characters):
<code>1g</code>
</li>
<li>
A <b>variable</b> number of powder "blocks" (<number>5</number> B64 characters which give us <number>6</number> powders per block).
<ul class = "indent">
<li>For each of the 5 powderable equipment fields [helmet, chestplate, leggings, boots, weapon], we will have the following:</li>
<li><number>1</number> B64 character that says that we need <number>n</number> blocks for this item.</li>
<li><number>n</number> blocks of <number>5</number> B64 characters.</li>
<li>
Since there are 4 <code>0</code>s (B64 0 = 0 unsigned) in this example, we have no powders on any of the armor piece (no blocks).
</li>
<li>
Then, we have <code>1</code> (B64 1 = 1 unsigned). There is 1 block of powders to decode for the weapon item. That is <code>00nZ6</code>.
</li>
<ul class = "indent">
<li>The unsigned equivalent of <code>00nZ6</code> in binary is 30 <b>binary</b> bits long (omitted). Each section of 5 bits directly corresponds to an powder ID.</li>
</ul>
</ul>
</li>
</ul>
</div>
<p>
It is possible that version 4 links will have an extra tome string like above (see: Version 6 section) after the powders. You can ignore this in decoding.
</p>
</div>
<div class="row section" title="Version 3">
<p>
Version 3 encoding added the ability to save build level.
</p>
<div class = "row section" title = "Example">
<code class="full-width">
https://hppeng-wynn.github.io/builder/#3_06W2SH0D40Qq2SK2SL02d0og0Qi191V-E0i2C1g0000100nZ6
</code>
<p>
Build hash format:
</p>
<ul class = "indent">
<li>
<number>9</number> items from <code>idMap</code> (<number>3</number> B64 characters each):
<code>06W</code>,
<code>2SH</code>,
<code>0D4</code>,
<code>0Qq</code>,
<code>2SK</code>,
<code>2SL</code>,
<code>02d</code>,
<code>0og</code>,
<code>0Qi</code>
</li>
<li>
<number>5</number> skill point totals (<number>2</number> B64 characters each):
<code>19</code>,
<code>1V</code>,
<code>-E</code>,
<code>0i</code>,
<code>2C</code>
</li>
<li>
<number>1</number> player level (<number>2</number> B64 characters):
<code>1g</code>
</li>
<li>
A <b>variable</b> number of powder "blocks" (<number>5</number> B64 characters which give us <number>6</number> powders per block).
<ul class = "indent">
<li>For each of the 5 powderable equipment fields [helmet, chestplate, leggings, boots, weapon], we will have the following:</li>
<li><number>1</number> B64 character that says that we need <number>n</number> blocks for this item.</li>
<li><number>n</number> blocks of <number>5</number> B64 characters.</li>
<li>
Since there are 4 <code>0</code>s (B64 0 = 0 unsigned) in this example, we have no powders on any of the armor piece (no blocks).
</li>
<li>
Then, we have <code>1</code> (B64 1 = 1 unsigned). There is 1 block of powders to decode for the weapon item. That is <code>00nZ6</code>.
</li>
<ul class = "indent">
<li>The unsigned equivalent of <code>00nZ6</code> in binary is 30 <b>binary</b> bits long (omitted). Each section of 5 bits directly corresponds to an powder ID.</li>
</ul>
</ul>
</li>
</ul>
</div>
</div>
<div class="row section" title="Version 2">
<p>
Version 2 encoding added the ability to save skill point info.
</p>
<div class = "row section" title = "Example">
<code class="full-width">
https://hppeng-wynn.github.io/builder/#2_06W2SH0D40Qq2SK2SL02d0og0Qi191V-E0i2C0000100nZ6
</code>
<p>
Build hash format:
</p>
<ul class = "indent">
<li>
<number>9</number> items from <code>idMap</code> (<number>3</number> B64 characters each):
<code>06W</code>,
<code>2SH</code>,
<code>0D4</code>,
<code>0Qq</code>,
<code>2SK</code>,
<code>2SL</code>,
<code>02d</code>,
<code>0og</code>,
<code>0Qi</code>
</li>
<li>
<number>5</number> skill point totals (<number>2</number> B64 characters each):
<code>19</code>,
<code>1V</code>,
<code>-E</code>,
<code>0i</code>,
<code>2C</code>
</li>
<li>
A <b>variable</b> number of powder "blocks" (<number>5</number> B64 characters which give us <number>6</number> powders per block).
<ul class = "indent">
<li>For each of the 5 powderable equipment fields [helmet, chestplate, leggings, boots, weapon], we will have the following:</li>
<li><number>1</number> B64 character that says that we need <number>n</number> blocks for this item.</li>
<li><number>n</number> blocks of <number>5</number> B64 characters.</li>
<li>
Since there are 4 <code>0</code>s (B64 0 = 0 unsigned) in this example, we have no powders on any of the armor piece (no blocks).
</li>
<li>
Then, we have <code>1</code> (B64 1 = 1 unsigned). There is 1 block of powders to decode for the weapon item. That is <code>00nZ6</code>.
</li>
<ul class = "indent">
<li>The unsigned equivalent of <code>00nZ6</code> in binary is 30 <b>binary</b> bits long (omitted). Each section of 5 bits directly corresponds to an powder ID.</li>
</ul>
</ul>
</li>
</ul>
</div>
</div>
<div class="row section" title="Version 1">
<p>
Version 1 is the very first encoding version by Wynnbuilder. It allows for saving all equipment (armors, accessories, weapon) and powders put on that equipment.
</p>
<div class = "row section" title = "Example">
<code class="full-width">
https://hppeng-wynn.github.io/builder/#1_06W2SH0D40Qq2SK2SL02d0og0Qi0000100nZ6
</code>
<p>
Build hash format:
</p>
<ul class = "indent">
<li>
<number>9</number> items from <code>idMap</code> (<number>3</number> B64 characters each):
<code>06W</code>,
<code>2SH</code>,
<code>0D4</code>,
<code>0Qq</code>,
<code>2SK</code>,
<code>2SL</code>,
<code>02d</code>,
<code>0og</code>,
<code>0Qi</code>
</li>
<li>
A <b>variable</b> number of powder "blocks" (<number>5</number> B64 characters which give us <number>6</number> powders per block).
<ul class = "indent">
<li>For each of the 5 powderable equipment fields [helmet, chestplate, leggings, boots, weapon], we will have the following:</li>
<li><number>1</number> B64 character that says that we need <number>n</number> blocks for this item.</li>
<li><number>n</number> blocks of <number>5</number> B64 characters.</li>
<li>
Since there are 4 <code>0</code>s (B64 0 = 0 unsigned) in this example, we have no powders on any of the armor piece (no blocks).
</li>
<li>
Then, we have <code>1</code> (B64 1 = 1 unsigned). There is 1 block of powders to decode for the weapon item. That is <code>00nZ6</code>.
</li>
<ul class = "indent">
<li>The unsigned equivalent of <code>00nZ6</code> in binary is 30 <b>binary</b> bits long (omitted). Each section of 5 bits directly corresponds to an powder ID.</li>
</ul>
</ul>
</li>
</ul>
</div>
</div>
</div>
<div class="row section" title="Crafted Items">
<p>
This section is about how to decode crafted items. To view an example of a crafted item in a build, check out <b>Builds > Version 4</b>.
</p>
<p>
Crafted items always start with "CR-" so that they are, as an entire category, distinguishable from item pool items. The ingredients and materials that make up the crafted item are stored in the rest of the "hash".
</p>
<p>
To encode all the info about a crafted item, we need:
</p>
<ul class = "indent">
<li>Ingredient Data</li>
<li>Recipe Data</li>
<li>Crafting Material Tiers</li>
<li>Attack Speed (for weapons)</li>
</ul>
<p>
Wynnbuilder assigns each ingredient and recipe to a unique ID number.
</p>
<div class = "row section" title = "ID number specifics">
<p>
For ingredients, you can download the ingredient id map here: <a href = "../ing_map.json" target = "_blank">ing_map.json</a>. The ID number for No Ingredient is 4000.
</p>
<p>
For recipes, you can download the recipe id map here: <a href = "../recipe_map.json" target = "_blank">recipe_map.json</a> or the recipe DB here: <a href = "recipes_clean.json" target = "_blank">recipes_clean.json</a>.
</p>
</div>
<div class = "row section" title = "Version 1">
<p>
This is the first version of crafted item encoding. Crafted Items are always stored in a constant number of B64 characters.
</p>
<div class = "row section" title = "Example - Crafted Item">
<p>
This example shows how to parse a crafted item hash.
</p>
<code class = "full-width">
CR-1628i8v8v94948f21
</code>
<p>
Crafted item hash format:
</p>
<ul class = "indent">
<li><number>3</number> characters to denote item type as crafted: <code>CR-</code> (always)</li>
<li><number>1</number> character for encoding version: <code>1</code> </li>
<li><number>6</number> ingredient IDs (<number>2</number> B64 characters each):
<code>62</code>,
<code>8i</code>,
<code>8v</code>,
<code>8v</code>,
<code>94</code>,
<code>94</code>
</li>
<li><number>2</number> B64 characters for recipe ID: <code>8f</code></li>
<li><number>1</number> character to encode material tiers: <code>2</code>
<ul class = "indent">
<li>There are 2 material tiers to decode. The ordering of materials is determined by their order within the corresponding recipe object held in the db.</li>
<li>The material tier character (from here on <math>t</math>) is in the range [<number>1</number>, <number>9</number>]. </li>
<li>Mat 1's tier is equal to <math>t % 3</math> except when this yields 0, in which case it becomes 3.</li>
<li>Mat 2's tier is equal to ceil(<math> (t - 0.5) / 3</math>).</li>
</ul>
</li>
<li><number>1</number> character to encode attack speed: <code>1</code>
<ul class = "indent">
<li>The integer after doing unsigned decoding from the B64 character denotes the index within the following array: [SLOW, NORMAL, FAST]. B64 <code>1</code> maps to the unsigned integer <number>1</number>, meaning that the attack speed of this crafted item would be NORMAL if it were a weapon.</li>
<li>Note: although only weapons will have attack speed, we decided to include the character in all crafted item hashes to keep a constant hash length.</li>
</ul>
</li>
</ul>
<p>
You may need to parse a crafted item from a wynnbuilder crafter link.
</p>
<code class = "full-width">
https://hppeng-wynn.github.io/crafter/#1628i8v8v94948f21
</code>
<p>
We can simply take the string after the octothorpe/hash tag (#), tack on "CR-" in front of this string, and arrive at the full hash for the crafted item in question. Decode using the same logic as the previous example.
</p>
</div>
</div>
</div>
<div class="row section" title="Custom Items">
<p>
This section is about how to decode custom items. To view an example of a custom item in a build, check out <b>Builds > Version 5</b>.
</p>
<p>
Custom items always start with "CI-" so that they are, as an entire category, distinguishable from item pool items. The stats and values that make up the custom item are stored in the rest of the "hash".
</p>
<div class = "row section" title = "Version 1">
<p>This is the first version of custom item encoding and decoding.</p>
<p>You will need the full array of item identification saving order and all non-rolled identifications (ex: name). View them below.</p>
<div class = "row section" title = "Important Arrays">
<p> ID saving order: <code>ci_save_order = ["name", "lore", "tier", "set", "slots", "type", "material", "drop", "quest", "nDam", "fDam", "wDam", "aDam", "tDam", "eDam", "atkSpd", "hp", "fDef", "wDef", "aDef", "tDef", "eDef", "lvl", "classReq", "strReq", "dexReq", "intReq", "defReq", "agiReq","str", "dex", "int", "agi", "def", "id", "skillpoints", "reqs", "nDam_", "fDam_", "wDam_", "aDam_", "tDam_", "eDam_", "majorIds", "hprPct", "mr", "sdPct", "mdPct", "ls", "ms", "xpb", "lb", "ref", "thorns", "expd", "spd", "atkTier", "poison", "hpBonus", "spRegen", "eSteal", "hprRaw", "sdRaw", "mdRaw", "fDamPct", "wDamPct", "aDamPct", "tDamPct", "eDamPct", "fDefPct", "wDefPct", "aDefPct", "tDefPct", "eDefPct", "spPct1", "spRaw1", "spPct2", "spRaw2", "spPct3", "spRaw3", "spPct4", "spRaw4", "rainbowRaw", "sprint", "sprintReg", "jh", "lq", "gXp", "gSpd","durability","duration","charges"];</code> </p>
<p> Non-rolled string IDs: <code>nonRolled_strings = ["name", "lore", "tier", "set", "type", "material", "drop", "quest", "majorIds", "classReq", "atkSpd", "displayName", "nDam", "fDam", "wDam", "aDam", "tDam", "eDam", "nDam_", "fDam_", "wDam_", "aDam_", "tDam_", "eDam_", "durability", "duration"];</code></p>
<p> Rolled IDs: <code>rolledIDs = ["hprPct", "mr", "sdPct", "mdPct", "ls", "ms", "xpb", "lb", "ref", "thorns", "expd", "spd", "atkTier", "poison", "hpBonus", "spRegen", "eSteal", "hprRaw", "sdRaw", "mdRaw", "fDamPct", "wDamPct", "aDamPct", "tDamPct", "eDamPct", "fDefPct", "wDefPct", "aDefPct", "tDefPct", "eDefPct", "spPct1", "spRaw1", "spPct2", "spRaw2", "spPct3", "spRaw3", "spPct4", "spRaw4", "rainbowRaw", "sprint", "sprintReg", "jh", "lq", "gXp", "gSpd"];</code></p>
<p> Non-rolled IDs: <code>nonRolledIDs = ["name", "lore", "displayName", "tier", "set", "slots", "type", "material", "drop", "quest", "restrict", "nDam", "fDam", "wDam", "aDam", "tDam", "eDam", "atkSpd", "hp", "fDef", "wDef", "aDef", "tDef", "eDef", "lvl", "classReq", "strReq", "dexReq", "intReq", "defReq", "agiReq", "str", "dex", "int", "agi", "def", "fixID", "category", "id", "skillpoints", "reqs", "nDam_", "fDam_", "wDam_", "aDam_", "tDam_", "eDam_", "majorIds"];</code></p>
<p> Tiers: <code>tiers = ["Normal", "Unique", "Rare", "Legendary", "Fabled", "Mythic", "Set", "Crafted"]</code></p>
<p> Types: <code>types = [ "helmet", "chestplate", "leggings", "boots", "ring", "bracelet", "necklace", "wand", "spear", "bow", "dagger", "relik", "potion", "scroll", "food"];</code></p>
<p> Attack Speeds: <code>attackSpeeds = ["SUPER_SLOW", "VERY_SLOW", "SLOW", "NORMAL", "FAST", "VERY_FAST", "SUPER_FAST"];</code></p>
<p> Class Requirements: <code>classes = ["Warrior", "Assassin", "Mage", "Archer", "Shaman"]</code> </p>
</div>
<div class = "row section" title = "Example">
<p>
Here's an example of a custom item hash.
</p>
<code class = "full-width">
CI-10000HMeta%20Chestplate010Gbest%20in%20slot0240401030510G0302SG0H020Fe0I020Fe0J020Fe0K020Fe0L020Fe0M0201Y0i0200U220z0204iKK150200U22160200U22170200U22180200U22190200U22
</code>
<p>
Given a custom item hash, we will in general continue to parse through many identifications and their values until we reach the end of the custom item hash.
</p>
<p>
Custom item hash format:
</p>
<ul class = "indent">
<li><number>1</number> B64 character denoting encoding/decoding version number: <code>1</code></li>
<li><number>1</number> character denoting whether or not this item has fixed IDs: <code>0</code>. (0 for no fixed IDs, 1 for fixed IDs)</li>
<li>A series of encoded identifications, each taking a variable number of characters. For every ID, we have to save:
<ul class = "indent">
<li><number>2</number> B64 characters that represent the identification ID (its index in the CI save order array). </li>
<li><number>2</number> B64 characters that represent the length <math>len</math> of the value of the identification.</li>
<li>A variable number characters to encode the value of the identification.
<li>For string-valued identifications (in the non-rolled strings array), we do not use any encoding for the value. The next <number>len</number> characters of the custom item hash is the raw value of the identification (before substituting space for "%20").
<ul class = "indent">
<li>Exception: for the identifications <code>tier</code>, <code>type</code>, <code>atkSpd</code>, and <code>classReq</code>, there is no string used. They are encoded as a numerical value representing an index in a pre-defined array (check the Important Arrays section above). They also do not use the earlier-specified 2 characters to store length; instead, they each use only 1 B64 character to store their index in their corresponding arrays.</li>
</ul>
</li>
<li>For numerical-valued identifications, encoding depends on the fixed ID value from before.
<ul class = "indent">
<li>Rolled IDs (with non-fixed IDs):
<ul class = "indent">
<li><number>1</number> character to denote the sign of the min and max values: 0 for both positive, 1 for negative min and positive max, 2 for positive min and negative max, and 3 for both negative.</li>
<li><number>len</number> B64 characters that represent the unsigned <b>minimum</b> value of the identification.</li>
<li><number>len</number> B64 characters that represent the unsigned <b>maximum</b> value of the identification.</li>
</ul>
</li>
<li>Rolled IDs (with fixed IDs) and Non-Rolled IDs:
<ul class = "indent">
<li><number>1</number> character (binary bit) to denote the sign of the value (0 positive, 1 negative).</li>
<li><number>len</number> B64 characters that represent the unsigned value of the identification.</li>
</ul>
</li>
</ul>
</li>
</li>
</ul>
</li>
<li>To finish the example, we'll go through all the actual identifications of the provided custom item.
<ul class = "indent">
<li>"CI-" constant portion</li>
<li>Encoding version number: <code>1</code></li>
<li>Fixed IDs: <code>0</code> (non-fixed IDs)</li>
<li><code>000HMeta%20Chestplate</code>
<ul class = "indent">
<li>ID name: <code>00</code> ("name")</li>
<li>ID value length: <code>0H</code> (<number>17</number>)</li>
<li>ID value: <code>Meta%20Chestplate</code> ("Meta Chestplate")</li>
</ul>
</li>
<li><code>010Gbest%20in%20slot</code>
<ul class = "indent">
<li>ID name: <code>01</code> ("lore")</li>
<li>ID value length: <code>0G</code> (<number>16</number>)</li>
<li>ID value: <code>best%20in%20slot</code> ("best in slot")</li>
</ul>
</li>
<li><code>024</code>
<ul class = "indent">
<li>ID name: <code>02</code> ("tier")</li>
<li>ID value length: None (exception) </li>
<li>ID value: <code>4</code> (tiers[4] = "Fabled")</li>
</ul>
</li>
<li><code>040103</code>
<ul class = "indent">
<li>ID name: <code>04</code> ("slots")</li>
<li>ID value length: <code>01</code> (<number>1</number>)</li>
<li>ID sign: <code>0</code> (positive)</li>
<li>ID value: <code>3</code> (<number>3</number>)</li>
</ul>
</li>
<li><code>051</code>
<ul class = "indent">
<li>ID name: <code>05</code> ("type")</li>
<li>ID value length: None (exception)</li>
<li>ID value: <code>1</code> (types[1] = "chestplate")</li>
</ul>
</li>
<li><code>0G0302SG</code>
<ul class = "indent">
<li>ID name: <code>0G</code> ("hp")</li>
<li>ID value length: <code>03</code> (<number>3</number>) </li>
<li>ID sign: <code>0</code> (positive)</li>
<li>ID value: <code>2SG</code> (<number>10000</number>)</li>
</ul>
</li>
<li><code>0H020Fe</code>
<ul class = "indent">
<li>ID name: <code>0H</code> ("fDef")</li>
<li>ID value length: <code>02</code> (<number>2</number>) </li>
<li>ID sign: <code>0</code> (positive)</li>
<li>ID value: <code>Fe</code> (<number>1000</number>)</li>
</ul>
</li>
<li><code>0I020Fe</code>
<ul class = "indent">
<li>ID name: <code>0I</code> ("wDef")</li>
<li>ID value length: <code>02</code> (<number>2</number>) </li>
<li>ID sign: <code>0</code> (positive)</li>
<li>ID value: <code>Fe</code> (<number>1000</number>)</li>
</ul>
</li>
<li><code>0J020Fe</code>
<ul class = "indent">
<li>ID name: <code>0J</code> ("aDef")</li>
<li>ID value length: <code>02</code> (<number>2</number>) </li>
<li>ID sign: <code>0</code> (positive)</li>
<li>ID value: <code>Fe</code> (<number>1000</number>)</li>
</ul>
</li>
<li><code>0K020Fe</code>
<ul class = "indent">
<li>ID name: <code>0K</code> ("tDef")</li>
<li>ID value length: <code>02</code> (<number>2</number>) </li>
<li>ID sign: <code>0</code> (positive)</li>
<li>ID value: <code>Fe</code> (<number>1000</number>)</li>
</ul>
</li>
<li><code>0L020Fe</code>
<ul class = "indent">
<li>ID name: <code>0L</code> ("eDef")</li>
<li>ID value length: <code>02</code> (<number>2</number>) </li>
<li>ID sign: <code>0</code> (positive)</li>
<li>ID value: <code>Fe</code> (<number>1000</number>)</li>
</ul>
</li>
<li><code>0M0201Y</code>
<ul class = "indent">
<li>ID name: <code>0M</code> ("lvl")</li>
<li>ID value length: <code>02</code> (<number>2</number>) </li>
<li>ID sign: <code>0</code> (positive)</li>
<li>ID value: <code>1Y</code> (<number>98</number>)</li>
</ul>
</li>
<li><code>0i0200U22</code>
<ul class = "indent">
<li>ID name: <code>0i</code> ("hprPct")</li>
<li>ID value length: <code>02</code> (<number>2</number>) </li>
<li>ID sign: <code>0</code> (both positive)</li>
<li>ID value minimum: <code>0U</code> (<number>30</number>)</li>
<li>ID value maximum: <code>22</code> (<number>130</number>)</li>
</ul>
</li>
<li><code>0z0204iKK</code>
<ul class = "indent">
<li>ID name: <code>0z</code> ("hprRaw")</li>
<li>ID value length: <code>02</code> (<number>2</number>) </li>
<li>ID sign: <code>0</code> (both positive)</li>
<li>ID value minimum: <code>4i</code> (<number>300</number>)</li>
<li>ID value maximum: <code>KK</code> (<number>1300</number>)</li>
</ul>
</li>
<li><code>0z0204iKK</code>
<ul class = "indent">
<li>ID name: <code>0z</code> ("hprRaw")</li>
<li>ID value length: <code>02</code> (<number>2</number>) </li>
<li>ID sign: <code>0</code> (both positive)</li>
<li>ID value minimum: <code>4i</code> (<number>300</number>)</li>
<li>ID value maximum: <code>KK</code> (<number>1300</number>)</li>
</ul>
</li>
<li><code>150200U22</code>
<ul class = "indent">
<li>ID name: <code>15</code> ("fDefPct")</li>
<li>ID value length: <code>02</code> (<number>2</number>) </li>
<li>ID sign: <code>0</code> (both positive)</li>
<li>ID value minimum: <code>0U</code> (<number>30</number>)</li>
<li>ID value maximum: <code>22</code> (<number>130</number>)</li>
</ul>
</li>
<li><code>160200U22</code>
<ul class = "indent">
<li>ID name: <code>16</code> ("wDefPct")</li>
<li>ID value length: <code>02</code> (<number>2</number>) </li>
<li>ID sign: <code>0</code> (both positive)</li>
<li>ID value minimum: <code>0U</code> (<number>30</number>)</li>
<li>ID value maximum: <code>22</code> (<number>130</number>)</li>
</ul>
</li>
<li><code>170200U22</code>
<ul class = "indent">
<li>ID name: <code>17</code> ("aDefPct")</li>
<li>ID value length: <code>02</code> (<number>2</number>) </li>
<li>ID sign: <code>0</code> (both positive)</li>
<li>ID value minimum: <code>0U</code> (<number>30</number>)</li>
<li>ID value maximum: <code>22</code> (<number>130</number>)</li>
</ul>
</li>
<li><code>180200U22</code>
<ul class = "indent">
<li>ID name: <code>18</code> ("tDefPct")</li>
<li>ID value length: <code>02</code> (<number>2</number>) </li>
<li>ID sign: <code>0</code> (both positive)</li>
<li>ID value minimum: <code>0U</code> (<number>30</number>)</li>
<li>ID value maximum: <code>22</code> (<number>130</number>)</li>
</ul>
</li>
<li><code>190200U22</code>
<ul class = "indent">
<li>ID name: <code>19</code> ("eDefPct")</li>
<li>ID value length: <code>02</code> (<number>2</number>) </li>
<li>ID sign: <code>0</code> (both positive)</li>
<li>ID value minimum: <code>0U</code> (<number>30</number>)</li>
<li>ID value maximum: <code>22</code> (<number>130</number>)</li>
</ul>
</li>
</ul>
</li>
</ul>
<!-- TODO -->
<p>
You may need to parse a custom item from a Wynnbuilder customizer link.
</p>
<code class = "full-width">
hppeng-wynn.github.io/custom/#10000HMeta%20Chestplate010Gbest%20in%20slot0240401030510G0302SG0H020Fe0I020Fe0J020Fe0K020Fe0L020Fe0M0201Y0i0200U220z0204iKK150200U22160200U22170200U22180200U22190200U22
</code>
<p>
Similar to crafted items, the part of the link after the "#" is the rest of the custom item after the "CI-" constant portion. You may need to convert all "%20" to spaces manually.
</p>
<p>
Details on reading custom items in build links are provided in the Decoding WB links > Builds section.
</p>
</div>
</div>
</div>
<p>
Last updated: 30 May 2022
</p>
</div>
<!-- <div class="row section" title="Test Section">
</div> -->
</div>
<script type="text/javascript" src="../js/dev.js"></script>
<script type="text/javascript" src="../js/sq2icons.js"></script>
</body>
</html>

View file

@ -28,9 +28,9 @@
<a href = "../builder/"><img src="../media/icons/new/builder.png" alt = "WynnBuilder" title = "WynnBuilder"><b>WynnBuilder</b></a>
<a href = "../crafter/"><img src = "../media/icons/new/crafter.png" alt = "WynnCrafter" title = "WynnCrafter"><b>WynnCrafter</b></a>
<a href = "../items/"><img src = "../media/icons/new/searcher.png" alt = "WynnAtlas" title = "WynnAtlas"><b>WynnAtlas</b></a>
<a href = "/customizer.html"><img src = "../media/icons/new/custom.png" alt = "WynnCustom" title = "WynnCustom"><b>WynnCustom</b></a>
<a href = "/map.html"><img src = "../media/icons/new/compass.png" alt = "WynnGPS" title = "WynnGPS"><b>WynnGPS</b></a>
<a href = "/wynnfo/index.html"><img src = "../media/icons/new/book.png" alt = "Wynnfo" title = "WynnCrafter"><b>WynnCrafter</b></a>
<a href = "../custom/"><img src = "../media/icons/new/custom.png" alt = "WynnCustom" title = "WynnCustom"><b>WynnCustom</b></a>
<a href = "../map/"><img src = "../media/icons/new/compass.png" alt = "WynnGPS" title = "WynnGPS"><b>WynnGPS</b></a>
<a href = "../wynnfo/"><img src = "../media/icons/new/book.png" alt = "Wynnfo" title = "WynnCrafter"><b>WynnCrafter</b></a>
<a onclick = "toggleIcons()"><img src = "../media/icons/new/reload.png" alt = "" title = "Swap items on page"><b>Swap Icon Style</b></a>
<hr/>
</div>
@ -220,6 +220,6 @@
docsFns.append(genDocEntry(entry[0], entry[1], null, entry[2]));
}
</script>
<script type="text/javascript" src="/js/icons.js"></script>
<script type="text/javascript" src="../js/sq2icons.js"></script>
</body>
</html>

View file

@ -116,6 +116,18 @@ function toggle_tab(tab) {
}
}
// toggle spell arrow
function toggle_spell_tab(tab) {
let arrow_img = document.querySelector("#" + "arrow_" + tab + "Avg");
if (document.querySelector("#"+tab).style.display == "none") {
document.querySelector("#"+tab).style.display = "";
arrow_img.src = arrow_img.src.replace("down", "up");
} else {
document.querySelector("#"+tab).style.display = "none";
arrow_img.src = arrow_img.src.replace("up", "down");
}
}
let tabs = ['overall-stats', 'offensive-stats', 'defensive-stats'];
function show_tab(tab) {

View file

@ -223,6 +223,15 @@ document.addEventListener('DOMContentLoaded', function() {
console.log("Set up graph");
// Other "main" stuff
// TODO: consolidate and comment
// Spell dropdowns
for (const i of spell_disp) {
document.querySelector("#"+i+"Avg").addEventListener("click", () => toggle_spell_tab(i));
}
// Masonry setup
let masonry = Macy({
container: "#masonry-container",
columns: 1,

View file

@ -12,7 +12,6 @@ class ComputeNode {
this.value = null;
this.name = name;
this.update_task = null;
this.update_time = Date.now();
this.fail_cb = false; // Set to true to force updates even if parent failed.
this.dirty = true;
this.inputs_dirty = new Map();
@ -22,12 +21,10 @@ class ComputeNode {
/**
* Request update of this compute node. Pushes updates to children.
*/
update(timestamp) {
if (timestamp <= this.update_time) {
update() {
if (!this.dirty) {
return;
}
this.update_time = timestamp;
if (this.inputs_dirty_count != 0) {
return;
}
@ -38,21 +35,21 @@ class ComputeNode {
this.value = this.compute_func(calc_inputs);
this.dirty = false;
for (const child of this.children) {
child.mark_input_clean(this.name, this.value, timestamp);
child.mark_input_clean(this.name, this.value);
}
}
/**
* Mark parent as not dirty. Propagates calculation if all inputs are present.
*/
mark_input_clean(input_name, value, timestamp) {
mark_input_clean(input_name, value) {
if (value !== null || this.fail_cb) {
if (this.inputs_dirty.get(input_name)) {
this.inputs_dirty.set(input_name, false);
this.inputs_dirty_count -= 1;
}
if (this.inputs_dirty_count === 0) {
this.update(timestamp);
this.update();
}
}
}
@ -111,8 +108,7 @@ function calcSchedule(node) {
}
node.mark_dirty();
node.update_task = setTimeout(function() {
const timestamp = Date.now();
node.update(timestamp);
node.update();
node.update_task = null;
}, 500);
}

View file

@ -190,7 +190,6 @@ class Craft{
let amounts = this.recipe.get("materials").map(x=> x.get("amount"));
//Mat Multipliers - should work!
matmult = (tierToMult[tiers[0]]*amounts[0] + tierToMult[tiers[1]]*amounts[1]) / (amounts[0]+amounts[1]);
console.log(matmult);
let low = this.recipe.get("healthOrDamage")[0];
let high = this.recipe.get("healthOrDamage")[1];

View file

@ -44,11 +44,26 @@ function init_crafter() {
try {
document.getElementById("recipe-choice").addEventListener("change", (event) => {
updateMaterials();
calculateCraftSchedule();
});
document.getElementById("level-choice").addEventListener("change", (event) => {
updateMaterials();
calculateCraftSchedule();
});
document.getElementById("recipe-choice").setAttribute("oninput", "updateCraftedImage()");
document.getElementById("recipe-choice").setAttribute("change", "updateCraftedImage()");
for (let i = 1; i < 4; ++i) {
document.getElementById("mat-1-"+i).setAttribute("onclick", document.getElementById("mat-1-"+i).getAttribute("onclick") + "; calculateCraftSchedule();");
document.getElementById("mat-2-"+i).setAttribute("onclick", document.getElementById("mat-2-"+i).getAttribute("onclick") + "; calculateCraftSchedule();");
}
for (let i = 1; i < 7; ++i) {
document.getElementById("ing-choice-" + i ).setAttribute("oninput", "calculateCraftSchedule();");
}
for (const str of ["slow", "normal", "fast"]) {
document.getElementById(str + "-atk-button").setAttribute("onclick", document.getElementById(str + "-atk-button").getAttribute("onclick") + "; calculateCraftSchedule();");
}
populateFields();
decodeCraft(ing_url_tag);
@ -88,6 +103,20 @@ function toggleAtkSpd(buttonId) {
}
}
let doCraftTask = null;
function calculateCraftSchedule(){
console.log("Craft Schedule called");
if (doCraftTask !== null) {
clearTimeout(doCraftTask);
}
doCraftTask = setTimeout(function(){
doCraftTask = null;
calculateCraft();
window.dispatchEvent(new Event('resize'));
}, 250);
}
function calculateCraft() {
//Make things display.
for (let i of document.getElementsByClassName("hide-container-block")) {
@ -230,9 +259,18 @@ function populateFields() {
}
/*
Copies the CR Hash (CR-blahblahblah)
*/
function copyRecipeHash() {
if (player_craft) {
copyTextToClipboard("CR-"+location.hash.slice(1));
document.getElementById("copy-hash-button").textContent = "Copied!";
}
}
/* Copy the link
/*
Copies the link (hppeng-wynn.github.io/crafter/#blahblah)
*/
function copyRecipe() {
if (player_craft) {

View file

@ -1,5 +1,6 @@
const ci_save_order = ["name", "lore", "tier", "set", "slots", "type", "material", "drop", "quest", "nDam", "fDam", "wDam", "aDam", "tDam", "eDam", "atkSpd", "hp", "fDef", "wDef", "aDef", "tDef", "eDef", "lvl", "classReq", "strReq", "dexReq", "intReq", "defReq", "agiReq", "str", "dex", "int", "agi", "def", "id", "skillpoints", "reqs", "nDam_", "fDam_", "wDam_", "aDam_", "tDam_", "eDam_", "majorIds", "hprPct", "mr", "sdPct", "mdPct", "ls", "ms", "xpb", "lb", "ref", "thorns", "expd", "spd", "atkTier", "poison", "hpBonus", "spRegen", "eSteal", "hprRaw", "sdRaw", "mdRaw", "fDamPct", "wDamPct", "aDamPct", "tDamPct", "eDamPct", "fDefPct", "wDefPct", "aDefPct", "tDefPct", "eDefPct", "spPct1", "spRaw1", "spPct2", "spRaw2", "spPct3", "spRaw3", "spPct4", "spRaw4", "rainbowRaw", "sprint", "sprintReg", "jh", "lq", "gXp", "gSpd", "durability", "duration", "charges"];
const nonRolled_strings = ["name", "lore", "tier", "set", "type", "material", "drop", "quest", "majorIds", "classReq", "atkSpd", "displayName", "nDam", "fDam", "wDam", "aDam", "tDam", "eDam", "nDam_", "fDam_", "wDam_", "aDam_", "tDam_", "eDam_", "durability", "duration"];
//omitted restrict - it's always "Custom Item"
//omitted displayName - either it's the same as name (repetitive) or it's "Custom Item"
//omitted category - can always get this from type
@ -93,6 +94,7 @@ function encodeCustom(custom, verbose) {
function getCustomFromHash(hash) {
let name = hash.slice();
let statMap;
console.log("decoding");
try {
if (name.slice(0, 3) === "CI-") {
name = name.substring(3);
@ -100,6 +102,7 @@ function getCustomFromHash(hash) {
throw new Error("Not a custom item!");
}
//probably change vers and fixID to be encoded and decoded to/from B64 in the future
let version = name.charAt(0);
let fixID = Boolean(parseInt(name.charAt(1), 10));
let tag = name.substring(2);
@ -220,8 +223,6 @@ class Custom{
*/
initCustomStats() {
//this.setHashVerbose(); //do NOT move sethash from here please
this.statMap.set("custom", true);
console.log(this.statMap);
for (const id of ci_save_order) {

View file

@ -232,6 +232,7 @@ function decodeCustom(custom_url_tag) {
let id = ci_save_order[Base64.toInt(tag.slice(0,2))];
//console.log(tag.slice(0, 2) + ": " + id);
let len = Base64.toInt(tag.slice(2,4));
if (rolledIDs.includes(id)) {
let sign = parseInt(tag.slice(4,5),10);
let minRoll = Base64.toInt(tag.slice(5,5+len));

67
js/dev.js Normal file
View file

@ -0,0 +1,67 @@
function init_dev() {
let sections = document.getElementsByClassName("section");
for (const section of sections) {
//so clicking works
section.classList.add("down");
//add title and toggle character
let title_row = document.createElement("div");
title_row.classList.add("row", "section-title");
let title = document.createElement("div");
title.classList.add("col");
title.textContent = section.title ? section.title : "";
title_row.appendChild(title);
section.insertBefore(title_row, section.firstChild);
let toggle_char = document.createElement("div");
toggle_char.classList.add("col-auto", "arrow");
toggle_char.textContent = "V";
title_row.appendChild(toggle_char);
title_row.addEventListener("click", (event) =>
{
toggleSection(section);
}, false);
for (const child of section.children) {
if (!child.classList.contains("section-title")) {
child.style.display = "none";
}
}
}
}
/*
Toggles section content as well as up and down arrow
@params:
*/
function toggleSection(section) {
//has down arrow (default state)
let down = section.classList.contains("down");
let arrow_elem = section.getElementsByClassName("arrow")[0];
if (down) {
section.classList.remove("down");
section.classList.add("up");
arrow_elem.style.transform = 'rotate(180deg)';
for (const elem of section.children) {
if (!elem.classList.contains("section-title")) {
elem.style.display = "";
}
}
} else {
section.classList.remove("up");
section.classList.add("down");
arrow_elem.style.transform = 'rotate(0deg)';
for (const elem of section.children) {
if (!elem.classList.contains("section-title")) {
elem.style.display = "none";
}
}
}
}
init_dev();

View file

@ -1814,6 +1814,13 @@ function displaySpellDamage(parent_elem, overallparent_elem, build, spell, spell
part_divavg.append(overallaverageLabel);
}
}
//up and down arrow - done ugly
let arrow = document.createElement("img");
arrow.id = "arrow_" + overallparent_elem.id;
arrow.style.maxWidth = document.body.clientWidth > 900 ? "3rem" : "10rem";
arrow.src = "../media/icons/" + (newIcons ? "new" : "old") + "/toggle_down.png";
overallparent_elem.appendChild(arrow);
}
/** Displays the ID costs of an item

View file

@ -103,6 +103,27 @@ function doSearchSchedule(){
}, 500);
}
function sq2ResetFields(){
for (let i in powderInputs) {
setValue(powderInputs[i], "");
}
for (let i in equipmentInputs) {
setValue(equipmentInputs[i], "");
}
for (let i in tomeInputs) {
setValue(tomeInputs[i], "");
}
setValue("str-skp", "0");
setValue("dex-skp", "0");
setValue("int-skp", "0");
setValue("def-skp", "0");
setValue("agi-skp", "0");
setValue("level-choice", "106");
location.hash = "";
calculateBuild();
}
// equipment field dynamic styling
function update_field(field) {
// built on the assumption of no one will type in CI/CR letter by letter
@ -221,10 +242,13 @@ function show_tab(tab) {
}
function toggle_spell_tab(tab) {
let arrow_img = document.querySelector("#" + "arrow_" + tab + "Avg");
if (document.querySelector("#"+tab).style.display == "none") {
document.querySelector("#"+tab).style.display = "";
arrow_img.src = arrow_img.src.replace("down", "up");
} else {
document.querySelector("#"+tab).style.display = "none";
arrow_img.src = arrow_img.src.replace("up", "down");
}
}

View file

@ -114,11 +114,9 @@ function parsePowdering(powder_info) {
for (let i = 0; i < 5; ++i) {
let powders = "";
let n_blocks = Base64.toInt(powder_info.charAt(0));
// console.log(n_blocks + " blocks");
powder_info = powder_info.slice(1);
for (let j = 0; j < n_blocks; ++j) {
let block = powder_info.slice(0,5);
console.log(block);
let six_powders = Base64.toInt(block);
for (let k = 0; k < 6 && six_powders != 0; ++k) {
powders += powderNames.get((six_powders & 0x1f) - 1);
@ -161,11 +159,10 @@ function decodeBuild(url_tag) {
let info_str = info[1];
let start_idx = 0;
for (let i = 0; i < 9; ++i ) {
if (info_str.charAt(start_idx) === "-") {
equipment[i] = "CR-"+info_str.slice(start_idx+1, start_idx+18);
start_idx += 18;
}
else {
if (info_str.slice(start_idx,start_idx+3) === "CR-") {
equipment[i] = info_str.slice(start_idx, start_idx+20);
start_idx += 20;
} else {
let equipment_str = info_str.slice(start_idx, start_idx+3);
equipment[i] = getItemNameFromID(Base64.toInt(equipment_str));
start_idx += 3;
@ -228,14 +225,12 @@ function decodeBuild(url_tag) {
info[1] = res[1];
}
// Tomes.
if (version == 6) {
if (version_number == 6) {
//tome values do not appear in anything before v6.
for (let i = 0; i < 7; ++i) {
let tome_str = info[1].charAt(i);
for (let i in tomes) {
setValue(tomeInputs[i], getTomeNameFromID(Base64.toInt(tome_str)));
}
}
info[1] = info[1].slice(7);
}

View file

@ -491,10 +491,12 @@ function displaysq2ExpandedItem(item, parent_id){
let base_dps_min = total_damages[0] * damage_mult;
let base_dps_max = total_damages[1] * damage_mult;
base_dps_elem.textContent = "Base DPS: "+base_dps_min.toFixed(3)+"\u279c"+base_dps_max.toFixed(3);
// base_dps_elem.textContent = "Base DPS: "+base_dps_min.toFixed(3)+"\u279c"+base_dps_max.toFixed(3);
base_dps_elem.textContent = base_dps_min.toFixed(3)+"\u279c"+base_dps_max.toFixed(3);
}
else {
base_dps_elem.textContent = "Base DPS: "+(total_damages * damage_mult);
let bdps = total_damages * damage_mult;
base_dps_elem.textContent = (bdps ? bdps : 0);
}
parent_div.appendChild(document.createElement("p"));
parent_div.appendChild(base_dps_elem);
@ -558,6 +560,11 @@ function displaysq2WeaponStats(build) {
stats.set("damageBonus", [0, 0, 0, 0, 0]);
stats.set("damageRaw", [item.get("nDam"), item.get("eDam"), item.get("tDam"), item.get("wDam"), item.get("fDam"), item.get("aDam")]);
//needed for damage calc CR powders
if (build.weapon.get("tier") === "Crafted") {
stats.set("damageBases", [item.get("nDamBaseHigh"), item.get("eDamBaseHigh"), item.get("tDamBaseHigh"), item.get("wDamBaseHigh"), item.get("fDamBaseHigh"), item.get("aDamBaseHigh")]);
}
let results = calculateSpellDamage(stats, [100, 0, 0, 0, 0, 0], 0, 0, 0, build.weapon, [0, 0, 0, 0, 0], 1, undefined);
let powdered_base = results[2];
@ -584,7 +591,8 @@ function displaysq2WeaponStats(build) {
tot /= 2;
let dps = Math.max(0, Math.round(tot * baseDamageMultiplier[attackSpeeds.indexOf(item.get("atkSpd"))] )); //atkspeeds
document.getElementById("weapon-dps").textContent = "base dps: " + dps;
// document.getElementById("weapon-dps").textContent = "base dps: " + (isNaN(dps) ? 0 : dps);
document.getElementById("weapon-dps").textContent = (isNaN(dps) ? 0 : dps);
document.getElementById("weapon-lv").textContent = item.get("lvl");
if (item.get("type")) {
@ -1407,6 +1415,13 @@ function displaysq2SpellDamage(parent_elem, overallparent_elem, build, spell, sp
part_divavg.append(overallaverageLabel);
}
}
//up and down arrow - done ugly
let arrow = document.createElement("img");
arrow.id = "arrow_" + overallparent_elem.id;
arrow.style.maxWidth = document.body.clientWidth > 900 ? "3rem" : "10rem";
arrow.src = "../media/icons/" + (newIcons ? "new" : "old") + "/toggle_down.png";
overallparent_elem.appendChild(arrow);
}
function displaysq2EquipOrder(parent_elem, buildOrder){

View file

@ -1,5 +1,5 @@
document.addEventListener("DOMContentLoaded", function() {
let filterInputs = new Map([["item-category", ["ALL", "armor", "helmet", "chestplate", "leggings", "boots", "accessory", "ring", "bracelet", "weapon", "wand", "spear", "bow", "dagger", "relik"]],
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],

Binary file not shown.

After

Width:  |  Height:  |  Size: 834 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 809 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 834 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 809 B

View file

@ -29,6 +29,7 @@ const changelog = new Map([
//[title ,[genre, filename, author(s), abstract/desc]]
]);
const sections = ["Changelog", "Mechanics", "History" ]
function init() {
@ -127,7 +128,7 @@ function initSections() {
div.id = sec;
let secspan = document.createElement("span");
secspan.classList.add("row", "up");
secspan.classList.add("row", "up", "clickable");
div.appendChild(secspan);
let title = document.createElement("div");
title.classList.add("col-10", "item-title", "text-start")