318 lines
10 KiB
JavaScript
Executable File
318 lines
10 KiB
JavaScript
Executable File
class Dice {
|
|
constructor(sides, addition = 0, count = 1, color = "#000") {
|
|
this.sides = sides;
|
|
this.addition = addition;
|
|
this.count = count;
|
|
this.color = color;
|
|
this.selected = false;
|
|
}
|
|
}
|
|
|
|
class DiceHistoryEntry {
|
|
constructor(dice = undefined, formula = undefined, result = undefined) {
|
|
this.dice = dice;
|
|
this.formula = formula;
|
|
this.result = result;
|
|
}
|
|
}
|
|
|
|
const default_sides = [4, 6, 8, 10, 12, 20, 100];
|
|
const default_colors = ["#de324c", "#f4895f", "#f8e16f", "#95cf92", "#369acc", "#9656a2", "#000000"];
|
|
|
|
let darkMode = window.matchMedia && window.matchMedia('(prefers-color-scheme: dark)').matches;
|
|
|
|
let dices = [];
|
|
let history = [];
|
|
|
|
let dicesContainer = document.getElementById("dices");
|
|
let historyContainer = document.getElementById("history");
|
|
|
|
function getDiceLabel(dice) {
|
|
return (dice.count > 1 ? dice.count : "") + "D" + dice.sides + (dice.addition ? (dice.addition < 0 ? "-" : "+") + Math.abs(dice.addition) : "");
|
|
}
|
|
|
|
function renderDice(dice, index) {
|
|
const diceElement = document.createElement("div");
|
|
diceElement.classList.add("dice");
|
|
|
|
const diceImage = document.createElement("div");
|
|
diceImage.classList.add("dice-image");
|
|
if (default_sides.indexOf(dice.sides) != -1) {
|
|
diceImage.classList.add("dice-image-" + dice.sides);
|
|
} else {
|
|
diceImage.classList.add("dice-image-custom");
|
|
}
|
|
if (dice.color) {
|
|
diceImage.style.backgroundColor = dice.color;
|
|
// revert b/w on dark-mode
|
|
if (darkMode) {
|
|
if (["#000", "#000000", "black", "rgb(0,0,0)", "rgb(0, 0, 0)"].indexOf(dice.color) != -1) {
|
|
diceImage.style.backgroundColor = "#fff";
|
|
} else if (["#fff", "#ffffff", "white", "rgb(255,255,255)", "rgb(255, 255, 255)"].indexOf(dice.color) != -1) {
|
|
diceImage.style.backgroundColor = "#000";
|
|
}
|
|
}
|
|
}
|
|
|
|
const diceImageContainer = document.createElement("div");
|
|
diceImageContainer.classList.add("dice-image-container");
|
|
diceImageContainer.onclick = function () {
|
|
if (dices[index].selected) {
|
|
dices[index].selected = false;
|
|
diceElement.classList.remove("selected");
|
|
} else {
|
|
dices[index].selected = true;
|
|
diceElement.classList.add("selected");
|
|
}
|
|
|
|
if (dices.filter((dice) => dice.selected).length) {
|
|
document.getElementById('roll-button').classList.remove("disabled");
|
|
} else {
|
|
document.getElementById('roll-button').classList.add("disabled");
|
|
}
|
|
|
|
localStorage.setItem('dices', JSON.stringify(dices));
|
|
};
|
|
diceImageContainer.appendChild(diceImage);
|
|
|
|
diceElement.appendChild(diceImageContainer);
|
|
|
|
const diceLabelContainer = document.createElement("div");
|
|
diceLabelContainer.classList.add("label-container");
|
|
|
|
const diceLabel = document.createElement("label");
|
|
diceLabel.innerText = getDiceLabel(dice);
|
|
|
|
diceLabelContainer.appendChild(diceLabel);
|
|
diceElement.appendChild(diceLabelContainer);
|
|
|
|
const diceRemove = document.createElement("div");
|
|
diceRemove.classList.add("remove");
|
|
diceRemove.onclick = function () {
|
|
removeDice(index);
|
|
};
|
|
diceElement.appendChild(diceRemove);
|
|
|
|
if (dice.selected) {
|
|
diceElement.classList.add("selected");
|
|
} else {
|
|
diceElement.classList.remove("selected");
|
|
}
|
|
|
|
|
|
dicesContainer.appendChild(diceElement);
|
|
}
|
|
|
|
function renderDices() {
|
|
dicesContainer.innerHTML = "";
|
|
dices.forEach((dice, index) => {
|
|
renderDice(dice, index);
|
|
})
|
|
|
|
if (dices.filter((dice) => dice.selected).length) {
|
|
document.getElementById('roll-button').classList.remove("disabled");
|
|
} else {
|
|
document.getElementById('roll-button').classList.add("disabled");
|
|
}
|
|
}
|
|
|
|
function addDice(sides, addition = 0, count = 1, color = "#000") {
|
|
dices.push(new Dice(sides, addition, count, color));
|
|
localStorage.setItem('dices', JSON.stringify(dices));
|
|
renderDices();
|
|
}
|
|
|
|
function removeDice(index) {
|
|
dices.splice(index, 1);
|
|
localStorage.setItem('dices', JSON.stringify(dices));
|
|
renderDices();
|
|
}
|
|
|
|
function resetDices() {
|
|
dices = [];
|
|
default_sides.forEach((side, i) => {
|
|
dices.push(new Dice(side, 0, 1, default_colors[i]));
|
|
});
|
|
localStorage.setItem('dices', JSON.stringify(dices));
|
|
renderDices();
|
|
}
|
|
|
|
|
|
function addDiceForm() {
|
|
let inputSides = document.getElementById("inputSides");
|
|
if (!inputSides.value) {
|
|
inputSides = document.getElementById("inputCustom")
|
|
}
|
|
const inputAddition = document.getElementById("inputAddition");
|
|
const inputCount = document.getElementById("inputCount");
|
|
const inputColor = document.getElementById("inputColor");
|
|
addDice(+inputSides.value, +inputAddition.value, +inputCount.value, inputColor.value);
|
|
}
|
|
|
|
function setDicesContainer(container) {
|
|
dicesContainer = container;
|
|
}
|
|
|
|
function renderHistory() {
|
|
historyContainer.innerHTML = "";
|
|
if (history.length) {
|
|
document.getElementById('history-button').classList.remove("disabled");
|
|
} else {
|
|
document.getElementById('history-button').classList.add("disabled");
|
|
}
|
|
history.forEach((entry) => {
|
|
if (entry.dice && entry.result) {
|
|
const entryElement = document.createElement("div");
|
|
entryElement.classList.add("entry");
|
|
const diceLabel = document.createElement("label");
|
|
diceLabel.innerHTML = getDiceLabel(entry.dice) + ": ";
|
|
diceLabel.style.color = entry.dice.color;
|
|
// revert b/w on dark-mode
|
|
if (darkMode) {
|
|
if (["#000", "#000000", "black", "rgb(0,0,0)", "rgb(0, 0, 0)"].indexOf(entry.dice.color) != -1) {
|
|
diceLabel.style.color = "#fff";
|
|
} else if (["#fff", "#ffffff", "white", "rgb(255,255,255)", "rgb(255, 255, 255)"].indexOf(entry.dice.color) != -1) {
|
|
diceLabel.style.color = "#000";
|
|
}
|
|
}
|
|
entryElement.appendChild(diceLabel);
|
|
|
|
const diceResult = document.createElement("span");
|
|
diceResult.innerText = entry.result;
|
|
entryElement.appendChild(diceResult);
|
|
|
|
const diceFormula = document.createElement("span");
|
|
const diceEqual = document.createElement("span");
|
|
entryElement.appendChild(diceEqual);
|
|
entryElement.appendChild(diceFormula);
|
|
|
|
if (entry.formula) {
|
|
diceFormula.innerText = entry.formula;
|
|
diceEqual.innerText = " = "
|
|
}
|
|
|
|
historyContainer.appendChild(entryElement);
|
|
} else {
|
|
historyContainer.appendChild(document.createElement("hr"));
|
|
}
|
|
})
|
|
}
|
|
|
|
function roll(dice) {
|
|
let formula = "";
|
|
for (let index = 0; index < dice.count; index++) {
|
|
formula += Math.floor(Math.random() * dice.sides + 1);
|
|
if (index < dice.count - 1) {
|
|
formula += " + ";
|
|
}
|
|
}
|
|
if (dice.addition) {
|
|
formula += " + " + dice.addition;
|
|
}
|
|
const result = eval(formula);
|
|
if (formula.indexOf("+") == -1) {
|
|
formula = "";
|
|
}
|
|
history.unshift(new DiceHistoryEntry(dice, formula, result));
|
|
localStorage.setItem('history', JSON.stringify(history));
|
|
renderHistory();
|
|
}
|
|
|
|
function rollSelected() {
|
|
if (dices.filter((dice) => dice.selected).length) {
|
|
if (history.length) {
|
|
history.unshift(new DiceHistoryEntry());
|
|
}
|
|
dices.forEach((dice) => {
|
|
if (dice.selected) {
|
|
roll(dice);
|
|
}
|
|
})
|
|
}
|
|
}
|
|
|
|
function clearHistory() {
|
|
history = [];
|
|
localStorage.removeItem('history');
|
|
renderHistory();
|
|
}
|
|
|
|
function exportData() {
|
|
const downloadButton = document.createElement('a');
|
|
downloadButton.setAttribute('href', 'data:application/json;charset=utf-8,' + encodeURIComponent(JSON.stringify({ dices: dices, history: history })));
|
|
downloadButton.setAttribute('download', 'rgp-dices-' + new Date().toISOString() + '.json');
|
|
document.body.appendChild(downloadButton);
|
|
downloadButton.click();
|
|
document.body.removeChild(downloadButton);
|
|
}
|
|
|
|
function importData(event) {
|
|
event.target.parentElement.classList.remove("error");
|
|
try {
|
|
const reader = new FileReader();
|
|
reader.addEventListener('load', async (event) => {
|
|
const data = JSON.parse(event.target.result);
|
|
if (data.dices) {
|
|
dices = data.dices;
|
|
renderDices();
|
|
}
|
|
if (data.history) {
|
|
history = data.history;
|
|
renderHistory();
|
|
}
|
|
});
|
|
|
|
reader.readAsText(event.target.files[0]);
|
|
} catch (e) {
|
|
console.warn(e);
|
|
event.target.parentElement.classList.add("error");
|
|
}
|
|
}
|
|
|
|
function updateCustom() {
|
|
if (!document.getElementById("inputSides").value) {
|
|
document.getElementById("inputCustom").classList.remove("hidden");
|
|
} else {
|
|
document.getElementById("inputCustom").classList.add("hidden");
|
|
}
|
|
}
|
|
|
|
function toggleDarkMode() {
|
|
if (darkMode) {
|
|
darkMode = false;
|
|
document.body.classList.remove("dark");
|
|
document.getElementById("dark-mode-icon").src = "./assets/dark.svg";
|
|
document.getElementById("dark-mode-text").innerText = "Dark Mode";
|
|
} else {
|
|
darkMode = true;
|
|
document.body.classList.add("dark");
|
|
document.getElementById("dark-mode-icon").src = "./assets/light.svg";
|
|
document.getElementById("dark-mode-text").innerText = "Light Mode";
|
|
}
|
|
renderDices();
|
|
renderHistory();
|
|
}
|
|
|
|
if (localStorage.getItem('dices')) {
|
|
dices = JSON.parse(localStorage.getItem('dices'));
|
|
} else {
|
|
default_sides.forEach((side, i) => {
|
|
dices.push(new Dice(side, 0, 1, default_colors[i]));
|
|
})
|
|
}
|
|
|
|
if (localStorage.getItem('history')) {
|
|
history = JSON.parse(localStorage.getItem('history'));
|
|
}
|
|
|
|
document.getElementById("importFile").addEventListener("change", importData);
|
|
|
|
renderDices();
|
|
renderHistory();
|
|
updateCustom();
|
|
|
|
if (darkMode) {
|
|
document.body.classList.add("dark");
|
|
document.getElementById("dark-mode-icon").src = "./assets/light.svg";
|
|
document.getElementById("dark-mode-text").innerText = "Light Mode";
|
|
} |