This commit is contained in:
Turtle committed 2026-01-11 10:26:39 +01:00
1 parent 565c1b9911
commit 28490ce8b3
36 files changed
+587 -179

No files matched your search

+212
View File
@@ -0,0 +1,212 @@
const getSkillTree = () => ({
id: "root",
text: "Skill-Tree",
children: [
{
text: "Dark-Mode",
id: "dark_mode",
description: "Ändert das Aussehen zu einem dunklen Design!",
collision: ["pink_mode"],
children: [
{
text: "Pink-Mode",
description: "Ändert das Aussehen zu einem pinken Design!",
id: "pink_mode",
collision: ["dark_mode"],
},
{
text: "Accent-Color",
description: "Verändere die Primärfarbe",
id: "accent_color",
call: `chooseAccentColor();`,
call_unset: `unsetAccentColor()`
}
]
},
{
text: "Profilbild",
id: "profile_pic",
description: "Erlange die Fähigkeit, das Profilbild zu ändern",
children: [
{
text: "Einfacher Rahmen",
id: "simple_border",
description: "Ein einfacher Rahmen, der sich um das Profilbild legt",
collision: ["gold_border", "epic_border"],
children: [
{
text: "Gold-Rahmen",
id: "gold_border",
description: "Ein goldener Rahmen, der sich um das Profilbild legt",
collision: ["simple_border", "epic_border"],
children: []
},
{
text: "Epic-Rahmen",
id: "epic_border",
description: "Ein epischer Rahmen, der sich um das Profilbild legt",
collision: ["simple_border", "gold_border"],
children: [
{
text: "Ehren-Titel",
id: "title_of_honor",
description: "Kriege den Ehrentitel \"Sir\" verliehen"
}
]
}
]
}
],
}
]
});
const _skillCb = {
"dark_mode": function() {
document.body.style = "background: black; color: white;";
},
"dark_mode_unset": function() {
document.body.style = "background: unset; color: unset;";
},
"pink_mode": function() {
document.body.style = `background: rgba(242, 199, 252, 1); color: #5a076d;`;
},
"pink_mode_unset": function() {
_skillCb.dark_mode_unset();
},
"accent_color": function() {
const storage = (userData.skillStorage ??= {})["accent_color"];
if (!storage) return;
const rgb = storage.join(",");
setRootStyle("--accent_color_fg", `rgba(${rgb}, 1)`);
setRootStyle("--accent_color_fg_o", `rgba(${rgb}, 0.5)`);
setRootStyle("--accent_color_bg", `rgba(${rgb}, 1)`);
setRootStyle("--accent_color_bg_o", `rgba(${rgb}, 0.5)`);
setRootStyle("--accent_color_bg_o2", `rgba(${rgb}, 0.25)`);
},
"accent_color_unset": function() {
removeRootStyle("--accent_color_fg");
removeRootStyle("--accent_color_fg_o");
removeRootStyle("--accent_color_bg");
removeRootStyle("--accent_color_bg_o");
removeRootStyle("--accent_color_bg_o2");
},
"simple_border": function() {
setProfileBorder("../imgs/simple_border.png", 8);
},
"unset_simple_border": () => unsetProfileBorder(),
"gold_border": function() {
setProfileBorder("../imgs/gold_border.png", 8);
},
"unset_gold_border": () => unsetProfileBorder(),
"epic_border": function() {
setProfileBorder("../imgs/epic_border.png", 8);
},
"unset_epic_border": () => unsetProfileBorder(),
"title_of_honor": function() {},
"profile_pic": () => updateEverything()
};
function updateEverything() {
updateAllProfiles(userData);
refreshOverlays();
}
function chooseAccentColor() {
var elm = getId("skill_chooseAccentColor");
if (!elm) {
elm = document.createElement("overlay");
elm.setAttribute("id", "skill_chooseAccentColor");
elm.innerHTML = `
<div class="overlay_title">Wähle eine Farbe:</div><br>
<input type="color" style="width: 100%; border-radius: var(--border-radius);"><br><br>
<button onclick="setAccentColor(this)" style="width: 100%; border-radius: var(--border-radius); font-size: 18px; padding: 10px; background: rgba(255, 255, 255, 0.5);">Bestätigen</button>
`;
document.body.appendChild(elm);
}
setTimeout(() => showOverlay("skill_chooseAccentColor"), 1);
}
function unsetAccentColor() {
userData.skillStorage ??= {};
userData.skillStorage["accent_color"] = null;
updateUserData(new CouchDB());
}
function setAccentColor(elm) {
const input = elm.parentElement.querySelector("input");
const rgba = hexToRGBA(input.value);
userData.skillStorage ??= {};
userData.skillStorage["accent_color"] = rgba;
updateUserData(new CouchDB());
hideOverlay("skill_chooseAccentColor");
_skillCb.accent_color();
updateEverything()
}
//--------------------------------------------//
function unsetProfileBorder() {
const elms = document.getElementsByClassName("profile");
for (var i of elms) i.innerHTML = '';
}
function setProfileBorder(src, x) {
const elms = document.getElementsByClassName("profile");
const style1 = `
width: 67px;
height: 67px;
border-radius: 50%;
border: none;
background-size: 67px 67px;
position: absolute;
background-image: url('${src}');
transform: translate(-${x}px, calc(-50%));
`;
for (var i of elms) {
i.innerHTML = `<div class="border" style="${style1}"></div>`;
}
const style2 = `
width: 160px;
height: 160px;
border-radius: 50%;
border: none;
background-size: 160px 160px;
position: absolute;
background-image: url('${src}');
transform: translate(-${x*1.2}px, -8px);
`;
const profilPic = getId("profile-pic");
if (profilPic) {
profilPic.innerHTML = `<div class="border" style="${style2}"></div>`;
}
}
function setRootStyle(key, value) {
document.documentElement.style.setProperty(key, value);
}
function removeRootStyle(key) {
document.documentElement.style.removeProperty(key);
}
function exeSkill(id, activate = true) {
const cb = _skillCb[activate ? id: id+"_unset"];
if (typeof(cb) != "function") return;
try { cb(); } catch(err) { console.error(err); }
}
var globalSkills = [];
async function runSkills() {
const skills = userData.enabled_abilities;
globalSkills = skills;
for (var i of skills) exeSkill(i, true);
}
userDataListener.push(runSkills);
+294
View File
@@ -0,0 +1,294 @@
//=> use showSkillTree() -> void;
//=> use playLevelSound() -> void;
//=> use playXPSound() -> void;
var aSkillPoints = 0;
function showSkillTree() {
var elm = getId("skill_tree_overlay");
if (!elm) {
elm = document.createElement("overlay");
elm.setAttribute("id", "skill_tree_overlay");
document.body.appendChild(elm);
}
elm.innerHTML = ``;
const div = document.createElement("div");
div.style = `
display: inline-block;
width: 100%;
height: 100%;
overflow: auto;
margin-top: 20px;
text-align: center;
color: black;
`;
var res = generateSkillTree(getSkillTree(), userData.abilities)
div.appendChild(res[0]);
aSkillPoints = userData.level - res[1];
elm.appendChild(div);
const div2 = document.createElement("div");
div2.style = `
display: inline-block;
width: 100%;
text-align: center;
margin-top: 20px;
`;
div2.innerHTML = `
<div style="padding: 10px 30px; background: rgba(255, 255, 255, 0.6); border-radius: var(--border-radius); display: inline-block;" class="do-not-color-me">
Skill-Points: <span class="aSkillPoints">${aSkillPoints}</span>
</div>
`;
elm.appendChild(div2);
showOverlay("skill_tree_overlay");
}
function _getRect(parent, data) {
var elm = getId("skill_tree_details_overlay");
if (!elm) {
elm = document.createElement("overlay");
elm.setAttribute("id", "skill_tree_details_overlay");
document.body.appendChild(elm);
}
const isEnabled = userData.abilities.includes(data.id);
elm.innerHTML = '';
const div = document.createElement("div");
div.style = `display: inline-block; width: 100%; min-width: 300px; text-align: center; color: black;`;
div.innerHTML = `
<b style="display: inline-block; margin-top: 5px;">${data.text}</b><br><br>
<span>${data.description}</span><br><br>
<span style="display: inline-block; border: 1px solid black; background: rgba(255, 255, 255, 0.3); width: 100%; border-radius: var(--border-radius); padding: 10px;">${isEnabled ?
"<span style='color: green;'>Im Besitz</span>":
"<span style='color: red;'>Noch nicht freigeschaltet</span>"
}</span><br><br>
`;
const bttnStyle = `display: inline-block; width: 100%; border-radius: var(--border-radius); padding: 10px; font-size: 18px; font-weight: normal; background: rgba(255, 255, 255, 0.3);`;
const bttnStyleDisabled = bttnStyle + `border: 1px solid black; opacity: 0.7;`;
if (isEnabled) {
const eAblities = userData.enabled_abilities ??= [];
const isEnabled = eAblities.includes(data.id);
div.innerHTML += `
<button onclick='activateSkill(this, ${JSON.stringify(data)})' style="${bttnStyle}">${isEnabled ? "Deaktivieren": "Aktivieren"}</button>
`;
} else {
const isParentEnabled = parent.id == "root" || userData.abilities.includes(parent.id);
const allowBuy = aSkillPoints > 0 && isParentEnabled;
div.innerHTML += `
<button onclick='_buySkill(${JSON.stringify(data)})' style="${allowBuy ? bttnStyle: bttnStyleDisabled}" ${allowBuy ? "": "disabled"}>Kaufen</button>
`;
}
elm.appendChild(div);
showOverlay("skill_tree_details_overlay");
}
async function activateSkill(elm, data) {
const elms = document.getElementsByClassName("skill_" + data.id);
const eAblities = userData.enabled_abilities ??= [];
const isEnabled = eAblities.includes(data.id);
if (isEnabled) {
//disabled
userData.enabled_abilities = eAblities.filter((val) => val != data.id);
for (var elm of elms) {
elm.setAttribute("fill", "rgb(187, 243, 183)");
}
} else {
//enabled
const coll = data.collision ??= [];
userData.enabled_abilities = eAblities.filter((val) => !coll.includes(val));
userData.enabled_abilities.push(data.id);
for (var elm of elms) {
elm.setAttribute("fill", "lightgreen");
}
for (var i of coll) {
if (!(userData["abilities"] ??= []).includes(i)) continue;
exeSkill(i, false);
for (var elm of document.getElementsByClassName("skill_" + i)) {
elm.setAttribute("fill", "rgb(187, 243, 183)");
}
}
}
elm.innerText = !isEnabled ? "Deaktivieren" : "Aktivieren";
getOverlay("skill_tree_details_overlay").innerHTML = "";
await updateUserData(new CouchDB(), userData);
hideOverlay("skill_tree_details_overlay");
if (!isEnabled) {
if (typeof(data.call) == "string") {
try { eval(data.call); } catch (err) { console.error(err); }
}
}
exeSkill(data.id, !isEnabled);
if (isEnabled) {
if (typeof(data.call_unset) == "string") {
try { eval(data.call_unset); } catch (err) { console.error(err); }
}
}
updateEverything();
}
async function _buySkill(data) {
const elms = document.getElementsByClassName("skill_" + data.id);
if (elms.length == 0) return;
for (var elm of elms) {
elm.setAttribute("fill", "rgb(187, 243, 183)");
}
aSkillPoints--;
const aSkillPoints_elms = document.getElementsByClassName("aSkillPoints");
for (var i of aSkillPoints_elms) {
i.innerText = aSkillPoints;
}
userData.abilities.push(data.id);
playXPSound();
getOverlay("skill_tree_details_overlay").innerHTML = "";
await updateUserData(new CouchDB(), userData);
hideOverlay("skill_tree_details_overlay");
}
function generateSkillTree(skillTree, abilities) {
const NS = "http://www.w3.org/2000/svg";
const nWidth = 120;
const nHeight = 40;
const lvlGap = 100;
const borderRadius = getComputedStyle(document.documentElement).getPropertyValue('--border-radius').trim();
const siblingGap = 40;
/* -------- calc layout -------- */
function measure_tree(data) {
data.children ??= [];
if (data.children.length === 0) {
data._width = nWidth;
} else {
data._width =
data.children.reduce((sum, c) => sum + measure_tree(c), 0) +
siblingGap * (data.children.length - 1);
}
return data._width;
}
measure_tree(skillTree);
function calc_tree(data, x, y) {
data._x = x;
data._y = y;
data.enabled = data.id == "root" || abilities.includes(data.id);
let childX = x - data._width / 2;
data.children.forEach(child => {
const cx = childX + child._width / 2;
const cy = y + lvlGap;
calc_tree(child, cx, cy);
childX += child._width + siblingGap;
});
}
calc_tree(skillTree, 0, 0);
/* -------- bounding-stuff -------- */
let minX = Infinity, maxX = -Infinity, maxY = -Infinity;
function bounds(data) {
minX = Math.min(minX, data._x - nWidth / 2);
maxX = Math.max(maxX, data._x + nWidth / 2);
maxY = Math.max(maxY, data._y + nHeight);
data.children.forEach(bounds);
}
bounds(skillTree);
const padding = 20;
const width = maxX - minX + padding * 2;
const height = maxY + padding * 2;
/* -------- other -------- */
const svg = document.createElementNS(NS, "svg");
svg.setAttribute("width", width);
svg.setAttribute("height", height);
svg.setAttribute(
"viewBox",
`${minX - padding} ${-padding} ${width} ${height}`
);
function drawLine(parent, data) {
const line = document.createElementNS(NS, "line");
line.setAttribute("x1", parent._x);
line.setAttribute("y1", parent._y + nHeight);
line.setAttribute("x2", data._x);
line.setAttribute("y2", data._y);
line.setAttribute("stroke", "#555");
svg.appendChild(line);
}
var levelCount = 0;
function drawNode(parent, data) {
data.children.forEach(child => {
drawLine(data, child);
drawNode(data, child);
});
const elmA = document.createElementNS(NS, "rect");
elmA.setAttribute("x", data._x - nWidth / 2);
elmA.setAttribute("y", data._y);
elmA.setAttribute("width", nWidth);
elmA.setAttribute("height", nHeight);
elmA.setAttribute("rx", borderRadius);
elmA.classList.add("skill_" + data.id);
elmA.setAttribute(
"fill", data.id == "root" ? "lightblue"
: (data.enabled ? (
userData.enabled_abilities.includes(data.id) ? "lightgreen": "rgb(187, 243, 183)"
): "lightgray")
);
elmA.setAttribute("stroke", "#333");
const elmB = document.createElementNS(NS, "text");
elmB.setAttribute("x", data._x);
elmB.setAttribute("y", data._y + nHeight / 2 + 5);
elmB.setAttribute("text-anchor", "middle");
elmB.setAttribute("font-size", "14");
elmB.textContent = data.text;
if (data.id != "root") {
if (data.enabled) levelCount++;
const js = `_getRect(${JSON.stringify(parent)}, ${JSON.stringify(data)})`;
elmA.setAttribute("onclick", js);
elmB.setAttribute("onclick", js);
}
svg.appendChild(elmA);
svg.appendChild(elmB);
}
drawNode(null, skillTree);
return [svg, levelCount];
}
async function playLevelSound() {
await playSound("../audio/levelup2.mp3");
}
async function playXPSound() {
await playSound("../audio/levelup1.mp3");
}