updated armor optimizer with some fixes
This commit is contained in:
parent
3ed25a982e
commit
4ce5b587f8
455
src/armor.html
455
src/armor.html
@ -1,275 +1,230 @@
|
|||||||
<!DOCTYPE html>
|
<!DOCTYPE html>
|
||||||
<html>
|
<html>
|
||||||
<head>
|
|
||||||
<!-- metadata -->
|
|
||||||
<meta charset="utf-8" />
|
|
||||||
<meta name="language" content="english" />
|
|
||||||
<meta name="viewport" content="width=device-width, initial-scale=1" />
|
|
||||||
|
|
||||||
<link rel="stylesheet" href="style/main.css" />
|
<head>
|
||||||
|
<!-- metadata -->
|
||||||
<!-- title and description -->
|
<meta charset="utf-8" />
|
||||||
<title>Erdtree - Armor Optimizer</title>
|
<meta name="language" content="english" />
|
||||||
<meta name="description" content="Elden Ring build planner, armor optimizer, weapon finder and more!" />
|
<meta name="viewport" content="width=device-width, initial-scale=1" />
|
||||||
<meta property="og:title" content="Erdtree Build Planner" />
|
<link rel="stylesheet" href="style/main.css" />
|
||||||
<meta
|
<!-- title and description -->
|
||||||
property="og:description"
|
<title>Erdtree - Armor Optimizer</title>
|
||||||
content="Erdtree - Elden Ring build planner, armor optimizer, weapon finder and more!"
|
<meta name="description"
|
||||||
/>
|
content="Elden Ring build planner, armor optimizer, weapon finder and more!" />
|
||||||
<meta property="og:url" content="https://erdtree.palmoe.dk" />
|
<meta property="og:title" content="Erdtree Build Planner" />
|
||||||
|
<meta property="og:description"
|
||||||
<!-- scripts -->
|
content="Erdtree - Elden Ring build planner, armor optimizer, weapon finder and more!" />
|
||||||
<script src="/script/armor.js"></script>
|
<meta property="og:url" content="https://erdtree.palmoe.dk" />
|
||||||
</head>
|
<!-- scripts -->
|
||||||
|
<script src="/script/armor.js"></script>
|
||||||
<body onload="init();">
|
</head>
|
||||||
<nav>
|
|
||||||
<h1><a href="/">Elden Ring Build Planner</a></h1>
|
|
||||||
<ul>
|
|
||||||
<li><a href="/planner.html">Build Planner</a></li>
|
|
||||||
</ul>
|
|
||||||
</nav>
|
|
||||||
|
|
||||||
<header>
|
|
||||||
<h1>Armor Optimizer</h1>
|
|
||||||
</header>
|
|
||||||
|
|
||||||
<main>
|
|
||||||
<div class="app">
|
|
||||||
<!-- settings -->
|
|
||||||
<article style="flex-basis: 25%">
|
|
||||||
<b>Settings</b>
|
|
||||||
|
|
||||||
<hr />
|
|
||||||
|
|
||||||
|
<body onload="init();">
|
||||||
|
<nav>
|
||||||
|
<h1><a href="/">Elden Ring Build Planner</a></h1>
|
||||||
|
<ul>
|
||||||
|
<li><a href="/planner.html">Build Planner</a></li>
|
||||||
|
</ul>
|
||||||
|
</nav>
|
||||||
|
<header>
|
||||||
|
<h1>Armor Optimizer</h1>
|
||||||
|
</header>
|
||||||
|
<main>
|
||||||
|
<div class="app">
|
||||||
|
<!-- settings -->
|
||||||
|
<article style="flex-basis: 25%">
|
||||||
|
<b>Settings</b>
|
||||||
|
<hr />
|
||||||
|
<div>
|
||||||
|
<label for="max-equip-load">Max. Equip Load</label>
|
||||||
|
<input style="max-width: 50px" class="stat"
|
||||||
|
id="max-equip-load" type="number" onchange="update()"
|
||||||
|
min="0" step="0.1" value="30" name="equip-load"
|
||||||
|
lang="en" />
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
<label for="current-equip-load">Current Equip Load</label>
|
||||||
|
<input style="max-width: 50px" class="stat"
|
||||||
|
id="current-equip-load" type="number"
|
||||||
|
onchange="update()" min="0" step="0.1" value="0"
|
||||||
|
name="equip-load" lang="en" />
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
<label for="equip-load-budget">Equip Load Budget</label>
|
||||||
|
<input style="max-width: 50px" class="stat"
|
||||||
|
id="equip-load-budget" type="number" value="0"
|
||||||
|
name="equip-load" lang="en" disabled />
|
||||||
|
</div>
|
||||||
|
<hr />
|
||||||
|
<b>Breakpoints</b>
|
||||||
|
<div>
|
||||||
<div>
|
<div>
|
||||||
<label for="max-equip-load">Max. Equip Load</label>
|
<input type="radio" id="fast-roll" onclick="update()"
|
||||||
<input
|
name="roll-type" value="0.3" />
|
||||||
style="max-width: 50px"
|
<label for="fast-roll">Fast Roll (up to 30% equip
|
||||||
class="stat"
|
load)</label>
|
||||||
id="max-equip-load"
|
|
||||||
type="number"
|
|
||||||
onchange="update()"
|
|
||||||
min="0"
|
|
||||||
step="0.1"
|
|
||||||
value="30"
|
|
||||||
name="equip-load"
|
|
||||||
lang="en"
|
|
||||||
/>
|
|
||||||
</div>
|
</div>
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
<div>
|
<div>
|
||||||
<label for="current-equip-load">Current Equip Load</label>
|
<input type="radio" id="normal-roll" onclick="update()"
|
||||||
<input
|
name="roll-type" value="0.7" checked />
|
||||||
style="max-width: 50px"
|
<label for="normal-roll">Normal Roll (up to 70% equip
|
||||||
class="stat"
|
load)</label>
|
||||||
id="current-equip-load"
|
|
||||||
type="number"
|
|
||||||
onchange="update()"
|
|
||||||
min="0"
|
|
||||||
step="0.1"
|
|
||||||
value="0"
|
|
||||||
name="equip-load"
|
|
||||||
lang="en"
|
|
||||||
/>
|
|
||||||
</div>
|
</div>
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
<div>
|
<div>
|
||||||
<label for="equip-load-budget">Equip Load Budget</label>
|
<input type="radio" id="fat-roll" onclick="update()"
|
||||||
<input
|
name="roll-type" value="1.0" />
|
||||||
style="max-width: 50px"
|
<label for="fat-roll">Fat Roll (up to 100% equip
|
||||||
class="stat"
|
load)</label>
|
||||||
id="equip-load-budget"
|
|
||||||
type="number"
|
|
||||||
value="0"
|
|
||||||
name="equip-load"
|
|
||||||
lang="en"
|
|
||||||
disabled
|
|
||||||
/>
|
|
||||||
</div>
|
</div>
|
||||||
|
</div>
|
||||||
<hr />
|
<hr />
|
||||||
|
<b>Sort by</b>
|
||||||
<b>Breakpoints</b>
|
<div>
|
||||||
|
|
||||||
<div>
|
<div>
|
||||||
<div>
|
<input type="radio" id="sort-average"
|
||||||
<input type="radio" id="fast-roll" onclick="update()" name="roll-type" value="0.3" />
|
name="sorting-order" onclick="update()" />
|
||||||
<label for="fast-roll">Fast Roll (up to 30% equip load)</label>
|
<label for="sort-average">Greatest Average
|
||||||
</div>
|
Negation</label>
|
||||||
</div>
|
</div>
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
<div>
|
<div>
|
||||||
<div>
|
<input type="radio" id="sort-physical"
|
||||||
<input
|
name="sorting-order" onclick="update()" checked />
|
||||||
type="radio"
|
<label for="sort-physical">Greatest Physical
|
||||||
id="normal-roll"
|
Negation</label>
|
||||||
onclick="update()"
|
|
||||||
name="roll-type"
|
|
||||||
value="0.7"
|
|
||||||
checked
|
|
||||||
/>
|
|
||||||
<label for="normal-roll">Normal Roll (up to 70% equip load)</label>
|
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
<div>
|
<div>
|
||||||
<div>
|
<input type="radio" id="sort-elemental"
|
||||||
<input type="radio" id="fat-roll" onclick="update()" name="roll-type" value="1.0" />
|
name="sorting-order" onclick="update()" />
|
||||||
<label for="fat-roll">Fat Roll (up to 100% equip load)</label>
|
<label for="sort-elemental">Greatest Elemental
|
||||||
</div>
|
Negation</label>
|
||||||
</div>
|
</div>
|
||||||
|
</div>
|
||||||
<hr />
|
<div>
|
||||||
|
|
||||||
<b>Sort by</b>
|
|
||||||
|
|
||||||
<div>
|
<div>
|
||||||
<div>
|
<input type="radio" id="sort-resistances"
|
||||||
<input type="radio" id="sort-average" name="sorting-order" onclick="update()" />
|
name="sorting-order" onclick="update()" />
|
||||||
<label for="sort-average">Greatest Average Negation</label>
|
<label for="sort-resistances">Greatest
|
||||||
</div>
|
Resistances</label>
|
||||||
</div>
|
</div>
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
<div>
|
<div>
|
||||||
<div>
|
<input type="radio" id="sort-poise" name="sorting-order"
|
||||||
<input type="radio" id="sort-physical" name="sorting-order" onclick="update()" checked />
|
onclick="update()" />
|
||||||
<label for="sort-physical">Greatest Physical Negation</label>
|
<label for="sort-poise">Greatest Poise</label>
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
|
</div>
|
||||||
|
<hr />
|
||||||
|
<b>Extras</b>
|
||||||
|
<div>
|
||||||
<div>
|
<div>
|
||||||
<div>
|
<input type="checkbox" id="winged-crystal-tear"
|
||||||
<input type="radio" id="sort-elemental" name="sorting-order" onclick="update()" />
|
onchange="update()" disabled />
|
||||||
<label for="sort-elemental">Greatest Elemental Negation</label>
|
<label for="winged-crystal-tear">Winged Crystal Tear (in
|
||||||
</div>
|
mixed physick)</label>
|
||||||
</div>
|
</div>
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
<div>
|
<div>
|
||||||
<div>
|
<input type="checkbox" id="fashion" onchange="update()"
|
||||||
<input type="radio" id="sort-resistances" name="sorting-order" onclick="update()" />
|
disabled />
|
||||||
<label for="sort-resistances">Greatest Resistances</label>
|
<label for="fashion">Fashion Mode</label>
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
|
</div>
|
||||||
|
<hr />
|
||||||
|
<b>Locked Items</b>
|
||||||
|
<template id="locked-option">
|
||||||
|
<option value="">Placeholder</option>
|
||||||
|
</template>
|
||||||
|
<div>
|
||||||
|
<label for="locked-helmet">Helmet</label>
|
||||||
|
<select type="text" id="locked-helmet" name="locked-items"
|
||||||
|
onchange="update()"></select>
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
<label for="locked-chestpiece">Chestpiece</label>
|
||||||
|
<select type="text" id="locked-chestpiece"
|
||||||
|
name="locked-items" onchange="update()"></select>
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
<label for="locked-gauntlets">Gauntlets</label>
|
||||||
|
<select type=" text" id="locked-gauntlets"
|
||||||
|
name="locked-items" onchange="update()"></select>
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
<label for="locked-leggings">Leggings</label>
|
||||||
|
<select type="text" id="locked-leggings" name="locked-items"
|
||||||
|
onchange="update()"></select>
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
<button id="clear-equipment" onclick="resetAll()">Reset
|
||||||
|
All</button>
|
||||||
|
</div>
|
||||||
|
</article>
|
||||||
|
<!-- sort -->
|
||||||
|
<article style="flex-basis: 60%; min-width: 320px">
|
||||||
|
<b>Results</b>
|
||||||
|
<hr />
|
||||||
|
<div>
|
||||||
|
<table id="results"></table>
|
||||||
|
</div>
|
||||||
|
<template id="result">
|
||||||
|
<thead>
|
||||||
|
<tr>
|
||||||
|
<th>Items</th>
|
||||||
|
<th>Stats</th>
|
||||||
|
</tr>
|
||||||
|
</thead>
|
||||||
|
<tbody>
|
||||||
|
<tr>
|
||||||
|
<td>Total</td>
|
||||||
|
<td>Stats</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td>Helmet</td>
|
||||||
|
<td>Stats</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td>Chestpiece</td>
|
||||||
|
<td>Stats</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td>Gaunlets</td>
|
||||||
|
<td>Stats</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td>Leggings</td>
|
||||||
|
<td>Stats</td>
|
||||||
|
</tr>
|
||||||
|
</tbody>
|
||||||
|
</template>
|
||||||
|
</article>
|
||||||
|
<!-- filter -->
|
||||||
|
<article>
|
||||||
|
<ul>
|
||||||
|
<li>
|
||||||
|
<b>Allowed Armor</b>
|
||||||
|
</li>
|
||||||
|
</ul>
|
||||||
|
</article>
|
||||||
|
</div>
|
||||||
|
</main>
|
||||||
|
<footer>
|
||||||
|
<h5>
|
||||||
|
Erdtree Planner (<a
|
||||||
|
href="https://git.palmoe.dk/vodofrede/erdtree">available under
|
||||||
|
BSD-3-Clause license</a>)
|
||||||
|
</h5>
|
||||||
|
<h5>Copyright 2022 vodofrede</h5>
|
||||||
|
</footer>
|
||||||
|
</body>
|
||||||
|
|
||||||
<div>
|
</html>
|
||||||
<div>
|
|
||||||
<input type="radio" id="sort-poise" name="sorting-order" onclick="update()" />
|
|
||||||
<label for="sort-poise">Greatest Poise</label>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<hr />
|
|
||||||
|
|
||||||
<b>Extras</b>
|
|
||||||
|
|
||||||
<div>
|
|
||||||
<div>
|
|
||||||
<input type="checkbox" id="winged-crystal-tear" onchange="update()" disabled />
|
|
||||||
<label for="winged-crystal-tear">Winged Crystal Tear (in mixed physick)</label>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div>
|
|
||||||
<div>
|
|
||||||
<input type="checkbox" id="fashion" onchange="update()" disabled />
|
|
||||||
<label for="fashion">Fashion Mode</label>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<hr />
|
|
||||||
|
|
||||||
<b>Locked Items</b>
|
|
||||||
<template id="locked-option">
|
|
||||||
<option value="">Placeholder</option>
|
|
||||||
</template>
|
|
||||||
|
|
||||||
<div>
|
|
||||||
<label for="select-helmet">Helmet</label>
|
|
||||||
<select type="text" id="select-helmet" name="locked-items" onchange="update()"></select>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div>
|
|
||||||
<label for="select-chestpiece">Chestpiece</label>
|
|
||||||
<select type="text" id="select-chestpiece" name="locked-items" onchange="update()"></select>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div>
|
|
||||||
<label for="select-gauntlets">Gauntlets</label>
|
|
||||||
<select type=" text" id="select-gauntlets" name="locked-items" onchange="update()"></select>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div>
|
|
||||||
<label for="select-leggings">Leggings</label>
|
|
||||||
<select type="text" id="select-leggings" name="locked-items" onchange="update()"></select>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div>
|
|
||||||
<button id="clear-equipment" onclick="reset()">Reset All</button>
|
|
||||||
</div>
|
|
||||||
</article>
|
|
||||||
|
|
||||||
<!-- sort -->
|
|
||||||
<article style="flex-basis: 60%; min-width: 320px">
|
|
||||||
<b>Results</b>
|
|
||||||
<hr />
|
|
||||||
|
|
||||||
<div>
|
|
||||||
<ul id="sort-results"></ul>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<template id="sort-result">
|
|
||||||
<li class="sort-result">
|
|
||||||
<table>
|
|
||||||
<thead>
|
|
||||||
<tr>
|
|
||||||
<th>Items</th>
|
|
||||||
<th>Stats</th>
|
|
||||||
</tr>
|
|
||||||
</thead>
|
|
||||||
<tbody>
|
|
||||||
<tr>
|
|
||||||
<td>Total</td>
|
|
||||||
<td>Stats</td>
|
|
||||||
</tr>
|
|
||||||
<tr>
|
|
||||||
<td>Helmet</td>
|
|
||||||
<td>Stats</td>
|
|
||||||
</tr>
|
|
||||||
<tr>
|
|
||||||
<td>Chestpiece</td>
|
|
||||||
<td>Stats</td>
|
|
||||||
</tr>
|
|
||||||
<tr>
|
|
||||||
<td>Gaunlets</td>
|
|
||||||
<td>Stats</td>
|
|
||||||
</tr>
|
|
||||||
<tr>
|
|
||||||
<td>Leggings</td>
|
|
||||||
<td>Stats</td>
|
|
||||||
</tr>
|
|
||||||
</tbody>
|
|
||||||
</table>
|
|
||||||
</li>
|
|
||||||
</template>
|
|
||||||
</article>
|
|
||||||
|
|
||||||
<!-- filter -->
|
|
||||||
<article>
|
|
||||||
<ul>
|
|
||||||
<li>
|
|
||||||
<b>Allowed Armor</b>
|
|
||||||
</li>
|
|
||||||
</ul>
|
|
||||||
</article>
|
|
||||||
</div>
|
|
||||||
</main>
|
|
||||||
|
|
||||||
<footer>
|
|
||||||
<h5>
|
|
||||||
Erdtree Planner (<a href="https://git.palmoe.dk/vodofrede/erdtree"
|
|
||||||
>available under BSD-3-Clause license</a
|
|
||||||
>)
|
|
||||||
</h5>
|
|
||||||
<h5>Copyright 2022 vodofrede</h5>
|
|
||||||
</footer>
|
|
||||||
</body>
|
|
||||||
</html>
|
|
@ -58,6 +58,7 @@
|
|||||||
},
|
},
|
||||||
"ash-of-war-scarab": {
|
"ash-of-war-scarab": {
|
||||||
"name": "Ash-of-War Scarab",
|
"name": "Ash-of-War Scarab",
|
||||||
|
"id": "ash-of-war-scarab",
|
||||||
"defenses": [-5.8, -5.6, -5.8, -5.8, -4.9, -4.9, -4.9, -5.1],
|
"defenses": [-5.8, -5.6, -5.8, -5.8, -4.9, -4.9, -4.9, -5.1],
|
||||||
"resistances": [42, 22, 27, 26],
|
"resistances": [42, 22, 27, 26],
|
||||||
"poise": 2,
|
"poise": 2,
|
||||||
@ -553,6 +554,7 @@
|
|||||||
"weight": 1.7
|
"weight": 1.7
|
||||||
},
|
},
|
||||||
"godskin-noble-hood": {
|
"godskin-noble-hood": {
|
||||||
|
"id": "godskin-noble-hood",
|
||||||
"name": "Godskin Noble Hood",
|
"name": "Godskin Noble Hood",
|
||||||
"defenses": [1.4, 2.8, 1.8, 1.4, 4.5, 4, 4.2, 4.8],
|
"defenses": [1.4, 2.8, 1.8, 1.4, 4.5, 4, 4.2, 4.8],
|
||||||
"resistances": [16, 10, 27, 29],
|
"resistances": [16, 10, 27, 29],
|
||||||
@ -1200,6 +1202,7 @@
|
|||||||
"weight": 2.2
|
"weight": 2.2
|
||||||
},
|
},
|
||||||
"sanguine-noble-hood": {
|
"sanguine-noble-hood": {
|
||||||
|
"id": "sanguine-noble-hood",
|
||||||
"name": "Sanguine Noble Hood",
|
"name": "Sanguine Noble Hood",
|
||||||
"defenses": [1.4, 0.9, 0.9, 0.9, 4.6, 3.8, 4.5, 4.6],
|
"defenses": [1.4, 0.9, 0.9, 0.9, 4.6, 3.8, 4.5, 4.6],
|
||||||
"resistances": [18, 5, 29, 27],
|
"resistances": [18, 5, 29, 27],
|
||||||
|
@ -1,80 +1,94 @@
|
|||||||
const HELMETS = fetch("/data/helmets.json")
|
let HELMETS;
|
||||||
.then((response) => response.json())
|
let CHESTPIECES;
|
||||||
.catch((error) => console.log(error));
|
let GAUNTLETS;
|
||||||
const CHESTPIECES = fetch("/data/chestpieces.json")
|
let LEGGINGS;
|
||||||
.then((response) => response.json())
|
let EQUIPMENT;
|
||||||
.catch((error) => console.log(error));
|
|
||||||
const GAUNTLETS = fetch("/data/gauntlets.json")
|
|
||||||
.then((response) => response.json())
|
|
||||||
.catch((error) => console.log(error));
|
|
||||||
const LEGGINGS = fetch("/data/leggings.json")
|
|
||||||
.then((response) => response.json())
|
|
||||||
.catch((error) => console.log(error));
|
|
||||||
|
|
||||||
var helmets;
|
const populate = (select, items) => items.forEach(item => select.options.add(new Option(item.name, item.id)));
|
||||||
var chestpieces;
|
const selected = select => select.options[select.selectedIndex];
|
||||||
var gauntlets;
|
|
||||||
var leggings;
|
|
||||||
|
|
||||||
async function init() {
|
async function init() {
|
||||||
// populate filter selects
|
HELMETS = await fetch("/data/helmets.json").then(response => response.json());
|
||||||
populateSelect("locked-option", "select-helmet", Object.values(await HELMETS));
|
CHESTPIECES = await fetch("/data/chestpieces.json").then(response => response.json());
|
||||||
populateSelect("locked-option", "select-chestpiece", Object.values(await CHESTPIECES));
|
GAUNTLETS = await fetch("/data/gauntlets.json").then(response => response.json());
|
||||||
populateSelect("locked-option", "select-gauntlets", Object.values(await GAUNTLETS));
|
LEGGINGS = await fetch("/data/leggings.json").then(response => response.json());
|
||||||
populateSelect("locked-option", "select-leggings", Object.values(await LEGGINGS));
|
EQUIPMENT = [HELMETS, CHESTPIECES, GAUNTLETS, LEGGINGS];
|
||||||
|
|
||||||
update(true);
|
// populate filter selects
|
||||||
|
populate(document.getElementById("locked-helmet"), Object.values(HELMETS));
|
||||||
|
populate(document.getElementById("locked-chestpiece"), Object.values(CHESTPIECES));
|
||||||
|
populate(document.getElementById("locked-gauntlets"), Object.values(GAUNTLETS));
|
||||||
|
populate(document.getElementById("locked-leggings"), Object.values(LEGGINGS));
|
||||||
|
|
||||||
|
update();
|
||||||
}
|
}
|
||||||
|
|
||||||
async function update() {
|
function update() {
|
||||||
// remove any previous results
|
// remove any previous results
|
||||||
Array.from(document.getElementsByClassName("sort-result")).forEach((elem) => elem.parentNode.removeChild(elem));
|
document.getElementById("results").innerHTML = "";
|
||||||
|
|
||||||
// clamp equip load values to reasonable values
|
// get budget & sort order
|
||||||
// [...document.getElementsByName("equip-load")].forEach(el => el.value = Math.max(el.value, 0.0));
|
|
||||||
|
|
||||||
// update budget
|
|
||||||
let budget = equipLoadBudget();
|
let budget = equipLoadBudget();
|
||||||
document.getElementById("equip-load-budget").value = budget.toFixed(1);
|
document.getElementById("equip-load-budget").value = budget.toFixed(1);
|
||||||
let sortBy = [...document.getElementsByName("sorting-order")].find((elem) => elem.checked).id;
|
let sortBy = [...document.getElementsByName("sorting-order")].find(elem => elem.checked).id;
|
||||||
|
|
||||||
// get locked items
|
// get locked items
|
||||||
let lockedItems = await Promise.all([HELMETS, CHESTPIECES, GAUNTLETS, LEGGINGS]).then((allItems) => {
|
let lockedItems = [...document.getElementsByName("locked-items")]
|
||||||
return [...document.getElementsByName("locked-items")]
|
.map((select, i) => Object.values(EQUIPMENT[i])[select.selectedIndex])
|
||||||
.map((select, i) => Object.values(allItems[i])[select.selectedIndex])
|
.filter(item => !item.id.startsWith("no-"));
|
||||||
.filter((item) => !item.id.startsWith("no-"));
|
|
||||||
});
|
|
||||||
|
|
||||||
// pre-sort and eliminate some equipment
|
// pre-sort and eliminate some equipment
|
||||||
helmets = eliminate(Object.values(await HELMETS), sortBy, lockedItems);
|
let helmets = dominated(Object.values(HELMETS), sortBy, lockedItems);
|
||||||
chestpieces = eliminate(Object.values(await CHESTPIECES), sortBy, lockedItems);
|
let chestpieces = dominated(Object.values(CHESTPIECES), sortBy, lockedItems);
|
||||||
gauntlets = eliminate(Object.values(await GAUNTLETS), sortBy, lockedItems);
|
let gauntlets = dominated(Object.values(GAUNTLETS), sortBy, lockedItems);
|
||||||
leggings = eliminate(Object.values(await LEGGINGS), sortBy, lockedItems);
|
let leggings = dominated(Object.values(LEGGINGS), sortBy, lockedItems);
|
||||||
let selection = permutations(budget, lockedItems);
|
|
||||||
|
let selection = permutations([helmets, chestpieces, gauntlets, leggings], budget, lockedItems);
|
||||||
|
|
||||||
// find best sets to display
|
// find best sets to display
|
||||||
let best = knapSack(selection, sortBy);
|
let best = knapSack(selection, sortBy);
|
||||||
|
|
||||||
// show best sets under budget
|
// show best sets under budget
|
||||||
populateResults("sort-result", "sort-results", best);
|
let template = document.getElementById("result");
|
||||||
|
let destination = document.getElementById("results");
|
||||||
|
best.forEach(set => {
|
||||||
|
let clone = template.content.cloneNode(true);
|
||||||
|
let tbody = clone.children[1];
|
||||||
|
let rows = tbody.children;
|
||||||
|
|
||||||
|
[...rows].slice(1).forEach((row, i) => {
|
||||||
|
row.children[0].innerText = set[i].name;
|
||||||
|
row.children[1].innerHTML = itemStatsToString(set[i]);
|
||||||
|
});
|
||||||
|
rows[0].children[1].innerHTML = setStatsToString(set);
|
||||||
|
|
||||||
|
destination.appendChild(clone);
|
||||||
|
});
|
||||||
|
|
||||||
|
// display error message if sets is empty
|
||||||
|
if (best.length == 0) {
|
||||||
|
let error = document.createElement("b");
|
||||||
|
error.innerHTML = "No sets found under budget";
|
||||||
|
destination.appendChild(error);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function reset() {
|
function resetAll() {
|
||||||
[...document.getElementsByName("locked-items")].forEach((select) => (select.selectedIndex = 0));
|
[...document.getElementsByName("locked-items")].forEach(select => (select.selectedIndex = 0));
|
||||||
update();
|
update();
|
||||||
}
|
}
|
||||||
|
|
||||||
function eliminate(list, sortBy, lockedItems) {
|
function dominated(itemList, sortBy, lockedItems) {
|
||||||
if (lockedItems.some((item) => list.includes(item))) {
|
if (lockedItems.some(item => itemList.includes(item))) {
|
||||||
return [list.find((item) => lockedItems.includes(item))];
|
return [itemList.find(item => lockedItems.includes(item))];
|
||||||
}
|
}
|
||||||
|
|
||||||
let sorted = [...list];
|
let sorted = [...itemList];
|
||||||
sorted.sort((a, b) => a.weight - b.weight);
|
sorted.sort((a, b) => a.weight - b.weight);
|
||||||
|
|
||||||
let approved = [];
|
let approved = [];
|
||||||
sorted.forEach((item) => {
|
sorted.forEach(item => {
|
||||||
if (!approved.some((other) => fitness(item, sortBy) <= fitness(other, sortBy))) {
|
if (!approved.some(other => fitness(item, sortBy) <= fitness(other, sortBy))) {
|
||||||
approved.push(item);
|
approved.push(item);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
@ -82,14 +96,14 @@ function eliminate(list, sortBy, lockedItems) {
|
|||||||
return approved;
|
return approved;
|
||||||
}
|
}
|
||||||
|
|
||||||
function permutations(budget, lockedItems) {
|
function permutations([helmets, chestpieces, gauntlets, leggings], budget, lockedItems) {
|
||||||
return helmets.flatMap((h) => {
|
return helmets.flatMap(h => {
|
||||||
return chestpieces.flatMap((c) => {
|
return chestpieces.flatMap(c => {
|
||||||
return gauntlets.flatMap((g) => {
|
return gauntlets.flatMap(g => {
|
||||||
return leggings
|
return leggings
|
||||||
.filter((l) => isAllowedSet([h, c, g, l], lockedItems))
|
.filter(l => isAllowedSet([h, c, g, l], lockedItems))
|
||||||
.filter((l) => budget > setWeight([h, c, g, l]))
|
.filter(l => budget > setWeight([h, c, g, l]))
|
||||||
.map((l) => [h, c, g, l]);
|
.map(l => [h, c, g, l]);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
@ -121,12 +135,12 @@ function fitness(item, sortBy) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const setWeight = (set) => (set.weight ??= set.reduce((total, item) => total + item.weight, 0));
|
const setWeight = set => (set.weight ??= set.reduce((total, item) => total + item.weight, 0));
|
||||||
const setFitness = (set, sortBy) => (set.fitness ??= set.reduce((total, item) => total + fitness(item, sortBy), 0.0));
|
const setFitness = (set, sortBy) => (set.fitness ??= set.reduce((total, item) => total + fitness(item, sortBy), 0.0));
|
||||||
const isAllowedSet = (set, lockedItems) => lockedItems.every((item) => set.includes(item));
|
const isAllowedSet = (set, lockedItems) => lockedItems.every(item => set.includes(item));
|
||||||
|
|
||||||
function equipLoadBudget() {
|
function equipLoadBudget() {
|
||||||
let rollModifier = parseFloat([...document.getElementsByName("roll-type")].find((elem) => elem.checked).value);
|
let rollModifier = parseFloat([...document.getElementsByName("roll-type")].find(elem => elem.checked).value);
|
||||||
|
|
||||||
let max = document.getElementById("max-equip-load").value || 0;
|
let max = document.getElementById("max-equip-load").value || 0;
|
||||||
let current = document.getElementById("current-equip-load").value || 0;
|
let current = document.getElementById("current-equip-load").value || 0;
|
||||||
@ -134,42 +148,6 @@ function equipLoadBudget() {
|
|||||||
return parseFloat(Math.max((max - current) * rollModifier, 0.0));
|
return parseFloat(Math.max((max - current) * rollModifier, 0.0));
|
||||||
}
|
}
|
||||||
|
|
||||||
// site rendering functions
|
|
||||||
function populateSelect(templateId, destinationId, items) {
|
|
||||||
let destination = document.getElementById(destinationId);
|
|
||||||
items.forEach((item) => {
|
|
||||||
destination.options.add(new Option(item.name, item.id));
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
async function populateResults(templateId, destinationId, sets) {
|
|
||||||
let template = document.getElementById(templateId);
|
|
||||||
let destination = document.getElementById(destinationId);
|
|
||||||
|
|
||||||
(await sets).forEach((set) => {
|
|
||||||
let clone = template.content.cloneNode(true);
|
|
||||||
|
|
||||||
let li = clone.children[0];
|
|
||||||
let table = li.children[0];
|
|
||||||
let tbody = table.children[1];
|
|
||||||
let rows = tbody.children;
|
|
||||||
|
|
||||||
rows[1].children[0].innerText = set[0].name;
|
|
||||||
rows[2].children[0].innerText = set[1].name;
|
|
||||||
rows[3].children[0].innerText = set[2].name;
|
|
||||||
rows[4].children[0].innerText = set[3].name;
|
|
||||||
|
|
||||||
rows[1].children[1].innerHTML = itemStatsToString(set[0]);
|
|
||||||
rows[2].children[1].innerHTML = itemStatsToString(set[1]);
|
|
||||||
rows[3].children[1].innerHTML = itemStatsToString(set[2]);
|
|
||||||
rows[4].children[1].innerHTML = itemStatsToString(set[3]);
|
|
||||||
|
|
||||||
rows[0].children[1].innerHTML = setStatsToString(set);
|
|
||||||
|
|
||||||
destination.appendChild(clone);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
function itemStatsToString(item) {
|
function itemStatsToString(item) {
|
||||||
let weight = item.weight.toFixed(1) + " wgt., ";
|
let weight = item.weight.toFixed(1) + " wgt., ";
|
||||||
let poise = item.poise + " poise, ";
|
let poise = item.poise + " poise, ";
|
||||||
@ -187,7 +165,7 @@ function itemStatsToString(item) {
|
|||||||
// let elemental = item.defenses.slice(4, 8).reduce((total, defense, i) => total + defense.toFixed(1) + " " + DEFENSE_NAMES[i + 4] + ", ", "");
|
// let elemental = item.defenses.slice(4, 8).reduce((total, defense, i) => total + defense.toFixed(1) + " " + DEFENSE_NAMES[i + 4] + ", ", "");
|
||||||
let resistances = item.resistances.reduce(
|
let resistances = item.resistances.reduce(
|
||||||
(total, res, i) => total + res + " " + ["immunity", "robustness", "focus", "vitality"][i] + ", ",
|
(total, res, i) => total + res + " " + ["immunity", "robustness", "focus", "vitality"][i] + ", ",
|
||||||
""
|
"",
|
||||||
);
|
);
|
||||||
|
|
||||||
return weight + poise + physical + elemental + "<br>" + resistances;
|
return weight + poise + physical + elemental + "<br>" + resistances;
|
||||||
@ -199,7 +177,7 @@ function setStatsToString(set) {
|
|||||||
poise: set[0].poise + set[1].poise + set[2].poise + set[3].poise,
|
poise: set[0].poise + set[1].poise + set[2].poise + set[3].poise,
|
||||||
defenses: set[0].defenses.map((stat, i) => stat + set[1].defenses[i] + set[2].defenses[i] + set[3].defenses[i]),
|
defenses: set[0].defenses.map((stat, i) => stat + set[1].defenses[i] + set[2].defenses[i] + set[3].defenses[i]),
|
||||||
resistances: set[0].resistances.map(
|
resistances: set[0].resistances.map(
|
||||||
(stat, i) => stat + set[1].resistances[i] + set[2].resistances[i] + set[3].resistances[i]
|
(stat, i) => stat + set[1].resistances[i] + set[2].resistances[i] + set[3].resistances[i],
|
||||||
),
|
),
|
||||||
};
|
};
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user