diff --git a/src/armor.html b/src/armor.html
index a820e46..7187cb8 100644
--- a/src/armor.html
+++ b/src/armor.html
@@ -1,196 +1,220 @@
+
+
+
+
+
-
-
-
-
-
+
-
+
+ Erdtree - Armor Optimizer
+
+
+
+
-
- Erdtree - Armor Optimizer
-
-
-
-
+
+
+
-
-
-
+
+
+
+
+
-
-
-
-
-
+
-
+
+
+
+
+ Settings
-
-
-
-
-
- Settings
+
-
-
-
+
Max. Equip Load
-
-
-
+
+
+
Current Equip Load
-
-
-
+
+
+
Equip Load Budget
-
-
+
+
-
+
-
- Breakpoints
-
+ Breakpoints
-
+
-
+
-
+
-
+
-
- Sort by
-
+ Sort by
-
+
-
+
-
+
-
+
-
+
-
+
-
- Extras
-
+ Extras
-
+
+
+
- Filter
-
-
- Locked Items
- Clear Locked Equipment
-
-
-
- Placeholder
-
+
-
-
- Helmet
-
-
-
+
Locked Items
+
+ Placeholder
+
-
- Chestpiece
-
-
-
+
+ Helmet
+
+
-
- Gauntlets
-
-
-
+
+ Chestpiece
+
+
-
- Leggings
-
-
-
-
-
-
-
+
+ Gauntlets
+
+
-
-
-
- Sort
+
+ Leggings
+
+
-
+
+ Reset All
+
+
+
+
+
+ Results
+
+
+
@@ -226,25 +250,26 @@
-
-
+
-
-
-
-
-
-
-
-
-
- Copyright 2022 vodofrede
-
-
+
+
+
+
+
+
+
+
+ Copyright 2022 vodofrede
+
+
diff --git a/src/class.html b/src/class.html
index cd15651..9b11283 100644
--- a/src/class.html
+++ b/src/class.html
@@ -1,371 +1,270 @@
+
+
+
+
+
-
-
-
-
-
+
-
+
+ Erdtree - Class Optimizer
+
+
+
+
-
- Erdtree - Class Optimizer
-
-
-
-
+
+
+
-
-
-
+
+
+
+
+
-
-
-
-
-
+
-
-
-
-
-
-
-
-
- Class
-
-
-
-
-
- Options
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- Explanation
- The columns in the second box represent, in order:
-
-
- The total level and stats of the lowest-level class with your desired statistics.
-
-
- Desired statistics. This is where you input the stats that you definitely want your build to have.
-
-
- Calculated statistics for your build (as they should be in your level-up menu in-game).
-
-
- Calculated final statistics as shown on the "Stats" screen in-game.
- The level indicator at the top of this column indicates your "virtual" level, and is not reflected
- in-game! This statistic includes stats from your talismans and helmet.
-
-
-
- Softcaps
-
-
-
- Skill
- Stat
- Softcaps
- Notes
-
-
-
-
- Vigor
- HP
- 25 (800HP) 40 (1450HP) 60 (1900HP)
- A +12 upgraded crimson flask heals for 810HP.
-
-
- Mind
- FP
- 40 (220FP)
- A +12 upgraded cerulean flask gives 220FP.
-
-
- Endurance
- Stamina
- 30 (125stm.) 50 (155stm.)
-
-
-
-
- Equip Load
- 25 (72 wgt.) 60 (120 wgt.)
-
-
-
- Strength
- AR
- 34 ≃ 50 (2h) 54 ≃ 80 (2h) 66 ≃ 99 (2h) 80
- 2-handing gives you 1.5x strength.
-
-
- Dexterity
- AR
- 55, 80
-
-
-
- Intelligence
- AR
- 55, 80
-
-
-
-
- Spell Buff
- 60, 80
-
-
-
- Faith
- AR
- 55, 80
-
-
-
-
- Spell Buff
- 60, 80
-
-
-
- Arcane
- AR
- 55, 80
-
-
-
-
- Status
- 45, 60
-
-
-
-
- Spell Buff
- 60, 80 (Pure catalyst) 30, 45 (Hybrid catalyst)
-
-
-
-
-
-
-
-
- Copyright 2022 vodofrede
-
-
+ Softcaps
+
+
+
+ Skill
+ Stat
+ Softcaps
+ Notes
+
+
+
+
+ Vigor
+ HP
+ 25 (800HP) 40 (1450HP) 60 (1900HP)
+ A +12 upgraded crimson flask heals for 810HP.
+
+
+ Mind
+ FP
+ 40 (220FP)
+ A +12 upgraded cerulean flask gives 220FP.
+
+
+ Endurance
+ Stamina
+ 30 (125stm.) 50 (155stm.)
+
+
+
+
+ Equip Load
+ 25 (72 wgt.) 60 (120 wgt.)
+
+
+
+ Strength
+ AR
+ 34 ≃ 50 (2h) 54 ≃ 80 (2h) 66 ≃ 99 (2h) 80
+ 2-handing gives you 1.5x strength.
+
+
+ Dexterity
+ AR
+ 55, 80
+
+
+
+ Intelligence
+ AR
+ 55, 80
+
+
+
+
+ Spell Buff
+ 60, 80
+
+
+
+ Faith
+ AR
+ 55, 80
+
+
+
+
+ Spell Buff
+ 60, 80
+
+
+
+ Arcane
+ AR
+ 55, 80
+
+
+
+
+ Status
+ 45, 60
+
+
+
+
+ Spell Buff
+ 60, 80 (Pure catalyst) 30, 45 (Hybrid catalyst)
+
+
+
+
+
+
+
+ Copyright 2022 vodofrede
+
+
diff --git a/src/script/armor.js b/src/script/armor.js
index 1f2fc7d..54c9670 100644
--- a/src/script/armor.js
+++ b/src/script/armor.js
@@ -135,15 +135,8 @@ function equipLoadBudget() {
// site rendering functions
function populateSelect(templateId, destinationId, items) {
- let template = document.getElementById(templateId);
let destination = document.getElementById(destinationId);
-
items.forEach(item => {
- let clone = template.content.cloneNode(true);
-
- clone.value = item.id;
- clone.innerHTML = item.name;
-
destination.options.add(new Option(item.name, item.id));
});
}
diff --git a/src/script/class.js b/src/script/class.js
index f4e98c7..1826af8 100644
--- a/src/script/class.js
+++ b/src/script/class.js
@@ -1,44 +1,45 @@
const CLASSES = fetch("/data/classes.json")
- .then(response => response.json())
- .catch(error => console.log(error));
+ .then((response) => response.json())
+ .catch((error) => console.log(error));
const TALISMANS = fetch("/data/talismans.json")
- .then(response => response.json())
- .catch(error => console.log(error));
+ .then((response) => response.json())
+ .catch((error) => console.log(error));
const HELMETS = fetch("/data/helmets.json")
- .then(response => response.json())
- .catch(error => console.log(error));
+ .then((response) => response.json())
+ .catch((error) => console.log(error));
-const STAT_SHORT_NAMES = [
- "vig.",
- "mnd.",
- "end.",
- "str.",
- "dex.",
- "int.",
- "fth.",
- "arc."
-]
+const STAT_SHORT_NAMES = ["vig.", "mnd.", "end.", "str.", "dex.", "int.", "fth.", "arc."];
async function init() {
- // populate helmet list
- let helmets = await HELMETS;
- helmets = Object.values(helmets).filter(helmet => helmet.stats != null && helmet.stats != undefined);
- console.log(helmets)
-
- let helmetTemplate = document.getElementById("helm");
- let helmetList = document.getElementById("helmets");
- helmets.forEach(helmet => {
- cloneTemplate(helmetTemplate, helmetList, helmet);
+ // populate helmet select
+ let helmets = Object.values(await HELMETS);
+ helmets = helmets.filter((helmet) => helmet.stats != null);
+ let destination = document.getElementById("helmet");
+ helmets.forEach((helmet) => {
+ destination.options.add(new Option(helmet.name, helmet.id));
});
// populate talisman list
- let talismans = await TALISMANS;
- talismans = Object.values(talismans).filter(talisman => talisman.stats != null && talisman.stats != undefined);
+ let talismans = Object.values(await TALISMANS);
+ talismans = talismans.filter((talisman) => talisman.stats != null && !talisman.id.includes("scar"));
- let talismanTemplate = document.getElementById("talisman");
- let talismanList = document.getElementById("talismans");
- talismans.forEach(talisman => {
- cloneTemplate(talismanTemplate, talismanList, talisman);
+ let template = document.getElementById("talisman");
+ destination = document.getElementById("talismans");
+ talismans.forEach((item) => {
+ let clone = template.content.cloneNode(true);
+ let li = clone.children[0];
+
+ let input = li.children[0].children[0];
+ let label = li.children[0].children[1];
+ let aside = li.children[1];
+
+ input.id = item.id;
+ input.value = item.id;
+ label.htmlFor = item.id;
+ label.innerHTML = item.name;
+ aside.innerHTML = statsDescription(item.stats);
+
+ destination.appendChild(clone);
});
update();
@@ -46,59 +47,63 @@ async function init() {
async function update() {
// get inputted stats, clamp value to 0..99
- let desired = [...document.getElementsByName("desired-stat")].map(
- elem => {
- elem.value = Math.min(Math.max(elem.value, 0), 99) || null;
- return parseInt(elem.value) || 0;
- }
- )
+ let total = [...document.getElementsByName("total")].map((elem) => {
+ elem.value = Math.min(Math.max(elem.value, 0), 99) || null;
+ return parseInt(elem.value) || 0;
+ });
// get added stats from items
let items = itemStats(Object.values(await TALISMANS).concat(Object.values(await HELMETS)));
- desired = desired.map((stat, i) => stat - items[i]);
-
// calculate best class
- let sorted = sortClasses(await CLASSES, desired);
+ let sorted = sortClasses(
+ Object.values(await CLASSES),
+ total.map((stat, i) => stat - items[i])
+ );
let best = sorted[0];
// update document
- document.getElementsByName("option").forEach((elem, i) => {
- let [name, level] = elem.children;
- name.innerHTML = sorted[i].name;
- level.innerHTML = "lvl. " + sorted[i].total;
- })
- document.getElementById("best-class").value = best.name;
-
- document.getElementById("class-level").value = best.level;
- document.getElementById("total-level").value = best.total;
- document.getElementById("subtractive-level").value = best.total;
- document.getElementById("additive-level").value = [...document.getElementsByName("additive-stat")].reduce((total, elem, i) => {
- return total + (desired[i] > best.stats[i] ? desired[i] : best.stats[i]) + items[i];
- }, 0) - 79;
-
- document.getElementsByName("class-stat").forEach((elem, i) => elem.value = best.stats[i]);
-
- document.getElementsByName("subtractive-stat").forEach((elem, i) => {
- elem.value = ((desired[i] > best.stats[i] ? desired[i] : best.stats[i]));
+ document.getElementsByName("initial").forEach((elem, i) => (elem.value = best.stats[i]));
+ document.getElementsByName("final").forEach((elem, i) => {
+ elem.value = Math.max(total[i] - items[i], best.stats[i]);
+ });
+ document.getElementsByName("virtual").forEach((elem, i) => {
+ elem.value = Math.max(total[i], best.stats[i]);
});
- document.getElementsByName("additive-stat").forEach((elem, i) => {
- elem.value = ((desired[i] > best.stats[i] ? desired[i] : best.stats[i]) + items[i]);
+ document.getElementById("initial-level").value = best.stats.reduce((sum, n) => sum + n) - 79;
+ document.getElementById("final-level").value = best.total;
+ document.getElementById("virtual-level").value = best.total + items.reduce((sum, n) => sum + n);
+
+ // update best classes
+ document.getElementById("best").value = best.name;
+ let destination = document.getElementById("classes");
+ destination.innerHTML = "";
+ let template = document.getElementById("class");
+ sorted.forEach((c) => {
+ let clone = template.content.cloneNode(true);
+ let li = clone.children[0];
+ let span = li.children[0];
+ let aside = li.children[1];
+
+ span.innerHTML = c.name;
+ aside.innerHTML = "lvl. " + c.total;
+
+ destination.appendChild(clone);
});
// update talismans
- let talismans = [...document.getElementsByClassName("talisman")]
+ let talismans = [...document.getElementsByName("talisman")];
- if (talismans.filter(checkbox => checkbox.checked).length >= 4) {
- talismans.forEach(checkbox => checkbox.disabled = !checkbox.checked);
+ if (talismans.filter((checkbox) => checkbox.checked).length >= 4) {
+ talismans.forEach((checkbox) => (checkbox.disabled = !checkbox.checked));
} else {
- talismans.forEach(checkbox => checkbox.disabled = false);
+ talismans.forEach((checkbox) => (checkbox.disabled = false));
}
}
function sortClasses(classes, desiredStats) {
- let deltas = Object.values(classes).map(c => {
+ let deltas = classes.map((c) => {
c.total = c.level + statDelta(c.stats, desiredStats);
return c;
});
@@ -107,48 +112,33 @@ function sortClasses(classes, desiredStats) {
}
function statDelta(classStats, desiredStats) {
- return classStats
- .map((e, i) => e < desiredStats[i] ? desiredStats[i] - e : 0)
- .reduce((total, n) => total + n);
+ 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)
- .map(elem => elem.id);
- let relevant = relevantItems.filter(item => ids.includes(item.id));
+ let helmet = document.getElementById("helmet").options[document.getElementById("helmet").selectedIndex].value;
+ let talismans = [...document.getElementsByName("talisman")].filter((t) => t.checked).map((t) => t.value);
- return relevant.reduce((total, item) => total.map((stat, i) => stat += item.stats[i]), [0, 0, 0, 0, 0, 0, 0, 0]);
+ ids = [helmet, ...talismans];
+ let relevant = relevantItems.filter((item) => ids.includes(item.id));
+
+ return relevant.reduce((total, item) => total.map((stat, i) => (stat += item.stats[i])), [0, 0, 0, 0, 0, 0, 0, 0]);
}
-function clearAll() {
- document.getElementsByName("desired-stat").forEach(elem => elem.value = null);
- [...document.getElementsByName("equipment")].forEach(elem => elem.checked = false);
- document.getElementById("helm-none").checked = true;
+function reset() {
+ document.getElementsByName("total").forEach((elem) => (elem.value = null));
+ document.getElementById("helmet").selectedIndex = 0;
+ [...document.getElementsByName("talisman")].forEach((elem) => (elem.checked = false));
update();
}
function statsDescription(stats) {
return stats.reduce((total, stat, i) => {
- return stat ? (total + " +" + stat + " " + STAT_SHORT_NAMES[i]) : total;
+ return stat ? total + " +" + stat + STAT_SHORT_NAMES[i] : total;
}, "");
}
-function cloneTemplate(template, destination, item) {
- let clone = template.content.cloneNode(true);
-
- let li = clone.children[0]
- let div = li.children[0];
- let inputElement = div.children[0];
- let labelElement = div.children[1]
-
- inputElement.id = item.id;
- labelElement.for = item.id;
- labelElement.innerHTML = item.name;
-
- let aside = li.children[1];
- aside.innerHTML = statsDescription(item.stats);
-
- destination.appendChild(clone);
-}
\ No newline at end of file
+function clamp(n, min, max) {
+ return Math.min(Math.max(n, min), max);
+}
diff --git a/src/script/planner.js b/src/script/planner.js
index 83e392c..20ebc16 100644
--- a/src/script/planner.js
+++ b/src/script/planner.js
@@ -64,6 +64,8 @@ function reset(area) {
document.getElementById("class").selectedIndex = 0;
[...document.getElementsByName("stat")].forEach(stat => stat.value = 10);
break;
+ default:
+ break;
}
update();
}
diff --git a/src/style/main.css b/src/style/main.css
index 02c6c47..acbabdd 100644
--- a/src/style/main.css
+++ b/src/style/main.css
@@ -2,8 +2,8 @@
@media (prefers-color-scheme: light) {
:root {
--primary: white;
- --secondary: #f8f8ff;
- --tertiary: #f3f3f3;
+ --lighter: #f8f8ff;
+ --darker: #f3f3f3;
--border: grey;
--font-color: black;
--font-inverted: white;
@@ -14,8 +14,8 @@
@media (prefers-color-scheme: dark) {
:root {
--primary: #2b2a33;
- --secondary: #1c1b22;
- --tertiary: #1c1b22;
+ --lighter: #373641;
+ --darker: #1f1e25;
--border: black;
--font-color: white;
--font-inverted: black;
@@ -33,8 +33,7 @@ html * {
/* fonts */
html {
- font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto,
- "Helvetica Neue", Arial, "Noto Sans", sans-serif;
+ font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", Arial, "Noto Sans", sans-serif;
}
@media (max-width: 899px) {
@@ -89,7 +88,13 @@ footer {
margin-top: auto;
outline: 1px solid var(--border);
- background-color: var(--secondary);
+ background-color: var(--lighter);
+}
+
+hr {
+ color: var(--border);
+ margin-top: 0.3rem;
+ margin-bottom: 0.3rem;
}
/* nav */
@@ -100,7 +105,7 @@ nav {
align-items: center;
/* look */
- background-color: var(--secondary);
+ background-color: var(--darker);
outline: 1px solid var(--border);
}
@@ -173,12 +178,11 @@ table {
text-align: center;
width: 100%;
- border-radius: 5px;
margin-bottom: 10px;
-
border: 1px solid var(--border);
+ border-radius: 5px;
- background-color: var(--primary);
+ background-color: var(--lighter);
}
td,
@@ -194,7 +198,8 @@ th {
button {
/* border: var(--border);
border-radius: 3px;*/
- padding: 3px;
+ margin: 0rem 0rem 0.2rem 0rem;
+ padding: 0.1rem 0.3rem 0.2rem 0.3rem;
color: black;
}
@@ -202,6 +207,20 @@ label {
user-select: none;
}
+input {
+ margin: 0rem 0rem 0.2rem 0rem;
+ color: black;
+}
+
+select {
+ margin: 0rem 0rem 0.2rem 0rem;
+ color: black;
+}
+
+select * {
+ color: black;
+}
+
/* cards */
.cards {
display: flex;
@@ -219,7 +238,7 @@ label {
border-radius: 5px;
/* look */
- background-color: var(--secondary);
+ background-color: var(--lighter);
}
.cards article * {
@@ -231,96 +250,51 @@ label {
.app {
display: flex;
flex-flow: row wrap;
- justify-content: center;
-
- padding: 15px;
- border: 1px solid var(--border);
- border-radius: 5px;
- min-width: 320px;
-
- background-color: var(--secondary);
+ gap: 30px;
}
-.app > article {
+.app article {
+ display: flex;
+ flex-flow: column nowrap;
+ flex-basis: 320px;
+ flex-grow: 1;
+
+ padding: 10px;
border: 1px solid var(--border);
border-radius: 5px;
- margin: 10px;
- padding: 10px;
-
- flex-grow: 1;
- flex-basis: 320px;
+ background-color: var(--lighter);
+}
+.app article > * {
display: flex;
- flex-direction: column;
- justify-content: top;
- align-items: stretch;
+ flex-flow: row nowrap;
+ justify-content: space-between;
+ align-content: flex-start;
+}
+
+.app article input {
+ text-align: center;
+ -moz-appearance: textfield;
+}
+
+.app article select {
+ max-width: 200px;
+}
+
+.app article input[type="number"] {
+ width: 45px;
}
.app ul {
- padding-left: 0;
- padding-top: 5px;
+ width: 100%;
+ padding: 0;
margin: 0;
+ list-style: none;
+ list-style-type: none;
}
.app li {
display: flex;
justify-content: space-between;
- width: 100%;
-
- list-style: none;
-}
-
-.app li * {
- flex-grow: 50%;
-}
-
-.app input {
- text-align: center;
- border: 1px solid var(--border);
-}
-
-.app input:is([disabled]) {
- background-color: var(--tertiary);
-}
-
-.app .stat {
- align-self: flex-end;
- max-width: 40px;
-
- margin-left: 10px;
-
- -webkit-appearance: none;
- -moz-appearance: textfield;
-}
-
-.app .stat:not([disabled]) {
- color: black;
-}
-
-.app hr {
- margin-top: 2px;
- margin-bottom: 4px;
-}
-
-.select {
- display: flex;
- flex-flow: column nowrap;
- justify-content: center;
-
- width: 100%;
- gap: 10px;
-}
-
-.select * {
- text-align: center;
- display: flex;
- flex-grow: 100%;
- flex-flow: column nowrap;
-}
-
-.select select {
- border: 1px solid var(--border);
-
- background-color: var(--primary);
- color: var(--font-color);
+ word-wrap: break-word;
}