Skip to content

Commit 54d7e08

Browse files
authored
Create script.js
1 parent 148147c commit 54d7e08

1 file changed

Lines changed: 325 additions & 0 deletions

File tree

js/script.js

Lines changed: 325 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,325 @@
1+
// ---------- Utility ----------
2+
const defaultValues = {
3+
baseHeightFt: 4,
4+
baseHeightIn: 8,
5+
heightMethod: "manual",
6+
heightManualInput: 10,
7+
heightDiceCount: 2,
8+
heightDiceType: 10,
9+
baseWeight: 110,
10+
weightMethod: "manual",
11+
weightManualInput: 3,
12+
weightDiceCount: 2,
13+
weightDiceType: 4
14+
};
15+
16+
// ---------- Calculation Expressions ----------
17+
let heightRollExpression = "";
18+
let weightRollExpression = "";
19+
20+
function rollDice(count, type) {
21+
let rolls = [];
22+
let total = 0;
23+
24+
for (let i = 0; i < count; i++) {
25+
let roll = Math.floor(Math.random() * type) + 1;
26+
rolls.push(roll);
27+
total += roll;
28+
}
29+
30+
return {
31+
total: total,
32+
rolls: rolls
33+
};
34+
}
35+
36+
function inchesToFeetInches(inches) {
37+
let ft = Math.floor(inches / 12);
38+
let inch = inches % 12;
39+
return `${ft} ft ${inch} in`;
40+
}
41+
42+
function inchesToCm(inches) {
43+
return (inches * 2.54).toFixed(1);
44+
}
45+
46+
function lbsToKg(lbs) {
47+
return (lbs * 0.453592).toFixed(1);
48+
}
49+
50+
function calculateBMI(weightLbs, heightInches) {
51+
let kg = weightLbs * 0.453592;
52+
let m = heightInches * 0.0254;
53+
return (kg / (m * m)).toFixed(1);
54+
}
55+
56+
function getBuildCategoryFromBMI(bmi) {
57+
bmi = parseFloat(bmi);
58+
59+
if (bmi < 18) return "Slender";
60+
if (bmi < 25) return "Average";
61+
if (bmi < 30) return "Broad";
62+
return "Massive";
63+
}
64+
65+
function getBuildColor(category) {
66+
switch (category) {
67+
case "Slender":
68+
return "#4da6ff";
69+
case "Average":
70+
return "#4caf50";
71+
case "Broad":
72+
return "#ff9800";
73+
case "Massive":
74+
return "#f44336";
75+
default:
76+
return "#000000";
77+
}
78+
}
79+
80+
function getBMICategory(bmi) {
81+
bmi = parseFloat(bmi);
82+
83+
if (bmi < 18.5) return "Underweight";
84+
if (bmi < 25) return "Healthy";
85+
if (bmi < 30) return "Overweight";
86+
if (bmi < 35) return "Obesity (Class I)";
87+
if (bmi < 40) return "Obesity (Class II - Severe)";
88+
return "Obesity (Class III - Morbid)";
89+
}
90+
91+
function getBMIColor(category) {
92+
switch (category) {
93+
case "Underweight":
94+
return "#4da6ff";
95+
case "Healthy":
96+
return "#4caf50";
97+
case "Overweight":
98+
return "#ff9800";
99+
case "Obesity (Class I)":
100+
return "#f44336";
101+
case "Obesity (Class II - Severe)":
102+
return "#c62828";
103+
case "Obesity (Class III - Morbid)":
104+
return "#8e0000";
105+
default:
106+
return "#000000";
107+
}
108+
}
109+
110+
// ---------- LocalStorage ----------
111+
function saveToLocalStorage() {
112+
const inputs = document.querySelectorAll("input, select");
113+
const data = {};
114+
115+
inputs.forEach(input => {
116+
data[input.id] = input.value;
117+
});
118+
119+
localStorage.setItem("dndCharacterCalc", JSON.stringify(data));
120+
}
121+
122+
function loadFromLocalStorage() {
123+
const saved = localStorage.getItem("dndCharacterCalc");
124+
if (!saved) return;
125+
126+
const data = JSON.parse(saved);
127+
128+
Object.keys(data).forEach(id => {
129+
const element = document.getElementById(id);
130+
if (element) {
131+
element.value = data[id];
132+
}
133+
});
134+
135+
syncHeightUI();
136+
syncWeightUI();
137+
}
138+
139+
// ---------- Toggle Visibility ----------
140+
document.getElementById("heightMethod").addEventListener("change", function() {
141+
document.getElementById("heightManual").style.display =
142+
this.value === "manual" ? "contents" : "none";
143+
document.getElementById("heightDigital").style.display =
144+
this.value === "digital" ? "contents" : "none";
145+
});
146+
147+
document.getElementById("weightMethod").addEventListener("change", function() {
148+
document.getElementById("weightManual").style.display =
149+
this.value === "manual" ? "block" : "none";
150+
document.getElementById("weightDigital").style.display =
151+
this.value === "digital" ? "block" : "none";
152+
});
153+
154+
// ---------- Roll Buttons ----------
155+
document.getElementById("rollHeight").addEventListener("click", function() {
156+
let count = parseInt(document.getElementById("heightDiceCount").value);
157+
let type = parseInt(document.getElementById("heightDiceType").value);
158+
159+
let rollData = rollDice(count, type);
160+
let result = rollData.total;
161+
let rolls = rollData.rolls;
162+
163+
document.getElementById("heightRollResult").value = result;
164+
165+
heightRollExpression = `${count}d${type} [${rolls.join(" + ")} = ${result}]`;
166+
});
167+
168+
document.getElementById("rollWeight").addEventListener("click", function() {
169+
let count = parseInt(document.getElementById("weightDiceCount").value);
170+
let type = parseInt(document.getElementById("weightDiceType").value);
171+
172+
let rollData = rollDice(count, type);
173+
let result = rollData.total;
174+
let rolls = rollData.rolls;
175+
176+
document.getElementById("weightRollResult").value = result;
177+
178+
weightRollExpression = `${count}d${type} [${rolls.join(" + ")} = ${result}]`;
179+
});
180+
181+
// ---------- Calculation ----------
182+
document.getElementById("calculate").addEventListener("click", function() {
183+
184+
let baseFt = parseInt(document.getElementById("baseHeightFt").value);
185+
let baseIn = parseInt(document.getElementById("baseHeightIn").value);
186+
let baseHeight = baseFt * 12 + baseIn;
187+
188+
let baseWeight = parseFloat(document.getElementById("baseWeight").value);
189+
190+
let heightModifier =
191+
document.getElementById("heightMethod").value === "manual" ?
192+
parseInt(document.getElementById("heightManualInput").value) :
193+
parseInt(document.getElementById("heightRollResult").value);
194+
if (document.getElementById("heightMethod").value === "manual") {
195+
heightRollExpression = `[${heightModifier}]`;
196+
}
197+
198+
let weightModifier =
199+
document.getElementById("weightMethod").value === "manual" ?
200+
parseInt(document.getElementById("weightManualInput").value) :
201+
parseInt(document.getElementById("weightRollResult").value);
202+
if (document.getElementById("weightMethod").value === "manual") {
203+
weightRollExpression = `[${weightModifier}]`;
204+
}
205+
206+
let finalHeight = baseHeight + heightModifier;
207+
// let finalWeight = baseWeight + weightModifier;
208+
let finalWeight = baseWeight + (heightModifier * weightModifier);
209+
210+
let bmi = calculateBMI(finalWeight, finalHeight);
211+
let build = getBuildCategoryFromBMI(bmi);
212+
let color = getBuildColor(build);
213+
let bmiCategory = getBMICategory(bmi);
214+
let bmiColor = getBMIColor(bmiCategory);
215+
216+
document.getElementById("result").innerHTML = `
217+
<div class="resultCard">
218+
<h2>Result</h2>
219+
<div class="resultRow">
220+
<div class="resultLabel">Height</div>
221+
<div class="resultValue"> ${inchesToFeetInches(finalHeight)} <br>
222+
<span class="resultSub">${inchesToCm(finalHeight)} cm</span>
223+
</div>
224+
</div>
225+
<div class="resultRow">
226+
<div class="resultLabel">Weight</div>
227+
<div class="resultValue"> ${finalWeight} lbs <br>
228+
<span class="resultSub">${lbsToKg(finalWeight)} kg</span>
229+
</div>
230+
</div>
231+
<div class="resultRow">
232+
<div class="resultLabel">Build</div>
233+
<div class="resultValue" style="color:${color}; font-weight:bold;"> ${build} </div>
234+
</div>
235+
<div class="resultRow">
236+
<div class="resultLabel">BMI <br>
237+
<span class="resultLabelSub">Human-equivalent</span>
238+
</div>
239+
<div class="resultValue">
240+
<span style="color:${bmiColor}; font-weight:bold;"> ${bmi}</span>
241+
<br>
242+
<span style="color:${bmiColor};"> ${bmiCategory} </span>
243+
</div>
244+
</div>
245+
<details style="margin-top:20px;">
246+
<summary style="cursor:pointer;">Show Calculation Details</summary>
247+
<div style="margin-top:10px; font-family:monospace; line-height: 1.5em;">
248+
<div style="margin-bottom:10px;">
249+
<strong>Height:</strong>
250+
<br> ${baseFt} ft ${baseIn} in + ${heightRollExpression} in <br> = ${inchesToFeetInches(finalHeight)}
251+
</div>
252+
<div>
253+
<strong>Weight:</strong>
254+
<br> ${baseWeight} lbs + (${heightRollExpression} × ${weightRollExpression}) lbs <br> = ${finalWeight} lbs
255+
</div>
256+
</div>
257+
</details>
258+
</div>
259+
`;
260+
});
261+
262+
document.getElementById("reset").addEventListener("click", function() {
263+
264+
Object.keys(defaultValues).forEach(id => {
265+
const element = document.getElementById(id);
266+
if (element) {
267+
element.value = defaultValues[id];
268+
}
269+
});
270+
271+
localStorage.removeItem("dndCharacterCalc");
272+
273+
syncHeightUI();
274+
syncWeightUI();
275+
276+
document.getElementById("heightRollResult").value = defaultValues.heightManualInput;
277+
document.getElementById("weightRollResult").value = defaultValues.weightManualInput;
278+
279+
heightRollExpression = `[${defaultValues.heightManualInput}]`;
280+
weightRollExpression = `[${defaultValues.weightManualInput}]`;
281+
document.getElementById("result").innerHTML = "";
282+
});
283+
// ---------- Credits toggle ----------
284+
document.querySelector("footer a").addEventListener("click", function(event) {
285+
// event.preventDefault();
286+
287+
document.querySelector(".calculator").style.display = "none";
288+
document.querySelector(".credits").style.display = "block";
289+
});
290+
291+
document.getElementById("backToCalculator").addEventListener("click", function() {
292+
document.querySelector(".calculator").style.display = "flex";
293+
document.querySelector(".credits").style.display = "none";
294+
});
295+
// ---------- Auto Save ----------
296+
document.querySelectorAll("input, select").forEach(element => {
297+
element.addEventListener("change", saveToLocalStorage);
298+
});
299+
// ---------- Initial UI Sync ----------
300+
function syncHeightUI() {
301+
const method = document.getElementById("heightMethod").value;
302+
document.getElementById("heightManual").style.display =
303+
method === "manual" ? "contents" : "none";
304+
document.getElementById("heightDigital").style.display =
305+
method === "digital" ? "contents" : "none";
306+
}
307+
308+
function syncWeightUI() {
309+
const method = document.getElementById("weightMethod").value;
310+
document.getElementById("weightManual").style.display =
311+
method === "manual" ? "block" : "none";
312+
document.getElementById("weightDigital").style.display =
313+
method === "digital" ? "block" : "none";
314+
}
315+
316+
syncHeightUI();
317+
syncWeightUI();
318+
loadFromLocalStorage();
319+
if (!localStorage.getItem("dndCharacterCalc")) {
320+
document.getElementById("heightRollResult").value = defaultValues.heightManualInput;
321+
document.getElementById("weightRollResult").value = defaultValues.weightManualInput;
322+
323+
heightRollExpression = `[${defaultValues.heightManualInput}]`;
324+
weightRollExpression = `[${defaultValues.weightManualInput}]`;
325+
}

0 commit comments

Comments
 (0)