wip armor optimizer

This commit is contained in:
Frederik Palmø 2022-03-20 16:57:42 +01:00
parent 07b7321ec9
commit 054dfbe1c4
9 changed files with 344 additions and 61 deletions

230
src/armor.html Normal file
View File

@ -0,0 +1,230 @@
<!DOCTYPE html>
<html>
<head>
<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">
<title>Erdtree - Class Optimizer</title>
<meta name="description" content="">
<script src="/script/armor.js"></script>
</head>
<body onload="init();">
<nav>
<h1><a href="/index.html">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: 30%">
<ul>
<li><b>Settings</b></li>
<hr>
<li>
<label for="equip-load"><b>Max. Equip Load</b></label>
<input style="max-width: 50px" class="stat" id="equip-load" type="number" onchange="update()"
min=0 step=0.1 value="30">
</li>
<hr>
<li>
<b>Breakpoints</b>
</li>
<li>
<div>
<input type="radio" id="fast-roll" onclick="update()" name="burden">
<label for="fast-roll">Fast Roll (up to 30% equip load)</label>
</div>
</li>
<li>
<div>
<input type="radio" id="normal-roll" onclick="update()" name="burden" checked>
<label for="normal-roll">Normal Roll (up to 70% equip load)</label>
</div>
</li>
<li>
<div>
<input type="radio" id="fast-roll" onclick="update()" name="burden">
<label for="fat-roll">Fat Roll (up to 100% equip load)</label>
</div>
</li>
<hr>
<li>
<b>Sorting</b>
</li>
<li>
<div>
<input type="radio" id="greatest-physical" name="sorting-order" onclick="update()" checked>
<label for="avg-physical">Greatest Physical Negation</label>
</div>
</li>
<li>
<div>
<input type="radio" id="greatest-elemental" name="sorting-order" onclick="update()">
<label for="avg-elemental">Greatest Elemental Negation</label>
</div>
</li>
<li>
<div>
<input type="radio" id="greatest-immunities" name="sorting-order" onclick="update()">
<label for="avg-immunities">Greatest Immunities</label>
</div>
</li>
<li>
<div>
<input type="radio" id="greatest-average" name="sorting-order" onclick="update()">
<label for="greatest-average">Greatest Weighted Average Defense</label>
</div>
</li>
<hr>
<li>
<b>Extras</b>
</li>
<li>
<div>
<input type="checkbox" id="winged-crystal-tear" onchange="update()">
<label for="winged-crystal-tear">Winged Crystal Tear (in mixed physick)</label>
</div>
</li>
<li>
<div>
<input type="checkbox" id="fashion" onchange="update()">
<label for="fashion">Fashion Mode</label>
</div>
</li>
</ul>
</article>
<!-- results -->
<article style="flex-basis: 60%; min-width: 300px">
<ul>
<li><b>Results</b></li>
<hr>
<template id="sort-result">
<table>
<thead>
<tr>
<th>Items</th>
<th>Stats</th>
</tr>
</thead>
<tbody>
<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>
</template>
</ul>
</article>
<!-- filter -->
<article>
<ul>
<li><b>Filter</b></li>
<hr>
<li>
<b>Locked Equipment</b>
<button id="clear-equipment" onclick="update()">Clear Locked Equipment</button>
</li>
<li>
<table>
<thead>
<tr>
<th>Headgear</th>
<th>Chestpiece</th>
<th>Gauntlets</th>
<th>Leggings</th>
</tr>
</thead>
<tbody>
<tr>
<td>
<select type="text" id="select-head" name="locked-equipment"
onchange="update()">
<option>None</option>
</select>
</td>
<td>
<select type="text" id="select-chest" name="locked-equipment"
onchange="update()">
<option>None</option>
</select>
</td>
<td>
<select type=" text" id="select-hands" name="locked-equipment"
onchange="update()">
<option>None</option>
</select>
</td>
<td>
<select type="text" id="select-legs" name="locked-equipment"
onchange="update()">
<option>None</option>
</select>
</td>
</tr>
</tbody>
</table>
</li>
<hr>
<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>

View File

@ -1,5 +1,5 @@
{
"helms": [
"helmets": [
{
"id": "albinauric-mask",
"name": "Albinauric Mask",

14
src/data/sets.json Normal file
View File

@ -0,0 +1,14 @@
{
"sets": [
{
"id": "alberichs-set",
"name": "Alberich's Set",
"pieces": [
"alberichs-pointed-hat",
"alberichs-robe",
"alberichs-bracers",
"alberichs-trousers"
]
}
]
}

View File

@ -17,7 +17,6 @@
<h1><a href="/index.html">Elden Ring Build Planner</a></h1>
<ul>
<li><a href="/planner.html">Build Planner</a></li>
<li><a href="/optimizer.html">Class Optimizer</a></li>
</ul>
</nav>
@ -29,7 +28,7 @@
<div class="cards">
<article>
<a href="/planner.html">
<h3>Build Planner</h3>
<h3>Build Planner (todo)</h3>
<br>
<p>Create a new build.</p>
</a>
@ -43,9 +42,17 @@
</a>
</article>
<article>
<a href="/armor.html">
<h3>Armor Optimizer (in progress)</h3>
<br>
<p>Maximize defensive stats.</p>
</a>
</article>
<article>
<a href="/attack.html">
<h3>Attack Rating Calculator</h3>
<h3>Attack Rating Calculator (todo)</h3>
<br>
<p>Calculate attack rating for a weapon.</p>
</a>
@ -53,23 +60,15 @@
<article>
<a href="/censor.html">
<h3>Censor Checker</h3>
<h3>Censor Checker (todo)</h3>
<br>
<p>Detect censored names.</p>
</a>
</article>
<article>
<a href="/armor.html">
<h3>Armor Optimizer</h3>
<br>
<p>Maximize defensive stats.</p>
</a>
</article>
<article>
<a href="/finder.html">
<h3>Weapon Finder</h3>
<h3>Weapon Finder (todo)</h3>
<br>
<p>Get suggestions for usable weapons.</p>
</a>

View File

@ -19,7 +19,6 @@
<h1><a href="/index.html">Elden Ring Build Planner</a></h1>
<ul>
<li><a href="/planner.html">Build Planner</a></li>
<li><a href="/optimizer.html">Class Optimizer</a></li>
</ul>
</nav>
@ -203,8 +202,6 @@
<hr>
<template id="talisman">
<li>
<div>
@ -221,17 +218,17 @@
<article>
<ul>
<li>
<b>Helms</b>
<b>Helmets</b>
</li>
<hr>
<details id="helms">
<summary>Click to show helms</summary>
<details id="helmets">
<summary>Click to show helmets</summary>
<li>
<div>
<input type="radio" name="equipment" id="helmNone" onclick="update()" checked>
<input type="radio" name="equipment" id="helm-none" onclick="update()" checked>
<label for="">None</label>
</div>
<aside></aside>
@ -255,10 +252,10 @@
<table>
<thead>
<tr>
<td>Skill</td>
<td>Stat</td>
<td>Softcaps</td>
<td>Notes</td>
<th>Skill</th>
<th>Stat</th>
<th>Softcaps</th>
<th>Notes</th>
</tr>
</thead>
<tbody>

View File

@ -17,7 +17,6 @@
<h1><a href="/index.html">Elden Ring Build Planner</a></h1>
<ul>
<li><a href="/planner.html">Build Planner</a></li>
<li><a href="/optimizer.html">Class Optimizer</a></li>
</ul>
</nav>
@ -33,4 +32,4 @@
</footer>
</body>
</html>
</html>

View File

@ -0,0 +1,39 @@
const HELMETS = fetch("/data/armor.json")
.then(response => response.json())
.then(data => data.helmets)
.catch(error => console.log(error));
const CHESTPIECES = fetch("/data/armor.json")
.then(response => response.json())
.then(data => data.chestpieces)
.catch(error => console.log(error));
const GAUNTLETS = fetch("/data/armor.json")
.then(response => response.json())
.then(data => data.gauntlets)
.catch(error => console.log(error));
const LEGGINGS = fetch("/data/armor.json")
.then(response => response.json())
.then(data => data.leggings)
.catch(error => console.log(error));
async function init() {
}
async function update() {
let sorted = sortedCandidates();
}
function sortedCandidates() {
// determine how to sort
// get most likely candidates
let candidates = findCandidates();
// sort candidates
return candidates;
}
function findCandidates() {
return [];
}

View File

@ -6,9 +6,9 @@ const TALISMANS = fetch("/data/talismans.json")
.then(response => response.json())
.then(data => data.talismans)
.catch(error => console.log(error));
const HELMS = fetch("data/armor.json")
const HELMETS = fetch("/data/helmets.json")
.then(response => response.json())
.then(data => data.helms)
.then(data => data.helmets)
.catch(error => console.log(error));
const STAT_SHORT_NAMES = [
@ -23,17 +23,17 @@ const STAT_SHORT_NAMES = [
]
async function init() {
// load and show helms
let helms = await HELMS;
helms = helms.filter(helm => helm.stats != null && helm.stats != undefined);
// populate helmet list
let helmets = await HELMETS;
helmets = helmets.filter(helmet => helmet.stats != null && helmet.stats != undefined);
let helmTemplate = document.getElementById("helm");
let helmList = document.getElementById("helms");
helms.forEach(helm => {
cloneTemplate(helmTemplate, helmList, helm);
let helmetTemplate = document.getElementById("helm");
let helmetList = document.getElementById("helmets");
helmets.forEach(helmet => {
cloneTemplate(helmetTemplate, helmetList, helmet);
});
// load and show talismans
// populate talisman list
let talismans = await TALISMANS;
talismans = talismans.filter(talisman => talisman.stats != null && talisman.stats != undefined);
@ -60,7 +60,7 @@ async function update() {
let best = sorted[0];
// get added stats from items
let items = itemStats((await TALISMANS).concat(await HELMS));
let items = itemStats((await TALISMANS).concat(await HELMETS));
// update document
document.getElementsByName("option").forEach((elem, i) => {
@ -91,12 +91,6 @@ async function update() {
}
}
function statDelta(classStats, desiredStats) {
return classStats
.map((e, i) => e < desiredStats[i] ? desiredStats[i] - e : 0)
.reduce((total, n) => total + n);
}
function sortClasses(classes, desiredStats) {
let deltas = classes.map(c => {
c.total = c.level + statDelta(c.stats, desiredStats);
@ -106,6 +100,12 @@ function sortClasses(classes, desiredStats) {
return deltas;
}
function statDelta(classStats, desiredStats) {
return classStats
.map((e, i) => e < desiredStats[i] ? desiredStats[i] - e : 0)
.reduce((total, n) => total + n);
}
function itemStats(relevantItems) {
let ids = [...document.getElementsByName("equipment")]
.filter(elem => elem.checked)
@ -118,7 +118,7 @@ function itemStats(relevantItems) {
function clearAll() {
document.getElementsByName("desired-stat").forEach(elem => elem.value = null);
[...document.getElementsByName("equipment")].forEach(elem => elem.checked = false);
document.getElementById("helmNone").checked = true;
document.getElementById("helm-none").checked = true;
update();
}

View File

@ -175,21 +175,17 @@ table {
margin-bottom: 10px;
border: 1px solid var(--border);
background-color: var(--secondary);
background-color: var(--primary);
}
td,
th {
padding: 0.5em;
border-bottom: 1px solid var(--primary);
}
thead {
font-weight: bold;
}
tbody:first-child {
font-weight: bold;
th {
border-bottom: 1px solid var(--border);
}
/* buttons & input */
@ -212,6 +208,7 @@ button {
text-align: center;
flex-grow: 1;
flex-basis: 25%;
min-width: 200px;
border: 1px solid var(--outline);
@ -273,19 +270,23 @@ button {
flex-grow: 50%;
}
.app .stat {
.app input {
text-align: center;
-webkit-appearance: none;
-moz-appearance: textfield;
margin-left: 10px;
max-width: 40px;
align-self: flex-end;
border: 1px solid var(--border);
}
.app input:is([disabled]) {
text-align: center;
background-color: var(--primary);
border: 1px solid var(--border);
}
.app .stat {
align-self: flex-end;
max-width: 40px;
margin-left: 10px;
-webkit-appearance: none;
-moz-appearance: textfield;
}
.app .stat:not([disabled]) {
@ -296,3 +297,7 @@ button {
margin-top: 2px;
margin-bottom: 4px;
}
.app select {
width: 100%;
}