Skip to content

Instantly share code, notes, and snippets.

@ccjmne
Last active February 11, 2023 15:20
Show Gist options
  • Save ccjmne/3d9586e936732555df9052703d0110d0 to your computer and use it in GitHub Desktop.
Save ccjmne/3d9586e936732555df9052703d0110d0 to your computer and use it in GitHub Desktop.
BDO Enhancement Cost Calculator
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>PEN: Kzarka Longsword • Enhancement Cost</title>
</head>
<body>
<style type="text/css">
html,
body {
width: 100%;
height: 100%;
}
body {
margin: 0;
background-color: #333;
color: #ddd;
font-family: sans-serif;
display: flex;
gap: 30px;
justify-content: center;
align-items: center;
flex-direction: column;
}
h1,
h2 {
margin: 0;
}
h2 {
font-weight: lighter;
}
main {
display: grid;
grid-template-columns: 1fr auto 1fr;
grid-gap: 10px 20px;
align-items: center;
}
footer {
display: flex;
flex-direction: column;
align-items: center;
}
main>div {
background-color: #222;
}
#valks {
display: grid;
grid-gap: 0 5px;
}
#valks>:not(button) {
padding: 2px;
background-color: #222;
border-radius: 5px 5px 0 0;
text-align: center;
}
#valks+* {
margin-top: -20px;
}
button {
padding: 10px;
}
.align-right {
text-align: right;
}
.align-center {
text-align: center;
}
.left {
border-radius: 5px 0 0 5px;
padding-left: 20px;
}
.left>button {
margin-left: 20px;
}
.right {
border-radius: 0 5px 5px 0;
padding-right: 20px;
}
.right>button {
margin-right: 20px;
}
.lighter {
color: #888;
}
</style>
<h1>TET: Blackstar Longsword<span class="lighter"> • </span>Enhancement Cost</h1>
<div id="valks"></div>
<div>
<input type="checkbox" id="freeValks" name="freeValks">
<label for="freeValks"><span class="lighter">Consider</span> Advices of Valks <span class="lighter">to be</span> free</label>
</div>
<main>
<div class="left align-right">
<span>failures: </span>
<strong id="gY"></strong>
<button id="btnGY">👎</button>
</div>
<strong class="align-center">+1–15 Blackstar Longsword</strong>
<div class="right">
<button id="btnGN">👍</button>
<span>successes: </span>
<strong id="gN"></strong>
</div>
<div class="left align-right">
<span>failures: </span>
<strong id="kzY"></strong>
<button id="btnKzY">👎</button>
</div>
<strong class="align-center">PRI–PEN Blackstar Longsword</strong>
<div class="right">
<button id="btnKzN">👍</button>
<span>successes: </span>
<strong id="kzN"></strong>
</div>
</main>
<footer>
<h1><span class="lighter">Total: </span><span id="total"></span></h1>
<h2 class="lighter">including 775m for the base Blackstar Longsword</h2>
</footer>
<script type="text/javascript">
const material = {
bsw: {
name: 'Black Stone (Weapon)',
value: 150_000
},
bsa: {
name: 'Black Stone (Armor)',
value: 150_000
},
cmbsw: {
name: 'Concentrated Magical Black Stone (Weapon)',
value: 2_850_000
},
cmbsa: {
name: 'Concentrated Magical Black Stone (Armor)',
value: 2_200_000
},
hbcs: {
name: 'Hard Black Crystal Shard',
value: 1_500_000
},
sbcs: {
name: 'Sharp Black Crystal Shard',
value: 2_100_000
},
meme: {
name: 'Memory Fragment',
value: 3_000_000
},
flawless: {
name: 'Flawless Magical Black Stone',
value: 8_000_000
},
}
function humanise(value) {
if (!value) {
return String(0);
}
let v = value;
const b = Math.floor(v / 1_000_000_000);
v = v % 1_000_000_000;
const m = Math.floor(v / 1_000_000);
v = v % 1_000_000;
const k = Math.floor(v / 1_000);
return `${b ? `${b}b ` : ''}${m ? `${m}m ` : ''}${k ? `${k}k ` : ''}`;
}
const valks = [
[20, 10_000_000],
[30, 25_000_000],
[40, 80_000_000],
[50, 200_000_000],
[60, 400_000_000],
[70, 700_000_000],
[80, 1_200_000_000],
[90, 1_900_000_000],
[100, 2_800_000_000],
].map(([stack, value]) => {
const button = document.createElement('button');
button.textContent = `+${stack}`;
const display = document.createElement('strong');
return {
name: `Advice of Valks (+${stack})`,
value,
display,
button
};
});
document.querySelector('#valks').style.gridTemplateColumns = `repeat(${valks.length}, auto)`;
document.querySelector('#valks').append(
...valks.map(({
display
}) => display),
...valks.map(({
button
}) => button)
);
const recipes = [{
name: '+1–15 Longsword Attempt (Fail)',
value: material['cmbsw'].value + 10 * material['meme'].value,
display: document.querySelector('#gY'),
button: document.querySelector('#btnGY'),
}, {
name: '+1–15 Longsword Attempt (Success)',
value: material['cmbsw'].value,
display: document.querySelector('#gN'),
button: document.querySelector('#btnGN'),
}, {
name: 'PRI–PEN Longsword Attempt (Fail)',
value: material['flawless'].value + 20 * material['meme'].value,
display: document.querySelector('#kzY'),
button: document.querySelector('#btnKzY'),
}, {
name: 'PRI–PEN Longsword Attempt (Success)',
value: material['flawless'].value,
display: document.querySelector('#kzN'),
button: document.querySelector('#btnKzN'),
}, ...valks];
const recipesCounts = JSON.parse(localStorage.getItem('recipes-used')) || {};
const total = document.querySelector('#total');
const basePrice = 775_000_000;
function update() {
recipes.forEach(({
name,
display
}) => display.textContent = String(recipesCounts[name] || 0));
total.textContent = humanise(recipes.reduce((cost, {
name,
value
}) => cost + ((document.querySelector('#freeValks').checked && /Advice of Valks/.test(name)) ? 0 : (recipesCounts[name] || 0) * value), basePrice));
localStorage.setItem('recipes-used', JSON.stringify(recipesCounts));
}
document.querySelector('#freeValks').addEventListener('change', update);
update();
recipes.forEach(({
name,
button
}) => {
button.addEventListener('click', e => {
recipesCounts[name] = (recipesCounts[name] || 0) + 1;
update();
});
button.addEventListener('contextmenu', e => {
recipesCounts[name] = Math.max(0, (recipesCounts[name] || 0) - 1);
e.preventDefault();
update();
});
});
</script>
</body>
</html>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment